diff options
Diffstat (limited to 'driver')
285 files changed, 0 insertions, 73910 deletions
diff --git a/driver/accel_bma2x2.c b/driver/accel_bma2x2.c deleted file mode 100644 index 6d2d596bea..0000000000 --- a/driver/accel_bma2x2.c +++ /dev/null @@ -1,335 +0,0 @@ -/* 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. - */ - -/* - * Bosch Accelerometer driver for Chrome EC - * - * Supported: BMA255 - */ - -#include "accelgyro.h" -#include "common.h" -#include "console.h" -#include "accel_bma2x2.h" -#include "i2c.h" -#include "math_util.h" -#include "spi.h" -#include "task.h" -#include "util.h" - -#define CPUTS(outstr) cputs(CC_ACCEL, outstr) -#define CPRINTF(format, args...) cprintf(CC_ACCEL, format, ## args) - -/* Number of times to attempt to enable sensor before giving up. */ -#define SENSOR_ENABLE_ATTEMPTS 5 - -/** - * Read register from accelerometer. - */ -static inline int raw_read8(const int port, const uint16_t i2c_addr_flags, - const int reg, int *data_ptr) -{ - return i2c_read8(port, i2c_addr_flags, reg, data_ptr); -} - -/** - * Write register from accelerometer. - */ -static inline int raw_write8(const int port, const uint16_t i2c_addr_flags, - const int reg, int data) -{ - return i2c_write8(port, i2c_addr_flags, reg, data); -} - -static int set_range(struct motion_sensor_t *s, int range, int rnd) -{ - int ret, range_val, reg_val, range_reg_val; - - /* Range has to be between 2G-16G */ - if (range < 2) - range = 2; - else if (range > 16) - range = 16; - - range_val = BMA2x2_RANGE_TO_REG(range); - if ((BMA2x2_REG_TO_RANGE(range_val) < range) && rnd) - range_val = BMA2x2_RANGE_TO_REG(range * 2); - - mutex_lock(s->mutex); - - /* Determine the new value of control reg and attempt to write it. */ - ret = raw_read8(s->port, s->i2c_spi_addr_flags, - BMA2x2_RANGE_SELECT_ADDR, &range_reg_val); - if (ret != EC_SUCCESS) { - mutex_unlock(s->mutex); - return ret; - } - reg_val = (range_reg_val & ~BMA2x2_RANGE_SELECT_MSK) | range_val; - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - BMA2x2_RANGE_SELECT_ADDR, reg_val); - - /* If successfully written, then save the range. */ - if (ret == EC_SUCCESS) - s->current_range = BMA2x2_REG_TO_RANGE(range_val); - - mutex_unlock(s->mutex); - - return ret; -} - -static int get_resolution(const struct motion_sensor_t *s) -{ - return BMA2x2_RESOLUTION; -} - -static int set_data_rate(const struct motion_sensor_t *s, int rate, int rnd) -{ - int ret, odr_val, odr_reg_val, reg_val; - struct accelgyro_saved_data_t *data = s->drv_data; - - /* Rate has to be between 7.8125Hz - 1000Hz */ - if (rate < 7813) { - rate = 7812; - odr_val = BMA2x2_BW_7_81HZ; - } else if (rate > 1000000) { - rate = 1000000; - odr_val = BMA2x2_BW_1000HZ; - } else { - odr_val = BMA2x2_BW_TO_REG(rate); - if ((BMA2x2_REG_TO_BW(odr_val) < rate) && rnd) - odr_val = BMA2x2_BW_TO_REG(rate * 2); - } - - mutex_lock(s->mutex); - - /* Determine the new value of control reg and attempt to write it. */ - ret = raw_read8(s->port, s->i2c_spi_addr_flags, - BMA2x2_BW_SELECT_ADDR, &odr_reg_val); - if (ret != EC_SUCCESS) { - mutex_unlock(s->mutex); - return ret; - } - reg_val = (odr_reg_val & ~BMA2x2_BW_MSK) | odr_val; - /* Set output data rate. */ - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - BMA2x2_BW_SELECT_ADDR, reg_val); - - /* If successfully written, then save the new data rate. */ - if (ret == EC_SUCCESS) - data->odr = BMA2x2_REG_TO_BW(odr_val); - - mutex_unlock(s->mutex); - return ret; -} - -static int get_data_rate(const struct motion_sensor_t *s) -{ - struct accelgyro_saved_data_t *data = s->drv_data; - - return data->odr; -} - -static int set_offset(const struct motion_sensor_t *s, const int16_t *offset, - int16_t temp) -{ - int i, ret; - intv3_t v = { offset[X], offset[Y], offset[Z] }; - - rotate_inv(v, *s->rot_standard_ref, v); - - /* temperature is ignored */ - /* Offset from host is in 1/1024g, 1/128g internally. */ - for (i = X; i <= Z; i++) { - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - BMA2x2_OFFSET_X_AXIS_ADDR + i, v[i] / 8); - if (ret) - return ret; - } - return EC_SUCCESS; -} - -static int get_offset(const struct motion_sensor_t *s, int16_t *offset, - int16_t *temp) -{ - int i, val, ret; - intv3_t v; - - for (i = X; i <= Z; i++) { - ret = raw_read8(s->port, s->i2c_spi_addr_flags, - BMA2x2_OFFSET_X_AXIS_ADDR + i, &val); - if (ret) - return ret; - v[i] = (int8_t)val * 8; - } - rotate(v, *s->rot_standard_ref, v); - offset[X] = v[X]; - offset[Y] = v[Y]; - offset[Z] = v[Z]; - - *temp = EC_MOTION_SENSE_INVALID_CALIB_TEMP; - return EC_SUCCESS; -} - -static int read(const struct motion_sensor_t *s, intv3_t v) -{ - uint8_t acc[6]; - int ret, i; - - /* Read 6 bytes starting at X_AXIS_LSB. */ - mutex_lock(s->mutex); - ret = i2c_read_block(s->port, s->i2c_spi_addr_flags, - BMA2x2_X_AXIS_LSB_ADDR, acc, 6); - mutex_unlock(s->mutex); - - if (ret != EC_SUCCESS) - return ret; - - /* - * Convert acceleration to a signed 16-bit number. Note, based on - * the order of the registers: - * - * acc[0] = X_AXIS_LSB -> bit 7~4 for value, bit 0 for new data bit - * acc[1] = X_AXIS_MSB - * acc[2] = Y_AXIS_LSB -> bit 7~4 for value, bit 0 for new data bit - * acc[3] = Y_AXIS_MSB - * acc[4] = Z_AXIS_LSB -> bit 7~4 for value, bit 0 for new data bit - * acc[5] = Z_AXIS_MSB - */ - for (i = X; i <= Z; i++) - v[i] = (((int8_t)acc[i * 2 + 1]) << 8) | (acc[i * 2] & 0xf0); - rotate(v, *s->rot_standard_ref, v); - - return EC_SUCCESS; -} - -static int perform_calib(struct motion_sensor_t *s, int enable) -{ - int ret, val, status, rate, range, i; - timestamp_t deadline; - - if (!enable) - return EC_SUCCESS; - - ret = raw_read8(s->port, s->i2c_spi_addr_flags, - BMA2x2_OFFSET_CTRL_ADDR, &val); - if (ret) - return ret; - if (!(val & BMA2x2_OFFSET_CAL_READY)) - return EC_ERROR_ACCESS_DENIED; - - rate = get_data_rate(s); - range = s->current_range; - /* - * Temporary set frequency to 100Hz to get enough data in a short - * period of time. - */ - set_data_rate(s, 100000, 0); - set_range(s, 2, 0); - - /* We assume the device is laying flat for calibration */ - if (s->rot_standard_ref == NULL || - (*s->rot_standard_ref)[2][2] > INT_TO_FP(0)) - val = BMA2x2_OFC_TARGET_PLUS_1G; - else - val = BMA2x2_OFC_TARGET_MINUS_1G; - val = ((BMA2x2_OFC_TARGET_0G << BMA2x2_OFC_TARGET_AXIS(X)) | - (BMA2x2_OFC_TARGET_0G << BMA2x2_OFC_TARGET_AXIS(Y)) | - (val << BMA2x2_OFC_TARGET_AXIS(Z))); - raw_write8(s->port, s->i2c_spi_addr_flags, - BMA2x2_OFC_SETTING_ADDR, val); - - for (i = X; i <= Z; i++) { - val = (i + 1) << BMA2x2_OFFSET_TRIGGER_OFF; - raw_write8(s->port, s->i2c_spi_addr_flags, - BMA2x2_OFFSET_CTRL_ADDR, val); - /* - * The sensor needs 16 samples. At 100Hz/10ms, it needs 160ms to - * complete. Set 400ms to have some margin. - */ - deadline.val = get_time().val + 400 * MSEC; - do { - if (timestamp_expired(deadline, NULL)) { - ret = EC_RES_TIMEOUT; - goto end_perform_calib; - } - msleep(50); - ret = raw_read8(s->port, s->i2c_spi_addr_flags, - BMA2x2_OFFSET_CTRL_ADDR, &status); - if (ret != EC_SUCCESS) - goto end_perform_calib; - } while ((status & BMA2x2_OFFSET_CAL_READY) == 0); - } - -end_perform_calib: - set_range(s, range, 0); - set_data_rate(s, rate, 0); - return ret; -} - -static int init(struct motion_sensor_t *s) -{ - int ret = 0, tries = 0, val, reg, reset_field; - - /* This driver requires a mutex */ - ASSERT(s->mutex); - - ret = raw_read8(s->port, s->i2c_spi_addr_flags, - BMA2x2_CHIP_ID_ADDR, &val); - if (ret) - return EC_ERROR_UNKNOWN; - - if (val != BMA255_CHIP_ID_MAJOR) - return EC_ERROR_ACCESS_DENIED; - - /* Reset the chip to be in a good state */ - reg = BMA2x2_RST_ADDR; - reset_field = BMA2x2_CMD_SOFT_RESET; - - mutex_lock(s->mutex); - - ret = raw_read8(s->port, s->i2c_spi_addr_flags, reg, &val); - if (ret != EC_SUCCESS) { - mutex_unlock(s->mutex); - return ret; - } - val |= reset_field; - ret = raw_write8(s->port, s->i2c_spi_addr_flags, reg, val); - if (ret != EC_SUCCESS) { - mutex_unlock(s->mutex); - return ret; - } - - /* The SRST will be cleared when reset is complete. */ - do { - ret = raw_read8(s->port, s->i2c_spi_addr_flags, reg, &val); - - /* Reset complete. */ - if ((ret == EC_SUCCESS) && !(val & reset_field)) - break; - - /* Check for tires. */ - if (tries++ > SENSOR_ENABLE_ATTEMPTS) { - ret = EC_ERROR_TIMEOUT; - mutex_unlock(s->mutex); - return ret; - } - msleep(1); - } while (1); - mutex_unlock(s->mutex); - - return sensor_init_done(s); -} - -const struct accelgyro_drv bma2x2_accel_drv = { - .init = init, - .read = read, - .set_range = set_range, - .get_resolution = get_resolution, - .set_data_rate = set_data_rate, - .get_data_rate = get_data_rate, - .set_offset = set_offset, - .get_offset = get_offset, - .perform_calib = perform_calib, -}; diff --git a/driver/accel_bma422.h b/driver/accel_bma422.h deleted file mode 100644 index 0ab580235c..0000000000 --- a/driver/accel_bma422.h +++ /dev/null @@ -1,16 +0,0 @@ -/* Copyright 2021 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. - */ - -/* BMA422 gsensor module for Chrome EC */ - -#ifndef __CROS_EC_ACCEL_BMA422_H -#define __CROS_EC_ACCEL_BMA422_H - -#include "accel_bma4xx.h" - -/* Chip ID of BMA422 */ -#define BMA422_CHIP_ID 0x12 - -#endif /* __CROS_EC_ACCEL_BMA422_H */ diff --git a/driver/accel_bma4xx.c b/driver/accel_bma4xx.c deleted file mode 100644 index e9502c20b4..0000000000 --- a/driver/accel_bma4xx.c +++ /dev/null @@ -1,434 +0,0 @@ -/* Copyright 2021 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. - */ - -/* - * Bosch Accelerometer driver for Chrome EC - * - * Supported: BMA422 - */ - -#include "accelgyro.h" -#include "accel_bma422.h" -#include "common.h" -#include "console.h" -#include "i2c.h" -#include "math_util.h" -#include "spi.h" -#include "task.h" -#include "util.h" - -#define CPUTS(outstr) cputs(CC_ACCEL, outstr) -#define CPRINTF(format, args...) cprintf(CC_ACCEL, format, ## args) - -/** - * Read 8bit register from accelerometer. - */ -static inline int bma4_read8(const struct motion_sensor_t *s, const int reg, - int *data_ptr) -{ - return i2c_read8(s->port, s->i2c_spi_addr_flags, reg, data_ptr); -} - -/** - * Write 8bit register from accelerometer. - */ -static inline int bma4_write8(const struct motion_sensor_t *s, const int reg, - int data) -{ - int ret; - - ret = i2c_write8(s->port, s->i2c_spi_addr_flags, reg, data); - - /* - * From Bosch: BMA needs a delay of 450us after each write if it - * is in suspend mode, otherwise the operation may be ignored by - * the sensor. Given we are only doing write during init, add - * the delay unconditionally. - */ - usleep(450); - - return ret; -} - -/* - * Set specific bit set to certain value of a 8-bit reg. - */ -static inline int bma4_set_reg8(const struct motion_sensor_t *s, int reg, - uint8_t bits, int mask) -{ - int val; - - RETURN_ERROR(bma4_read8(s, reg, &val)); - - val = (val & ~mask) | bits; - - return bma4_write8(s, reg, val); -} - -static int write_accel_offset(const struct motion_sensor_t *s, intv3_t v) -{ - int i, val; - - rotate_inv(v, *s->rot_standard_ref, v); - - for (i = X; i <= Z; i++) { - val = round_divide((int64_t)v[i] * BMA4_OFFSET_ACC_DIV_MG, - BMA4_OFFSET_ACC_MULTI_MG); - if (val > 127) - val = 127; - if (val < -128) - val = -128; - if (val < 0) - val += 256; - - RETURN_ERROR(bma4_write8(s, BMA4_OFFSET_0_ADDR + i, val)); - } - - return EC_SUCCESS; -} - -static int set_foc_config(struct motion_sensor_t *s) -{ - /* Disabling offset compensation */ - RETURN_ERROR(bma4_set_reg8(s, BMA4_NV_CONFIG_ADDR, - (BMA4_DISABLE << BMA4_NV_ACCEL_OFFSET_POS), - BMA4_NV_ACCEL_OFFSET_MSK)); - - /* Set accelerometer configurations to 50Hz,CIC, continuous mode */ - RETURN_ERROR(bma4_write8(s, BMA4_ACCEL_CONFIG_ADDR, - BMA4_FOC_ACC_CONF_VAL)); - - - /* Set accelerometer to normal mode by enabling it */ - RETURN_ERROR(bma4_set_reg8(s, BMA4_POWER_CTRL_ADDR, - (BMA4_ENABLE << BMA4_ACCEL_ENABLE_POS), - BMA4_ACCEL_ENABLE_MSK)); - - /* Disable advance power save mode */ - RETURN_ERROR(bma4_set_reg8(s, BMA4_POWER_CONF_ADDR, - (BMA4_DISABLE - << BMA4_ADVANCE_POWER_SAVE_POS), - BMA4_ADVANCE_POWER_SAVE_MSK)); - - return EC_SUCCESS; -} - -static int wait_and_read_data(struct motion_sensor_t *s, intv3_t v) -{ - int i; - - /* Retry 5 times */ - uint8_t reg_data[6] = {0}, try_cnt = 5; - - /* Check if data is ready */ - while (try_cnt && (!(reg_data[0] & BMA4_STAT_DATA_RDY_ACCEL_MSK))) { - /* 20ms delay for 50Hz ODR */ - msleep(20); - - /* Read the status register */ - RETURN_ERROR(i2c_read_block(s->port, s->i2c_spi_addr_flags, - BMA4_STATUS_ADDR, reg_data, 1)); - - try_cnt--; - } - - if (!(reg_data[0] & 0x80)) - return EC_ERROR_TIMEOUT; - - /* Read the sensor data */ - RETURN_ERROR(i2c_read_block(s->port, s->i2c_spi_addr_flags, - BMA4_DATA_8_ADDR, reg_data, 6)); - - for (i = X; i <= Z; i++) { - v[i] = (((int8_t)reg_data[i * 2 + 1]) << 8) - | (reg_data[i * 2] & 0xf0); - - /* Since the resolution is only 12 bits*/ - v[i] = (v[i] / 0x10); - } - - rotate(v, *s->rot_standard_ref, v); - - return EC_SUCCESS; -} - -static int8_t perform_accel_foc(struct motion_sensor_t *s, int *target, - int sens_range) -{ - intv3_t accel_data, offset; - - /* Structure to store accelerometer data temporarily */ - int32_t delta_value[3] = {0, 0, 0}; - - /* Variable to define count */ - uint8_t i, loop, sample_count = 0; - - for (loop = 0; loop < BMA4_FOC_SAMPLE_LIMIT; loop++) { - RETURN_ERROR(wait_and_read_data(s, accel_data)); - - sample_count++; - - /* Store the data in a temporary structure */ - delta_value[0] += accel_data[0] - target[X]; - delta_value[1] += accel_data[1] - target[Y]; - delta_value[2] += accel_data[2] - target[Z]; - } - - /* - * The data is in LSB so -> [(LSB)*1000*range/2^11*-1] - * (unit of offset:mg) - */ - for (i = X; i <= Z; ++i) { - offset[i] = ((((delta_value[i] * 1000 * sens_range) - / sample_count) / 2048) * -1); - } - - RETURN_ERROR(write_accel_offset(s, offset)); - - /* Enable the offsets and backup to NVM */ - RETURN_ERROR(bma4_set_reg8(s, BMA4_NV_CONFIG_ADDR, - (BMA4_ENABLE << BMA4_NV_ACCEL_OFFSET_POS), - BMA4_NV_ACCEL_OFFSET_MSK)); - - return EC_SUCCESS; -} - -static int perform_calib(struct motion_sensor_t *s, int enable) -{ - uint8_t config[2]; - int pwr_ctrl, pwr_conf; - intv3_t target = {0, 0, 0}; - int sens_range = s->current_range; - - if (!enable) - return EC_SUCCESS; - - /* Read accelerometer configurations */ - RETURN_ERROR(i2c_read_block(s->port, s->i2c_spi_addr_flags, - BMA4_ACCEL_CONFIG_ADDR, config, 2)); - - /* Get accelerometer enable status to be saved */ - RETURN_ERROR(bma4_read8(s, BMA4_POWER_CTRL_ADDR, &pwr_ctrl)); - - /* Get advance power save mode to be saved */ - RETURN_ERROR(bma4_read8(s, BMA4_POWER_CONF_ADDR, &pwr_conf)); - - /* Perform calibration */ - RETURN_ERROR(set_foc_config(s)); - - /* We calibrate considering Z axis is laid flat on the surface */ - target[Z] = BMA4_ACC_DATA_PLUS_1G(sens_range); - - RETURN_ERROR(perform_accel_foc(s, target, sens_range)); - - /* Set the saved sensor configuration */ - RETURN_ERROR(i2c_write_block(s->port, s->i2c_spi_addr_flags, - BMA4_ACCEL_CONFIG_ADDR, config, 2)); - - RETURN_ERROR(bma4_write8(s, BMA4_POWER_CTRL_ADDR, pwr_ctrl)); - - RETURN_ERROR(bma4_write8(s, BMA4_POWER_CONF_ADDR, pwr_conf)); - - return EC_SUCCESS; -} - -static int set_range(struct motion_sensor_t *s, int range, int round) -{ - int ret, range_reg_val; - - range_reg_val = BMA4_RANGE_TO_REG(range); - - /* - * If rounding flag is set then set the range_val to nearest - * valid value. - */ - if ((BMA4_REG_TO_RANGE(range_reg_val) < range) && round) - range_reg_val = BMA4_RANGE_TO_REG(range * 2); - - mutex_lock(s->mutex); - - /* Determine the new value of control reg and attempt to write it. */ - ret = bma4_set_reg8(s, BMA4_ACCEL_RANGE_ADDR, - range_reg_val << BMA4_ACCEL_RANGE_POS, - BMA4_ACCEL_RANGE_MSK); - - /* If successfully written, then save the range. */ - if (ret == EC_SUCCESS) - s->current_range = BMA4_REG_TO_RANGE(range_reg_val); - - mutex_unlock(s->mutex); - - return ret; -} - -static int get_resolution(const struct motion_sensor_t *s) -{ - return BMA4_12_BIT_RESOLUTION; -} - -static int set_data_rate(const struct motion_sensor_t *s, int rate, int round) -{ - int ret, odr_reg_val; - struct accelgyro_saved_data_t *data = s->drv_data; - - odr_reg_val = BMA4_ODR_TO_REG(rate); - - if ((BMA4_REG_TO_ODR(odr_reg_val) < rate) && round) - odr_reg_val = BMA4_ODR_TO_REG(rate * 2); - - mutex_lock(s->mutex); - - /* Determine the new value of control reg and attempt to write it. */ - ret = bma4_set_reg8(s, BMA4_ACCEL_CONFIG_ADDR, - odr_reg_val << BMA4_ACCEL_ODR_POS, - BMA4_ACCEL_ODR_MSK); - - /* If successfully written, then save the new data rate. */ - if (ret == EC_SUCCESS) - data->odr = BMA4_REG_TO_ODR(odr_reg_val); - - mutex_unlock(s->mutex); - - return ret; -} - -static int get_data_rate(const struct motion_sensor_t *s) -{ - struct accelgyro_saved_data_t *data = s->drv_data; - - return data->odr; -} - -static int set_offset(const struct motion_sensor_t *s, const int16_t *offset, - int16_t temp) -{ - int ret; - intv3_t v = { offset[X], offset[Y], offset[Z] }; - - mutex_lock(s->mutex); - - ret = write_accel_offset(s, v); - - if (ret == EC_SUCCESS) { - /* Enable the offsets and backup to NVM */ - ret = bma4_set_reg8(s, BMA4_NV_CONFIG_ADDR, - (BMA4_ENABLE << BMA4_NV_ACCEL_OFFSET_POS), - BMA4_NV_ACCEL_OFFSET_MSK); - } - - mutex_unlock(s->mutex); - - return ret; -} - -static int get_offset(const struct motion_sensor_t *s, int16_t *offset, - int16_t *temp) -{ - int i, val, ret; - intv3_t v; - - mutex_lock(s->mutex); - - for (i = X; i <= Z; i++) { - ret = bma4_read8(s, BMA4_OFFSET_0_ADDR + i, &val); - if (ret) { - mutex_unlock(s->mutex); - return ret; - } - - if (val > 0x7f) - val -= -256; - - v[i] = round_divide((int64_t)val * BMA4_OFFSET_ACC_MULTI_MG, - BMA4_OFFSET_ACC_DIV_MG); - } - - mutex_unlock(s->mutex); - - /* Offset is in milli-g */ - rotate(v, *s->rot_standard_ref, v); - offset[X] = v[X]; - offset[Y] = v[Y]; - offset[Z] = v[Z]; - - *temp = (int16_t)EC_MOTION_SENSE_INVALID_CALIB_TEMP; - - return EC_SUCCESS; -} - -static int read(const struct motion_sensor_t *s, intv3_t v) -{ - uint8_t acc[6]; - int ret, i; - - mutex_lock(s->mutex); - - /* Read 6 bytes starting at X_AXIS_LSB. */ - ret = i2c_read_block(s->port, s->i2c_spi_addr_flags, - BMA4_DATA_8_ADDR, acc, 6); - - mutex_unlock(s->mutex); - - if (ret) - return ret; - - /* - * Convert acceleration to a signed 16-bit number. Note, based on - * the order of the registers: - * - * acc[0] = X_AXIS_LSB -> bit 7~4 for value, bit 0 for new data bit - * acc[1] = X_AXIS_MSB - * acc[2] = Y_AXIS_LSB -> bit 7~4 for value, bit 0 for new data bit - * acc[3] = Y_AXIS_MSB - * acc[4] = Z_AXIS_LSB -> bit 7~4 for value, bit 0 for new data bit - * acc[5] = Z_AXIS_MSB - */ - for (i = X; i <= Z; i++) - v[i] = (((int8_t)acc[i * 2 + 1]) << 8) | (acc[i * 2] & 0xf0); - - rotate(v, *s->rot_standard_ref, v); - - return EC_SUCCESS; -} - -static int init(struct motion_sensor_t *s) -{ - int ret = 0, reg_val; - - /* This driver requires a mutex. Assert if mutex is not supplied. */ - ASSERT(s->mutex); - - /* Read accelerometer's CHID ID */ - RETURN_ERROR(bma4_read8(s, BMA4_CHIP_ID_ADDR, ®_val)); - - if (s->chip != MOTIONSENSE_CHIP_BMA422 || reg_val != BMA422_CHIP_ID) - return EC_ERROR_HW_INTERNAL; - - mutex_lock(s->mutex); - - /* Enable accelerometer */ - ret = bma4_set_reg8(s, BMA4_POWER_CTRL_ADDR, - BMA4_ENABLE << BMA4_ACCEL_ENABLE_POS, - BMA4_ACCEL_ENABLE_MSK); - - mutex_unlock(s->mutex); - - if (ret) - return ret; - - return sensor_init_done(s); -} - -const struct accelgyro_drv bma4_accel_drv = { - .init = init, - .read = read, - .set_range = set_range, - .get_resolution = get_resolution, - .set_data_rate = set_data_rate, - .get_data_rate = get_data_rate, - .set_offset = set_offset, - .get_offset = get_offset, - .perform_calib = perform_calib, -}; diff --git a/driver/accel_bma4xx.h b/driver/accel_bma4xx.h deleted file mode 100644 index 13c9da4a92..0000000000 --- a/driver/accel_bma4xx.h +++ /dev/null @@ -1,166 +0,0 @@ -/* Copyright 2021 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. - */ - -/* BMA4XX gsensor module for Chrome EC */ - -#ifndef __CROS_EC_ACCEL_BMA4XX_H -#define __CROS_EC_ACCEL_BMA4XX_H - -#define BMA4_I2C_ADDR_PRIMARY 0x18 -#define BMA4_I2C_ADDR_SECONDARY 0x19 -#define BMA4_I2C_BMM150_ADDR 0x10 - -/* Chip-specific registers */ -#define BMA4_CHIP_ID_ADDR 0x00 -#define BMA4_CHIP_ID_MIN 0x10 -#define BMA4_CHIP_ID_MAX 0x15 - -#define BMA4_ERROR_ADDR 0x02 -#define BMA4_FATAL_ERR_MSK 0x01 -#define BMA4_CMD_ERR_POS 1 -#define BMA4_CMD_ERR_MSK 0x02 -#define BMA4_ERR_CODE_POS 2 -#define BMA4_ERR_CODE_MSK 0x1C -#define BMA4_FIFO_ERR_POS 6 -#define BMA4_FIFO_ERR_MSK 0x40 -#define BMA4_AUX_ERR_POS 7 -#define BMA4_AUX_ERR_MSK 0x80 - -#define BMA4_STATUS_ADDR 0x03 -#define BMA4_STAT_DATA_RDY_ACCEL_POS 7 -#define BMA4_STAT_DATA_RDY_ACCEL_MSK 0x80 - -#define BMA4_DATA_0_ADDR 0x0A -#define BMA4_DATA_8_ADDR 0x12 - -#define BMA4_SENSORTIME_0_ADDR 0x18 -#define BMA4_INT_STAT_0_ADDR 0x1C -#define BMA4_INT_STAT_1_ADDR 0x1D -#define BMA4_STEP_CNT_OUT_0_ADDR 0x1E -#define BMA4_HIGH_G_OUT_ADDR 0x1F -#define BMA4_TEMPERATURE_ADDR 0x22 - -#define BMA4_FIFO_LENGTH_0_ADDR 0x24 -#define BMA4_FIFO_DATA_ADDR 0x26 -#define BMA4_ACTIVITY_OUT_ADDR 0x27 -#define BMA4_ORIENTATION_OUT_ADDR 0x28 - -#define BMA4_INTERNAL_STAT 0x2A -#define BMA4_ASIC_INITIALIZED 0x01 - -#define BMA4_ACCEL_CONFIG_ADDR 0x40 -#define BMA4_ACCEL_ODR_POS 0 -#define BMA4_ACCEL_ODR_MSK 0x0F -#define BMA4_ACCEL_BW_POS 4 -#define BMA4_ACCEL_BW_MSK 0x70 -#define BMA4_ACCEL_PERFMODE_POS 7 -#define BMA4_ACCEL_PERFMODE_MSK 0x80 -#define BMA4_OUTPUT_DATA_RATE_0_78HZ 0x01 -#define BMA4_OUTPUT_DATA_RATE_1_56HZ 0x02 -#define BMA4_OUTPUT_DATA_RATE_3_12HZ 0x03 -#define BMA4_OUTPUT_DATA_RATE_6_25HZ 0x04 -#define BMA4_OUTPUT_DATA_RATE_12_5HZ 0x05 -#define BMA4_OUTPUT_DATA_RATE_25HZ 0x06 -#define BMA4_OUTPUT_DATA_RATE_50HZ 0x07 -#define BMA4_OUTPUT_DATA_RATE_100HZ 0x08 -#define BMA4_OUTPUT_DATA_RATE_200HZ 0x09 -#define BMA4_OUTPUT_DATA_RATE_400HZ 0x0A -#define BMA4_OUTPUT_DATA_RATE_800HZ 0x0B -#define BMA4_OUTPUT_DATA_RATE_1600HZ 0x0C -#define BMA4_ACCEL_OSR4_AVG1 0 -#define BMA4_ACCEL_OSR2_AVG2 1 -#define BMA4_ACCEL_NORMAL_AVG4 2 -#define BMA4_ACCEL_CIC_AVG8 3 -#define BMA4_ACCEL_RES_AVG16 4 -#define BMA4_ACCEL_RES_AVG32 5 -#define BMA4_ACCEL_RES_AVG64 6 -#define BMA4_ACCEL_RES_AVG128 7 -#define BMA4_CIC_AVG_MODE 0 -#define BMA4_CONTINUOUS_MODE 1 - -#define BMA4_ACCEL_RANGE_ADDR 0x41 -#define BMA4_ACCEL_RANGE_POS 0 -#define BMA4_ACCEL_RANGE_MSK 0x03 -#define BMA4_ACCEL_RANGE_2G 0 -#define BMA4_ACCEL_RANGE_4G 1 -#define BMA4_ACCEL_RANGE_8G 2 -#define BMA4_ACCEL_RANGE_16G 3 - -#define BMA4_RESERVED_REG_5B_ADDR 0x5B -#define BMA4_RESERVED_REG_5C_ADDR 0x5C -#define BMA4_FEATURE_CONFIG_ADDR 0x5E -#define BMA4_INTERNAL_ERROR 0x5F -#define BMA4_IF_CONFIG_ADDR 0x6B -#define BMA4_FOC_ACC_CONF_VAL 0xB7 - -#define BMA4_NV_CONFIG_ADDR 0x70 -#define BMA4_NV_ACCEL_OFFSET_POS 3 -#define BMA4_NV_ACCEL_OFFSET_MSK 0x08 - -#define BMA4_OFFSET_0_ADDR 0x71 -#define BMA4_OFFSET_1_ADDR 0x72 -#define BMA4_OFFSET_2_ADDR 0x73 - -#define BMA4_POWER_CONF_ADDR 0x7C -#define BMA4_ADVANCE_POWER_SAVE_POS 0 -#define BMA4_ADVANCE_POWER_SAVE_MSK 0x01 - -#define BMA4_POWER_CTRL_ADDR 0x7D -#define BMA4_ACCEL_ENABLE_POS 2 -#define BMA4_ACCEL_ENABLE_MSK 0x04 -#define BMA4_ENABLE 0x01 -#define BMA4_DISABLE 0x00 - -#define BMA4_CMD_ADDR 0x7E -#define BMA4_NVM_PROG 0xA0 -#define BMA4_FIFO_FLUSH 0xB0 -#define BMA4_SOFT_RESET 0xB6 - -/* Other definitions */ -#define BMA4_X_AXIS 0 -#define BMA4_Y_AXIS 1 -#define BMA4_Z_AXIS 2 - -#define BMA4_12_BIT_RESOLUTION 12 -#define BMA4_14_BIT_RESOLUTION 14 -#define BMA4_16_BIT_RESOLUTION 16 - -/* - * The max positive value of accel data is 0x07FF, equal to range(g) - * So, in order to get +1g, divide the 0x07FF by range - */ -#define BMA4_ACC_DATA_PLUS_1G(range) (0x07FF / (range)) - -/* For offset registers 1LSB - 3.9mg */ -#define BMA4_OFFSET_ACC_MULTI_MG (3900 * 1000) -#define BMA4_OFFSET_ACC_DIV_MG 1000000 - -#define BMA4_FOC_SAMPLE_LIMIT 32 - -/* Min and Max sampling frequency in mHz */ -#define BMA4_ACCEL_MIN_FREQ 12500 -#define BMA4_ACCEL_MAX_FREQ MOTION_MAX_SENSOR_FREQUENCY(1600000, 6250) - -#define BMA4_RANGE_TO_REG(_range) \ - ((_range) < 8 ? BMA4_ACCEL_RANGE_2G + ((_range) / 4) : \ - BMA4_ACCEL_RANGE_8G + ((_range) / 16)) - -#define BMA4_REG_TO_RANGE(_reg) \ - ((_reg) < BMA4_ACCEL_RANGE_8G ? 2 + (_reg) * 2 : \ - 8 + ((_reg) - BMA4_ACCEL_RANGE_8G) * 8) - -#define BMA4_ODR_TO_REG(_odr) \ - ((_odr) < 125000 ? \ - BMA4_OUTPUT_DATA_RATE_0_78HZ + __fls(((_odr) * 10) / 7800) : \ - BMA4_OUTPUT_DATA_RATE_25HZ + __fls((_odr) / 25000)) - -#define BMA4_REG_TO_ODR(_reg) \ - ((_reg) < BMA4_OUTPUT_DATA_RATE_25HZ ? \ - (7800 << ((_reg) - BMA4_OUTPUT_DATA_RATE_0_78HZ)) / 10 : \ - 25000 << ((_reg) - BMA4_OUTPUT_DATA_RATE_25HZ)) - -extern const struct accelgyro_drv bma4_accel_drv; - -#endif /* __CROS_EC_ACCEL_BMA4XX_H */ diff --git a/driver/accel_kionix.c b/driver/accel_kionix.c deleted file mode 100644 index 69f0ca9073..0000000000 --- a/driver/accel_kionix.c +++ /dev/null @@ -1,693 +0,0 @@ -/* 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. - */ - -/* - * Kionix Accelerometer driver for Chrome EC - * - * Supported: KX022, KXCJ9 - */ - -#include "accelgyro.h" -#include "common.h" -#include "console.h" -#include "accel_kionix.h" -#include "accel_kx022.h" -#include "accel_kxcj9.h" -#include "i2c.h" -#include "math_util.h" -#include "motion_orientation.h" -#include "spi.h" -#include "task.h" -#include "util.h" - -#define CPUTS(outstr) cputs(CC_ACCEL, outstr) -#define CPRINTF(format, args...) cprintf(CC_ACCEL, format, ## args) - -/* Number of times to attempt to enable sensor before giving up. */ -#define SENSOR_ENABLE_ATTEMPTS 3 - -#if !defined(CONFIG_ACCEL_KXCJ9) && !defined(CONFIG_ACCEL_KX022) -#error "Must use either KXCJ9 or KX022" -#endif - -#if defined(CONFIG_ACCEL_KXCJ9) && !defined(CONFIG_ACCEL_KX022) -#define V(s_) 1 -#elif defined(CONFIG_ACCEL_KX022) && !defined(CONFIG_ACCEL_KXCJ9) -#define V(s_) 0 -#else -#define V(s_) ((s_)->chip == MOTIONSENSE_CHIP_KXCJ9) -#endif -/* Index for which table to use. */ -#if !defined(CONFIG_ACCEL_KXCJ9) || !defined(CONFIG_ACCEL_KX022) -#define T(s_) 0 -#else -#define T(s_) V(s_) -#endif /* !defined(CONFIG_ACCEL_KXCJ9) || !defined(CONFIG_ACCEL_KX022) */ - -STATIC_IF(CONFIG_KX022_ORIENTATION_SENSOR) int check_orientation_locked( - const struct motion_sensor_t *s); - -/* List of range values in +/-G's and their associated register values. */ -static const struct accel_param_pair ranges[][3] = { -#ifdef CONFIG_ACCEL_KX022 - { {2, KX022_GSEL_2G}, - {4, KX022_GSEL_4G}, - {8, KX022_GSEL_8G} }, -#endif /* defined(CONFIG_ACCEL_KX022) */ -#ifdef CONFIG_ACCEL_KXCJ9 - { {2, KXCJ9_GSEL_2G}, - {4, KXCJ9_GSEL_4G}, - {8, KXCJ9_GSEL_8G_14BIT} }, -#endif /* defined(CONFIG_ACCEL_KXCJ9) */ -}; - -/* List of resolution values in bits and their associated register values. */ -static const struct accel_param_pair resolutions[][2] = { -#ifdef CONFIG_ACCEL_KX022 - { {8, KX022_RES_8BIT}, - {16, KX022_RES_16BIT} }, -#endif /* defined(CONFIG_ACCEL_KX022) */ -#ifdef CONFIG_ACCEL_KXCJ9 - { {8, KXCJ9_RES_8BIT}, - {12, KXCJ9_RES_12BIT} }, -#endif /* defined(CONFIG_ACCEL_KXCJ9) */ -}; - -/* List of ODR values in mHz and their associated register values. */ -static const struct accel_param_pair datarates[][13] = { -#ifdef CONFIG_ACCEL_KX022 - /* One duplicate because table sizes must match. */ - { {781, KX022_OSA_0_781HZ}, - {781, KX022_OSA_0_781HZ}, - {1563, KX022_OSA_1_563HZ}, - {3125, KX022_OSA_3_125HZ}, - {6250, KX022_OSA_6_250HZ}, - {12500, KX022_OSA_12_50HZ}, - {25000, KX022_OSA_25_00HZ}, - {50000, KX022_OSA_50_00HZ}, - {100000, KX022_OSA_100_0HZ}, - {200000, KX022_OSA_200_0HZ}, - {400000, KX022_OSA_400_0HZ}, - {800000, KX022_OSA_800_0HZ}, - {1600000, KX022_OSA_1600HZ} }, -#endif /* defined(CONFIG_ACCEL_KX022) */ -#ifdef CONFIG_ACCEL_KXCJ9 - { {0, KXCJ9_OSA_0_000HZ}, - {781, KXCJ9_OSA_0_781HZ}, - {1563, KXCJ9_OSA_1_563HZ}, - {3125, KXCJ9_OSA_3_125HZ}, - {6250, KXCJ9_OSA_6_250HZ}, - {12500, KXCJ9_OSA_12_50HZ}, - {25000, KXCJ9_OSA_25_00HZ}, - {50000, KXCJ9_OSA_50_00HZ}, - {100000, KXCJ9_OSA_100_0HZ}, - {200000, KXCJ9_OSA_200_0HZ}, - {400000, KXCJ9_OSA_400_0HZ}, - {800000, KXCJ9_OSA_800_0HZ}, - {1600000, KXCJ9_OSA_1600_HZ} }, -#endif /* defined(CONFIG_ACCEL_KXCJ9) */ -}; - -/** - * Find index into a accel_param_pair that matches the given engineering value - * passed in. The round_up flag is used to specify whether to round up or down. - * Note, this function always returns a valid index. If the request is - * outside the range of values, it returns the closest valid index. - */ -static int find_param_index(const int eng_val, const int round_up, - const struct accel_param_pair *pairs, - const int size) -{ - int i; - - /* Linear search for index to match. */ - for (i = 0; i < size - 1; i++) { - if (eng_val <= pairs[i].val) - return i; - - if (eng_val < pairs[i+1].val) { - if (round_up) - return i + 1; - else - return i; - } - } - - return i; -} - -/** - * Read register from accelerometer. - */ -static int raw_read8(const int port, - const uint16_t i2c_spi_addr_flags, - const int reg, int *data_ptr) -{ - int rv = EC_ERROR_INVAL; - - if (ACCEL_ADDR_IS_SPI(i2c_spi_addr_flags)) { -#ifdef CONFIG_SPI_ACCEL_PORT - uint8_t val; - uint8_t cmd = 0x80 | reg; - - rv = spi_transaction( - &spi_devices[ACCEL_GET_SPI_ADDR(i2c_spi_addr_flags)], - &cmd, 1, &val, 1); - if (rv == EC_SUCCESS) - *data_ptr = val; - -#endif - } else { - rv = i2c_read8(port, i2c_spi_addr_flags, - reg, data_ptr); - } - return rv; -} - -/** - * Write register from accelerometer. - */ -static int raw_write8(const int port, - const uint16_t i2c_spi_addr_flags, - const int reg, int data) -{ - int rv = EC_ERROR_INVAL; - - if (ACCEL_ADDR_IS_SPI(i2c_spi_addr_flags)) { -#ifdef CONFIG_SPI_ACCEL_PORT - uint8_t cmd[2] = { reg, data }; - - rv = spi_transaction( - &spi_devices[ACCEL_GET_SPI_ADDR(i2c_spi_addr_flags)], - cmd, 2, NULL, 0); -#endif - } else { - rv = i2c_write8(port, i2c_spi_addr_flags, - reg, data); - } - return rv; -} - -static int raw_read_multi(const int port, - const uint16_t i2c_spi_addr_flags, - uint8_t reg, uint8_t *rxdata, int rxlen) -{ - int rv = EC_ERROR_INVAL; - - if (ACCEL_ADDR_IS_SPI(i2c_spi_addr_flags)) { -#ifdef CONFIG_SPI_ACCEL_PORT - reg |= 0x80; - rv = spi_transaction( - &spi_devices[ACCEL_GET_SPI_ADDR(i2c_spi_addr_flags)], - ®, 1, rxdata, rxlen); -#endif - } else { - rv = i2c_read_block(port, i2c_spi_addr_flags, - reg, rxdata, rxlen); - } - return rv; -} - -/** - * Disable sensor by taking it out of operating mode. When disabled, the - * acceleration data does not change. - * - * Note: This is intended to be called in a pair with enable_sensor(). - * - * @param s Pointer to motion sensor data - * @param reg_val Pointer to location to store control register after disabling - * - * @return EC_SUCCESS if successful, EC_ERROR_* otherwise - */ -static int disable_sensor(const struct motion_sensor_t *s, int *reg_val) -{ - int i, ret, reg, pc1_field; - - reg = KIONIX_CTRL1_REG(V(s)); - pc1_field = KIONIX_PC1_FIELD(V(s)); - - /* - * Read the current state of the control register - * so that we can restore it later. - */ - for (i = 0; i < SENSOR_ENABLE_ATTEMPTS; i++) { - ret = raw_read8(s->port, s->i2c_spi_addr_flags, - reg, reg_val); - if (ret != EC_SUCCESS) - continue; - - *reg_val &= ~pc1_field; - - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - reg, *reg_val); - if (ret == EC_SUCCESS) - return EC_SUCCESS; - } - return ret; -} - -/** - * Enable sensor by placing it in operating mode. - * - * Note: This is intended to be called in a pair with disable_sensor(). - * - * @param s Pointer to motion sensor data - * @param reg_val Value of the control register to write to sensor - * - * @return EC_SUCCESS if successful, EC_ERROR_* otherwise - */ -static int enable_sensor(const struct motion_sensor_t *s, int reg_val) -{ - int i, ret, reg, pc1_field; - - reg = KIONIX_CTRL1_REG(V(s)); - pc1_field = KIONIX_PC1_FIELD(V(s)); - - for (i = 0; i < SENSOR_ENABLE_ATTEMPTS; i++) { - ret = raw_read8(s->port, s->i2c_spi_addr_flags, - reg, ®_val); - if (ret != EC_SUCCESS) - continue; - - /* Enable tilt orientation mode if lid sensor */ - if (IS_ENABLED(CONFIG_KX022_ORIENTATION_SENSOR) && - (s->location == MOTIONSENSE_LOC_LID) && - (V(s) == 0)) - reg_val |= KX022_CNTL1_TPE; - - /* Enable accelerometer based on reg_val value. */ - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - reg, reg_val | pc1_field); - - /* On first success, we are done. */ - if (ret == EC_SUCCESS) - break; - } - return ret; -} - -/** - * Set a register value. - * - * @param s Pointer to motion sensor data - * @param reg Register to write to - * @param reg_val Value of the control register to write to sensor - * @param field Bitfield to modify. - * - * @return EC_SUCCESS if successful, EC_ERROR_* otherwise - */ -static int set_value(const struct motion_sensor_t *s, int reg, int val, - int field) -{ - int ret, reg_val_new, reg_val; - - /* Disable the sensor to allow for changing of critical parameters. */ - mutex_lock(s->mutex); - ret = disable_sensor(s, ®_val); - if (ret != EC_SUCCESS) { - mutex_unlock(s->mutex); - return ret; - } - - /* Determine new value of control reg and attempt to write it. */ - reg_val_new = (reg_val & ~field) | val; - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - reg, reg_val_new); - - /* If successfully written, then save the range. */ - if (ret == EC_SUCCESS) - /* Re-enable the sensor. */ - ret = enable_sensor(s, reg_val_new); - - mutex_unlock(s->mutex); - return ret; -} - -static int set_range(struct motion_sensor_t *s, int range, int rnd) -{ - int ret, index, reg, range_field, range_val; - - /* Find index for interface pair matching the specified range. */ - index = find_param_index(range, rnd, ranges[T(s)], - ARRAY_SIZE(ranges[T(s)])); - range_field = KIONIX_RANGE_FIELD(V(s)); - reg = KIONIX_CTRL1_REG(V(s)); - range_val = ranges[T(s)][index].reg; - - ret = set_value(s, reg, range_val, range_field); - if (ret == EC_SUCCESS) - s->current_range = ranges[T(s)][index].val; - return ret; -} - -static int set_resolution(const struct motion_sensor_t *s, int res, int rnd) -{ - int ret, index, reg, res_field, res_val; - struct kionix_accel_data *data = s->drv_data; - - /* Find index for interface pair matching the specified resolution. */ - index = find_param_index(res, rnd, resolutions[T(s)], - ARRAY_SIZE(resolutions[T(s)])); - res_val = resolutions[T(s)][index].reg; - res_field = KIONIX_RES_FIELD(V(s)); - reg = KIONIX_CTRL1_REG(V(s)); - - ret = set_value(s, reg, res_val, res_field); - if (ret == EC_SUCCESS) - data->sensor_resolution = resolutions[T(s)][index].val; - return ret; -} - -static int get_resolution(const struct motion_sensor_t *s) -{ - struct kionix_accel_data *data = s->drv_data; - - return data->sensor_resolution; -} - -static int set_data_rate(const struct motion_sensor_t *s, int rate, int rnd) -{ - int ret, index, reg, odr_field, odr_val; - struct kionix_accel_data *data = s->drv_data; - - /* Find index for interface pair matching the specified rate. */ - index = find_param_index(rate, rnd, datarates[T(s)], - ARRAY_SIZE(datarates[T(s)])); - odr_val = datarates[T(s)][index].reg; - reg = KIONIX_ODR_REG(V(s)); - odr_field = KIONIX_ODR_FIELD(V(s)); - - ret = set_value(s, reg, odr_val, odr_field); - if (ret == EC_SUCCESS) - data->base.odr = datarates[T(s)][index].val; - return ret; -} - -static int get_data_rate(const struct motion_sensor_t *s) -{ - struct kionix_accel_data *data = s->drv_data; - - return data->base.odr; -} - -static int set_offset(const struct motion_sensor_t *s, const int16_t *offset, - int16_t temp) -{ - /* temperature is ignored */ - struct kionix_accel_data *data = s->drv_data; - data->offset[X] = offset[X]; - data->offset[Y] = offset[Y]; - data->offset[Z] = offset[Z]; - return EC_SUCCESS; -} - -static int get_offset(const struct motion_sensor_t *s, int16_t *offset, - int16_t *temp) -{ - struct kionix_accel_data *data = s->drv_data; - offset[X] = data->offset[X]; - offset[Y] = data->offset[Y]; - offset[Z] = data->offset[Z]; - *temp = EC_MOTION_SENSE_INVALID_CALIB_TEMP; - return EC_SUCCESS; -} - -static __maybe_unused enum motionsensor_orientation kx022_convert_orientation( - const struct motion_sensor_t *s, - int orientation) -{ - enum motionsensor_orientation res = MOTIONSENSE_ORIENTATION_UNKNOWN; - - switch (orientation) { - case KX022_ORIENT_PORTRAIT: - res = MOTIONSENSE_ORIENTATION_PORTRAIT; - break; - case KX022_ORIENT_INVERT_PORTRAIT: - res = MOTIONSENSE_ORIENTATION_UPSIDE_DOWN_PORTRAIT; - break; - case KX022_ORIENT_LANDSCAPE: - res = MOTIONSENSE_ORIENTATION_LANDSCAPE; - break; - case KX022_ORIENT_INVERT_LANDSCAPE: - res = MOTIONSENSE_ORIENTATION_UPSIDE_DOWN_LANDSCAPE; - break; - default: - break; - } - res = motion_orientation_remap(s, res); - return res; -} - -#ifdef CONFIG_KX022_ORIENTATION_SENSOR -static int check_orientation_locked(const struct motion_sensor_t *s) -{ - struct kionix_accel_data *data = s->drv_data; - int orientation, raw_orientation; - int ret; - - ret = raw_read8(s->port, s->i2c_spi_addr_flags, - KX022_TSCP, &raw_orientation); - if (ret != EC_SUCCESS) - return ret; - - /* mask off up and down events, we don't care about those */ - raw_orientation &= KX022_ORIENT_MASK; - if (raw_orientation && (raw_orientation != data->raw_orientation)) { - data->raw_orientation = raw_orientation; - orientation = kx022_convert_orientation(s, raw_orientation); - *motion_orientation_ptr(s) = orientation; - } - return ret; -} - -bool motion_orientation_changed(const struct motion_sensor_t *s) -{ - return ((struct kionix_accel_data *)s->drv_data)->orientation != - ((struct kionix_accel_data *)s->drv_data)->last_orientation; -} - -enum motionsensor_orientation *motion_orientation_ptr( - const struct motion_sensor_t *s) -{ - return &((struct kionix_accel_data *)s->drv_data)->orientation; -} - -void motion_orientation_update(const struct motion_sensor_t *s) -{ - ((struct kionix_accel_data *)s->drv_data)->last_orientation = - ((struct kionix_accel_data *)s->drv_data)->orientation; -} - -#endif - -static int read(const struct motion_sensor_t *s, intv3_t v) -{ - uint8_t acc[6]; - uint8_t reg; - int ret, i, resolution; - struct kionix_accel_data *data = s->drv_data; - - /* Read 6 bytes starting at XOUT_L. */ - reg = KIONIX_XOUT_L(V(s)); - mutex_lock(s->mutex); - ret = raw_read_multi(s->port, s->i2c_spi_addr_flags, reg, acc, 6); - if (IS_ENABLED(CONFIG_KX022_ORIENTATION_SENSOR) && - (s->location == MOTIONSENSE_LOC_LID) && - (V(s) == 0) && - (ret == EC_SUCCESS)) - ret = check_orientation_locked(s); - mutex_unlock(s->mutex); - - if (ret != EC_SUCCESS) - return ret; - - /* - * Convert acceleration to a signed 16-bit number. Note, based on - * the order of the registers: - * - * acc[0] = XOUT_L - * acc[1] = XOUT_H - * acc[2] = YOUT_L - * acc[3] = YOUT_H - * acc[4] = ZOUT_L - * acc[5] = ZOUT_H - * - * Add calibration offset before returning the data. - */ - resolution = get_resolution(s); - for (i = X; i <= Z; i++) { - if (V(s)) { - v[i] = (((int8_t)acc[i * 2 + 1]) << 4) | - (acc[i * 2] >> 4); - v[i] <<= 16 - resolution; - } else { - if (resolution == 8) - acc[i * 2] = 0; - v[i] = (((int8_t)acc[i * 2 + 1]) << 8) | acc[i * 2]; - } - } - rotate(v, *s->rot_standard_ref, v); - - /* apply offset in the device coordinates */ - for (i = X; i <= Z; i++) - v[i] += (data->offset[i] << 5) / s->current_range; - - return EC_SUCCESS; -} - -static int init(struct motion_sensor_t *s) -{ - int ret, val, reg, reset_field; - uint8_t timeout; - - mutex_lock(s->mutex); - if (V(s)) { - /* The chip can take up to 10ms to boot */ - reg = KIONIX_WHO_AM_I(V(s)); - timeout = 0; - do { - msleep(1); - /* Read WHO_AM_I to be sure the device has booted */ - ret = raw_read8(s->port, s->i2c_spi_addr_flags, - reg, &val); - if (ret == EC_SUCCESS) - break; - - /* Check for timeout. */ - if (timeout++ > 20) { - ret = EC_ERROR_TIMEOUT; - break; - } - } while (1); - } else { - /* Write 0x00 to the internal register for KX022 */ - reg = KX022_INTERNAL; - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - reg, 0x0); - if (ret != EC_SUCCESS) { - /* - * For I2C communication, if ACK was not received - * from the first address, resend the command using - * the second address. - */ - if (!ACCEL_ADDR_IS_SPI(s->i2c_spi_addr_flags)) { - const uint16_t i2c_alt_addr_flags = - I2C_STRIP_FLAGS( - s->i2c_spi_addr_flags) - & ~2; - ret = raw_write8(s->port, - i2c_alt_addr_flags, - reg, 0x0); - } - } - } - - if (ret != EC_SUCCESS) - goto reset_failed; - - /* Issue a software reset. */ - reg = KIONIX_CTRL2_REG(V(s)); - reset_field = KIONIX_RESET_FIELD(V(s)); - - if (V(s)) { - /* Place the sensor in standby mode to make changes. */ - ret = disable_sensor(s, &val); - if (ret != EC_SUCCESS) - goto reset_failed; - ret = raw_read8(s->port, s->i2c_spi_addr_flags, reg, &val); - if (ret != EC_SUCCESS) - goto reset_failed; - - val |= reset_field; - } else { - /* Write 0 to CTRL2 for KX022 */ - ret = raw_write8(s->port, s->i2c_spi_addr_flags, reg, 0x0); - if (ret != EC_SUCCESS) - goto reset_failed; - - val = reset_field; - } - - ret = raw_write8(s->port, s->i2c_spi_addr_flags, reg, val); - if (ret != EC_SUCCESS) - goto reset_failed; - - if (V(s)) { - /* The SRST will be cleared when reset is complete. */ - timeout = 0; - do { - msleep(1); - - ret = raw_read8(s->port, s->i2c_spi_addr_flags, - reg, &val); - /* Reset complete. */ - if ((ret == EC_SUCCESS) && !(val & reset_field)) - break; - /* Check for timeout. */ - if (timeout++ > 20) { - ret = EC_ERROR_TIMEOUT; - goto reset_failed; - } - } while (1); - } else { - /* Wait 2 milliseconds for completion of the software reset. */ - msleep(2); - - reg = KX022_COTR; - ret = raw_read8(s->port, s->i2c_spi_addr_flags, reg, &val); - if (val != KX022_COTR_VAL_DEFAULT) { - CPRINTF("[%s: the software reset failed]\n", s->name); - ret = EC_ERROR_HW_INTERNAL; - goto reset_failed; - } - } - - reg = KIONIX_WHO_AM_I(V(s)); - ret = raw_read8(s->port, s->i2c_spi_addr_flags, reg, &val); - if (ret != EC_SUCCESS || val != KIONIX_WHO_AM_I_VAL(V(s))) { - ret = EC_ERROR_HW_INTERNAL; - goto reset_failed; - } - - mutex_unlock(s->mutex); - - /* Initialize with the desired parameters. */ - if (V(s)) - ret = set_resolution(s, 12, 1); - else - ret = set_resolution(s, 16, 1); - if (ret != EC_SUCCESS) - return ret; - - return sensor_init_done(s); - -reset_failed: - mutex_unlock(s->mutex); - return ret; -} - -const struct accelgyro_drv kionix_accel_drv = { - .init = init, - .read = read, - .set_range = set_range, - .set_resolution = set_resolution, - .get_resolution = get_resolution, - .set_data_rate = set_data_rate, - .get_data_rate = get_data_rate, - .set_offset = set_offset, - .get_offset = get_offset, -}; - -#ifdef CONFIG_CMD_I2C_STRESS_TEST_ACCEL -struct i2c_stress_test_dev kionix_i2c_stress_test_dev = { - .reg_info = { - .read_reg = KIONIX_WHO_AM_I(V(s)), - .read_val = KIONIX_WHO_AM_I_VAL(V(s)), - .write_reg = KIONIX_ODR_REG(V(s)), - }, - .i2c_read = &raw_read8, - .i2c_write = &raw_write8, -}; -#endif /* CONFIG_CMD_I2C_STRESS_TEST_ACCEL */ diff --git a/driver/accel_kionix.h b/driver/accel_kionix.h deleted file mode 100644 index 5ec83411e9..0000000000 --- a/driver/accel_kionix.h +++ /dev/null @@ -1,79 +0,0 @@ -/* 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. - */ - -/* Kionix Accelerometer driver for Chrome EC */ - -#ifndef __CROS_EC_ACCEL_KIONIX_H -#define __CROS_EC_ACCEL_KIONIX_H - -#include "common.h" -#include "accelgyro.h" -#include "driver/accel_kx022.h" -#include "driver/accel_kxcj9.h" - -/* - * Struct for pairing an engineering value with the register value for a - * parameter. - */ -struct accel_param_pair { - int val; /* Value in engineering units. */ - int reg; /* Corresponding register value. */ -}; - -struct kionix_accel_data { - struct accelgyro_saved_data_t base; - /* Current resolution of accelerometer. */ - int sensor_resolution; - int16_t offset[3]; -#ifdef CONFIG_KX022_ORIENTATION_SENSOR - int8_t raw_orientation; - enum motionsensor_orientation orientation; - enum motionsensor_orientation last_orientation; -#endif -}; - -extern const struct accelgyro_drv kionix_accel_drv; - -/* - * The addr field of motion_sensor support both SPI and I2C: - * - * +-------------------------------+---+ - * | 7 bit i2c address | 0 | - * +-------------------------------+---+ - * Or - * +-------------------------------+---+ - * | SPI device ID | 1 | - * +-------------------------------+---+ - */ -#define KIONIX_CTRL1_REG(v) (KX022_CNTL1 + \ - (v) * (KXCJ9_CTRL1 - KX022_CNTL1)) -#define KIONIX_CTRL2_REG(v) (KX022_CNTL2 + \ - (v) * (KXCJ9_CTRL2 - KX022_CNTL2)) -#define KIONIX_ODR_REG(v) (KX022_ODCNTL + \ - (v) * (KXCJ9_DATA_CTRL - KX022_ODCNTL)) -#define KIONIX_ODR_FIELD(v) (KX022_OSA_FIELD + \ - (v) * (KXCJ9_OSA_FIELD - KX022_OSA_FIELD)) -#define KIONIX_PC1_FIELD(v) (KX022_CNTL1_PC1 + \ - (v) * (KXCJ9_CTRL1_PC1 - KX022_CNTL1_PC1)) -#define KIONIX_RANGE_FIELD(v) (KX022_GSEL_FIELD + \ - (v) * (KXCJ9_GSEL_ALL - KX022_GSEL_FIELD)) -#define KIONIX_RES_FIELD(v) (KX022_RES_16BIT + \ - (v) * (KXCJ9_RES_12BIT - KX022_RES_16BIT)) -#define KIONIX_RESET_FIELD(v) (KX022_CNTL2_SRST + \ - (v) * (KXCJ9_CTRL2_SRST - KX022_CNTL2_SRST)) -#define KIONIX_XOUT_L(v) (KX022_XOUT_L + \ - (v) * (KXCJ9_XOUT_L - KX022_XOUT_L)) - -#define KIONIX_WHO_AM_I(v) (KX022_WHOAMI + \ - (v) * (KXCJ9_WHOAMI - KX022_WHOAMI)) - -#define KIONIX_WHO_AM_I_VAL(v) (KX022_WHO_AM_I_VAL + \ - (v) * (KXCJ9_WHO_AM_I_VAL - KX022_WHO_AM_I_VAL)) - -#ifdef CONFIG_CMD_I2C_STRESS_TEST_ACCEL -extern struct i2c_stress_test_dev kionix_i2c_stress_test_dev; -#endif - -#endif /* __CROS_EC_ACCEL_KIONIX_H */ diff --git a/driver/accel_kx022.h b/driver/accel_kx022.h deleted file mode 100644 index a806568c59..0000000000 --- a/driver/accel_kx022.h +++ /dev/null @@ -1,141 +0,0 @@ -/* 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. - */ - -/* KX022 gsensor module for Chrome EC */ - -#ifndef __CROS_EC_ACCEL_KX022_H -#define __CROS_EC_ACCEL_KX022_H - -/* - * 7-bit address is 001111Xb. Where 'X' is determined - * by the voltage on the ADDR pin. - */ -#define KX022_ADDR0_FLAGS 0x1e -#define KX022_ADDR1_FLAGS 0x1f -#define KX022_WHO_AM_I_VAL 0x14 - -/* Chip-specific registers */ -#define KX022_XHP_L 0x00 -#define KX022_XHP_H 0x01 -#define KX022_YHP_L 0x02 -#define KX022_YHP_H 0x03 -#define KX022_ZHP_L 0x04 -#define KX022_ZHP_H 0x05 -#define KX022_XOUT_L 0x06 -#define KX022_XOUT_H 0x07 -#define KX022_YOUT_L 0x08 -#define KX022_YOUT_H 0x09 -#define KX022_ZOUT_L 0x0a -#define KX022_ZOUT_H 0x0b -#define KX022_COTR 0x0c -#define KX022_COTR_VAL_COTC 0xAA -#define KX022_COTR_VAL_DEFAULT 0x55 -#define KX022_WHOAMI 0x0f -#define KX022_TSCP 0x10 -#define KX022_TSPP 0x11 -#define KX022_INS1 0x12 -#define KX022_INS2 0x13 -#define KX022_INS3 0x14 -#define KX022_STATUS_REG 0x15 -#define KX022_INT_REL 0x17 -#define KX022_CNTL1 0x18 -#define KX022_CNTL2 0x19 -#define KX022_CNTL3 0x1a -#define KX022_ODCNTL 0x1b -#define KX022_INC1 0x1c -#define KX022_INC2 0x1d -#define KX022_INC3 0x1e -#define KX022_INC4 0x1f -#define KX022_INC5 0x20 -#define KX022_INC6 0x21 -#define KX022_TILT_TIMER 0x22 -#define KX022_WUFC 0x23 -#define KX022_TDTRC 0x24 -#define KX022_TDTC 0x25 -#define KX022_TTH 0x26 -#define KX022_TTL 0x27 -#define KX022_FTD 0x28 -#define KX022_STD 0x29 -#define KX022_TLT 0x2a -#define KX022_TWS 0x2b -#define KX022_ATH 0x30 -#define KX022_TILT_ANGLE_LL 0x32 -#define KX022_TILT_ANGLE_HL 0x33 -#define KX022_HYST_SET 0x34 -#define KX022_LP_CNTL 0x35 -#define KX022_BUF_CNTL1 0x3a -#define KX022_BUF_CNTL2 0x3b -#define KX022_BUF_STATUS_1 0x3c -#define KX022_BUF_STATUS_2 0x3d -#define KX022_BUF_CLEAR 0x3e -#define KX022_BUF_READ 0x3f -#define KX022_SELF_TEST 0x60 -#define KX022_INTERNAL 0x7f - - -#define KX022_CNTL1_PC1 BIT(7) -#define KX022_CNTL1_WUFE BIT(1) -#define KX022_CNTL1_TPE BIT(0) - -/* TSCP orientations */ -#define KX022_ORIENT_PORTRAIT BIT(2) -#define KX022_ORIENT_INVERT_PORTRAIT BIT(3) -#define KX022_ORIENT_LANDSCAPE BIT(4) -#define KX022_ORIENT_INVERT_LANDSCAPE BIT(5) -#define KX022_ORIENT_MASK (KX022_ORIENT_PORTRAIT | \ - KX022_ORIENT_INVERT_PORTRAIT | \ - KX022_ORIENT_LANDSCAPE | \ - KX022_ORIENT_INVERT_LANDSCAPE) - -#define KX022_CNTL2_SRST BIT(7) - -#define KX022_CNTL3_OWUF_FIELD 7 - -#define KX022_INC1_IEA BIT(4) -#define KX022_INC1_IEN BIT(5) - -#define KX022_GSEL_2G (0 << 3) -#define KX022_GSEL_4G BIT(3) -#define KX022_GSEL_8G (2 << 3) -#define KX022_GSEL_FIELD (3 << 3) - -#define KX022_RES_8BIT (0 << 6) -#define KX022_RES_16BIT BIT(6) - -#define KX022_OSA_0_781HZ 8 -#define KX022_OSA_1_563HZ 9 -#define KX022_OSA_3_125HZ 0xa -#define KX022_OSA_6_250HZ 0xb -#define KX022_OSA_12_50HZ 0 -#define KX022_OSA_25_00HZ 1 -#define KX022_OSA_50_00HZ 2 -#define KX022_OSA_100_0HZ 3 -#define KX022_OSA_200_0HZ 4 -#define KX022_OSA_400_0HZ 5 -#define KX022_OSA_800_0HZ 6 -#define KX022_OSA_1600HZ 7 -#define KX022_OSA_FIELD 0xf - -#define KX022_OWUF_0_781HZ 0 -#define KX022_OWUF_1_563HZ 1 -#define KX022_OWUF_3_125HZ 2 -#define KX022_OWUF_6_250HZ 3 -#define KX022_OWUF_12_50HZ 4 -#define KX022_OWUF_25_00HZ 5 -#define KX022_OWUF_50_00HZ 6 -#define KX022_OWUF_100_0HZ 7 - -#define KX022_INC2_ZPWUE BIT(0) -#define KX022_INC2_ZNWUE BIT(1) -#define KX022_INC2_YPWUE BIT(2) -#define KX022_INC2_YNWUE BIT(3) -#define KX022_INC2_XPWUE BIT(4) -#define KX022_INC2_XNWUE BIT(5) - -/* Min and Max sampling frequency in mHz */ -#define KX022_ACCEL_MIN_FREQ 12500 -#define KX022_ACCEL_MAX_FREQ MOTION_MAX_SENSOR_FREQUENCY(1600000, 6250) - -#endif /* __CROS_EC_ACCEL_KX022_H */ diff --git a/driver/accel_kxcj9.h b/driver/accel_kxcj9.h deleted file mode 100644 index f7488317f0..0000000000 --- a/driver/accel_kxcj9.h +++ /dev/null @@ -1,111 +0,0 @@ -/* Copyright 2014 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. - */ - -/* KXCJ9 gsensor module for Chrome EC */ - -#ifndef __CROS_EC_ACCEL_KXCJ9_H -#define __CROS_EC_ACCEL_KXCJ9_H - -#include "task.h" - -/* - * 7-bit address is 000111Xb. Where 'X' is determined - * by the voltage on the ADDR pin. - */ -#define KXCJ9_ADDR0_FLAGS 0x0E -#define KXCJ9_ADDR1_FLAGS 0x0D -#define KXCJ9_WHO_AM_I_VAL 0x0A - -/* Chip-specific registers */ -#define KXCJ9_XOUT_L 0x06 -#define KXCJ9_XOUT_H 0x07 -#define KXCJ9_YOUT_L 0x08 -#define KXCJ9_YOUT_H 0x09 -#define KXCJ9_ZOUT_L 0x0a -#define KXCJ9_ZOUT_H 0x0b -#define KXCJ9_DCST_RESP 0x0c -#define KXCJ9_WHOAMI 0x0f -#define KXCJ9_INT_SRC1 0x16 -#define KXCJ9_INT_SRC2 0x17 -#define KXCJ9_STATUS 0x18 -#define KXCJ9_INT_REL 0x1a -#define KXCJ9_CTRL1 0x1b -#define KXCJ9_CTRL2 0x1d -#define KXCJ9_INT_CTRL1 0x1e -#define KXCJ9_INT_CTRL2 0x1f -#define KXCJ9_DATA_CTRL 0x21 -#define KXCJ9_WAKEUP_TIMER 0x29 -#define KXCJ9_SELF_TEST 0x3a -#define KXCJ9_WAKEUP_THRESHOLD 0x6a - -#define KXCJ9_INT_SRC1_WUFS BIT(1) -#define KXCJ9_INT_SRC1_DRDY BIT(4) - -#define KXCJ9_INT_SRC2_ZPWU BIT(0) -#define KXCJ9_INT_SRC2_ZNWU BIT(1) -#define KXCJ9_INT_SRC2_YPWU BIT(2) -#define KXCJ9_INT_SRC2_YNWU BIT(3) -#define KXCJ9_INT_SRC2_XPWU BIT(4) -#define KXCJ9_INT_SRC2_XNWU BIT(5) - -#define KXCJ9_STATUS_INT BIT(4) - -#define KXCJ9_CTRL1_WUFE BIT(1) -#define KXCJ9_CTRL1_DRDYE BIT(5) -#define KXCJ9_CTRL1_PC1 BIT(7) - -#define KXCJ9_GSEL_2G (0 << 3) -#define KXCJ9_GSEL_4G BIT(3) -#define KXCJ9_GSEL_8G (2 << 3) -#define KXCJ9_GSEL_8G_14BIT (3 << 3) -#define KXCJ9_GSEL_ALL (3 << 3) - -#define KXCJ9_RES_8BIT (0 << 6) -#define KXCJ9_RES_12BIT BIT(6) - -#define KXCJ9_CTRL2_OWUF (7 << 0) -#define KXCJ9_CTRL2_DCST BIT(4) -#define KXCJ9_CTRL2_SRST BIT(7) - -#define KXCJ9_OWUF_0_781HZ 0 -#define KXCJ9_OWUF_1_563HZ 1 -#define KXCJ9_OWUF_3_125HZ 2 -#define KXCJ9_OWUF_6_250HZ 3 -#define KXCJ9_OWUF_12_50HZ 4 -#define KXCJ9_OWUF_25_00HZ 5 -#define KXCJ9_OWUF_50_00HZ 6 -#define KXCJ9_OWUF_100_0HZ 7 - -#define KXCJ9_INT_CTRL1_IEL BIT(3) -#define KXCJ9_INT_CTRL1_IEA BIT(4) -#define KXCJ9_INT_CTRL1_IEN BIT(5) - -#define KXCJ9_INT_CTRL2_ZPWUE BIT(0) -#define KXCJ9_INT_CTRL2_ZNWUE BIT(1) -#define KXCJ9_INT_CTRL2_YPWUE BIT(2) -#define KXCJ9_INT_CTRL2_YNWUE BIT(3) -#define KXCJ9_INT_CTRL2_XPWUE BIT(4) -#define KXCJ9_INT_CTRL2_XNWUE BIT(5) - -#define KXCJ9_OSA_0_000HZ 0 -#define KXCJ9_OSA_0_781HZ 8 -#define KXCJ9_OSA_1_563HZ 9 -#define KXCJ9_OSA_3_125HZ 0xa -#define KXCJ9_OSA_6_250HZ 0xb -#define KXCJ9_OSA_12_50HZ 0 -#define KXCJ9_OSA_25_00HZ 1 -#define KXCJ9_OSA_50_00HZ 2 -#define KXCJ9_OSA_100_0HZ 3 -#define KXCJ9_OSA_200_0HZ 4 -#define KXCJ9_OSA_400_0HZ 5 -#define KXCJ9_OSA_800_0HZ 6 -#define KXCJ9_OSA_1600_HZ 7 -#define KXCJ9_OSA_FIELD 0xf - -/* Min and Max sampling frequency in mHz */ -#define KXCJ9_ACCEL_MIN_FREQ 12500 -#define KXCJ9_ACCEL_MAX_FREQ MOTION_MAX_SENSOR_FREQUENCY(1600000, 6250) - -#endif /* __CROS_EC_ACCEL_KXCJ9_H */ diff --git a/driver/accel_lis2ds.c b/driver/accel_lis2ds.c deleted file mode 100644 index 93272262ad..0000000000 --- a/driver/accel_lis2ds.c +++ /dev/null @@ -1,385 +0,0 @@ -/* Copyright 2019 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. - */ - -/** - * LIS2DS Accel module for Chrome EC - * MEMS digital output motion sensor: - * ultra-low-power high-performance 3-axis "pico" accelerometer - * - * For any details on driver implementation please - * Refer to AN4748 Application Note on www.st.com - */ -#include "accelgyro.h" -#include "common.h" -#include "console.h" -#include "driver/accel_lis2ds.h" -#include "hooks.h" -#include "hwtimer.h" -#include "i2c.h" -#include "math_util.h" -#include "motion_sense_fifo.h" -#include "task.h" -#include "timer.h" -#include "util.h" - -#define CPRINTS(format, args...) cprints(CC_ACCEL, format, ## args) - -STATIC_IF(CONFIG_ACCEL_FIFO) volatile uint32_t last_interrupt_timestamp; - -/** - * lis2ds_enable_fifo - Enable/Disable FIFO in LIS2DS12 - * @s: Motion sensor pointer - * @mode: fifo_modes - */ -static int lis2ds_enable_fifo(const struct motion_sensor_t *s, int mode) -{ - return st_write_data_with_mask(s, LIS2DS_FIFO_CTRL_ADDR, - LIS2DS_FIFO_MODE_MASK, mode); -} - -/** - * Load data from internal sensor FIFO - * DIFF8 bits set means FIFO Full because 256 samples -> 0x100 - */ -static int lis2ds_load_fifo(struct motion_sensor_t *s, uint16_t nsamples, - uint32_t saved_ts) -{ - int ret, read_len, fifo_len, chunk_len, i; - struct ec_response_motion_sensor_data vect; - int *axis = s->raw_xyz; - uint8_t fifo[FIFO_READ_LEN]; - - fifo_len = nsamples * OUT_XYZ_SIZE; - read_len = 0; - - while (read_len < fifo_len) { - chunk_len = GENERIC_MIN(fifo_len - read_len, sizeof(fifo)); - - ret = st_raw_read_n_noinc(s->port, s->i2c_spi_addr_flags, - LIS2DS_OUT_X_L_ADDR, fifo, chunk_len); - if (ret != EC_SUCCESS) - return ret; - - for (i = 0; i < chunk_len; i += OUT_XYZ_SIZE) { - /* Apply precision, sensitivity and rotation vector */ - st_normalize(s, axis, &fifo[i]); - - /* Fill vector array */ - vect.data[0] = axis[0]; - vect.data[1] = axis[1]; - vect.data[2] = axis[2]; - vect.flags = 0; - vect.sensor_num = s - motion_sensors; - motion_sense_fifo_stage_data(&vect, s, 3, saved_ts); - } - - read_len += chunk_len; - }; - - if (read_len > 0) - motion_sense_fifo_commit_data(); - - return EC_SUCCESS; -} - -__maybe_unused static int lis2ds_config_interrupt(const struct motion_sensor_t *s) -{ - int ret = EC_SUCCESS; - - /* Interrupt trigger level of power-on-reset is HIGH */ - if (!(s->flags & MOTIONSENSE_FLAG_INT_ACTIVE_HIGH)) { - ret = st_write_data_with_mask(s, LIS2DS_H_ACTIVE_ADDR, - LIS2DS_H_ACTIVE_MASK, LIS2DS_EN_BIT); - if (ret != EC_SUCCESS) - return ret; - } - - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) { - /* - * Configure FIFO threshold to 1 sample: interrupt on watermark - * will be generated every time a new data sample will be stored - * in FIFO. The interrupr on watermark is cleared only when the - * number or samples still present in FIFO exceeds the - * configured threshold. - */ - ret = st_raw_write8(s->port, s->i2c_spi_addr_flags, - LIS2DS_FIFO_THS_ADDR, 1); - if (ret != EC_SUCCESS) - return ret; - - /* Enable interrupt on FIFO watermark and route to int1. */ - ret = st_write_data_with_mask(s, LIS2DS_CTRL4_ADDR, - LIS2DS_INT1_FTH, LIS2DS_EN_BIT); - if (ret != EC_SUCCESS) - return ret; - } - - return ret; -} - -/** - * lis2ds_interrupt - interrupt from int1 pin of sensor - * Schedule Motion Sense Task to manage Interrupts - */ -void lis2ds_interrupt(enum gpio_signal signal) -{ - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) - last_interrupt_timestamp = __hw_clock_source_read(); - - task_set_event(TASK_ID_MOTIONSENSE, CONFIG_ACCEL_LIS2DS_INT_EVENT); -} - -/** - * lis2ds_irq_handler - bottom half of the interrupt stack. - */ -__maybe_unused static int lis2ds_irq_handler(struct motion_sensor_t *s, - uint32_t *event) -{ - int ret = EC_SUCCESS; - - if ((s->type != MOTIONSENSE_TYPE_ACCEL) || - (!(*event & CONFIG_ACCEL_LIS2DS_INT_EVENT))) - return EC_ERROR_NOT_HANDLED; - - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) { - uint16_t nsamples = 0; - uint8_t fifo_src_samples[2]; - - ret = st_raw_read_n_noinc(s->port, - s->i2c_spi_addr_flags, - LIS2DS_FIFO_SRC_ADDR, - (uint8_t *)fifo_src_samples, - sizeof(fifo_src_samples)); - if (ret != EC_SUCCESS) - return ret; - - /* Check if FIFO is full. */ - if (fifo_src_samples[0] & LIS2DS_FIFO_OVR_MASK) - CPRINTS("%s FIFO Overrun", s->name); - - /* DIFF8 = 1 FIFO FULL, 256 unread samples. */ - nsamples = fifo_src_samples[1] & LIS2DS_FIFO_DIFF_MASK; - if (fifo_src_samples[0] & LIS2DS_FIFO_DIFF8_MASK) - nsamples = 256; - - ret = lis2ds_load_fifo(s, nsamples, last_interrupt_timestamp); - } - - return ret; -} - -/** - * set_range - set full scale range - * @s: Motion sensor pointer - * @range: Range - * @rnd: Round up/down flag - */ -static int set_range(struct motion_sensor_t *s, int range, int rnd) -{ - int err; - uint8_t reg_val; - int newrange = ST_NORMALIZE_RATE(range); - - /* Adjust and check rounded value */ - if (rnd && (newrange < range)) - newrange <<= 1; - - if (newrange > LIS2DS_ACCEL_FS_MAX_VAL) - newrange = LIS2DS_ACCEL_FS_MAX_VAL; - else if (newrange < LIS2DS_ACCEL_FS_MIN_VAL) - newrange = LIS2DS_ACCEL_FS_MIN_VAL; - - reg_val = LIS2DS_FS_REG(newrange); - - mutex_lock(s->mutex); - err = st_write_data_with_mask(s, LIS2DS_FS_ADDR, LIS2DS_FS_MASK, - reg_val); - if (err == EC_SUCCESS) - /* Save internally gain for speed optimization. */ - s->current_range = newrange; - mutex_unlock(s->mutex); - - return EC_SUCCESS; -} - -static int set_data_rate(const struct motion_sensor_t *s, int rate, int rnd) -{ - int ret, normalized_rate = 0; - struct stprivate_data *data = s->drv_data; - uint8_t reg_val = 0; - - mutex_lock(s->mutex); - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) { - /* FIFO stop collecting events. Restart FIFO in Bypass mode */ - ret = lis2ds_enable_fifo(s, LIS2DS_FIFO_BYPASS_MODE); - if (ret != EC_SUCCESS) { - CPRINTS("Failed to disable FIFO. Error: %d", ret); - goto unlock_rate; - } - } - - /* Avoid LIS2DS_ODR_TO_REG to manage 0 mHz rate */ - if (rate > 0) { - reg_val = LIS2DS_ODR_TO_REG(rate); - normalized_rate = LIS2DS_REG_TO_ODR(reg_val); - - if (rnd && (normalized_rate < rate)) { - reg_val++; - normalized_rate = LIS2DS_REG_TO_ODR(rate); - } - - if (normalized_rate < LIS2DS_ODR_MIN_VAL || - normalized_rate > LIS2DS_ODR_MAX_VAL) { - ret = EC_RES_INVALID_PARAM; - goto unlock_rate; - } - } - - ret = st_write_data_with_mask(s, LIS2DS_ACC_ODR_ADDR, - LIS2DS_ACC_ODR_MASK, reg_val); - if (ret == EC_SUCCESS) { - data->base.odr = normalized_rate; - - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) { - /* FIFO restart collecting events in Cont. mode. */ - ret = lis2ds_enable_fifo(s, LIS2DS_FIFO_CONT_MODE); - if (ret != EC_SUCCESS) - CPRINTS("Failed to enable FIFO. Error: %d", - ret); - } - } - -unlock_rate: - mutex_unlock(s->mutex); - - return ret; -} - -static int is_data_ready(const struct motion_sensor_t *s, int *ready) -{ - int ret, tmp; - - ret = st_raw_read8(s->port, s->i2c_spi_addr_flags, - LIS2DS_STATUS_REG, &tmp); - if (ret != EC_SUCCESS) { - CPRINTS("%s: type:0x%X RD XYZ Error %d", s->name, s->type, ret); - return ret; - } - - *ready = (LIS2DS_STS_XLDA_UP == (tmp & LIS2DS_STS_XLDA_UP)); - - return EC_SUCCESS; -} - -static int read(const struct motion_sensor_t *s, intv3_t v) -{ - uint8_t raw[OUT_XYZ_SIZE]; - int ret, tmp = 0; - - ret = is_data_ready(s, &tmp); - if (ret != EC_SUCCESS) - return ret; - - /* - * If sensor data is not ready, return the previous read data. - * Note: return success so that motion senor task can read again - * to get the latest updated sensor data quickly. - */ - if (!tmp) { - if (v != s->raw_xyz) - memcpy(v, s->raw_xyz, sizeof(s->raw_xyz)); - return EC_SUCCESS; - } - - /* Read 6 bytes starting at xyz_reg */ - ret = st_raw_read_n_noinc(s->port, s->i2c_spi_addr_flags, - LIS2DS_OUT_X_L_ADDR, raw, - LIS2DS_OUT_XYZ_SIZE); - if (ret != EC_SUCCESS) { - CPRINTS("%s: type:0x%X RD XYZ Error %d", s->name, s->type, ret); - return ret; - } - - /* Transform from LSB to real data with rotation and gain */ - st_normalize(s, v, raw); - - return EC_SUCCESS; -} - -static int init(struct motion_sensor_t *s) -{ - int ret = 0, tmp; - struct stprivate_data *data = s->drv_data; - - ret = st_raw_read8(s->port, s->i2c_spi_addr_flags, - LIS2DS_WHO_AM_I_REG, &tmp); - if (ret != EC_SUCCESS) - return EC_ERROR_UNKNOWN; - - if (tmp != LIS2DS_WHO_AM_I) - return EC_ERROR_ACCESS_DENIED; - - /* - * This sensor can be powered through an EC reboot, so the state of - * the sensor is unknown here. Initiate software reset to restore - * sensor to default. - */ - mutex_lock(s->mutex); - - ret = st_raw_write8(s->port, s->i2c_spi_addr_flags, - LIS2DS_SOFT_RESET_ADDR, LIS2DS_SOFT_RESET_MASK); - if (ret != EC_SUCCESS) - goto err_unlock; - - msleep(20); - - /* Enable BDU */ - ret = st_write_data_with_mask(s, LIS2DS_BDU_ADDR, LIS2DS_BDU_MASK, - LIS2DS_EN_BIT); - if (ret != EC_SUCCESS) - goto err_unlock; - - ret = st_write_data_with_mask(s, LIS2DS_LIR_ADDR, LIS2DS_LIR_MASK, - LIS2DS_EN_BIT); - if (ret != EC_SUCCESS) - goto err_unlock; - - ret = st_write_data_with_mask(s, LIS2DS_INT2_ON_INT1_ADDR, - LIS2DS_INT2_ON_INT1_MASK, LIS2DS_EN_BIT); - if (ret != EC_SUCCESS) - goto err_unlock; - - if (IS_ENABLED(CONFIG_ACCEL_INTERRUPTS)) - ret = lis2ds_config_interrupt(s); - if (ret != EC_SUCCESS) - goto err_unlock; - - mutex_unlock(s->mutex); - - /* Set default resolution */ - data->resol = LIS2DS_RESOLUTION; - - return sensor_init_done(s); - -err_unlock: - mutex_unlock(s->mutex); - CPRINTS("%s: MS Init type:0x%X Error", s->name, s->type); - - return ret; -} - -const struct accelgyro_drv lis2ds_drv = { - .init = init, - .read = read, - .set_range = set_range, - .get_resolution = st_get_resolution, - .set_data_rate = set_data_rate, - .get_data_rate = st_get_data_rate, - .set_offset = st_set_offset, - .get_offset = st_get_offset, -#ifdef CONFIG_ACCEL_INTERRUPTS - .irq_handler = lis2ds_irq_handler, -#endif /* CONFIG_ACCEL_INTERRUPTS */ -}; diff --git a/driver/accel_lis2ds.h b/driver/accel_lis2ds.h deleted file mode 100644 index e25bc5954f..0000000000 --- a/driver/accel_lis2ds.h +++ /dev/null @@ -1,164 +0,0 @@ -/* Copyright 2019 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. - */ - -/* LIS2DS accelerometer module for Chrome EC */ - -#ifndef __CROS_EC_ACCEL_LIS2DS_H -#define __CROS_EC_ACCEL_LIS2DS_H - -#include "driver/stm_mems_common.h" - -/* - * 7-bit address is 110101Xb. Where 'X' is determined - * by the voltage on the ADDR pin. - */ -#define LIS2DS_ADDR0_FLAGS 0x1a -#define LIS2DS_ADDR1_FLAGS 0x1e - -/* who am I */ -#define LIS2DS_WHO_AM_I_REG 0x0f -#define LIS2DS_WHO_AM_I 0x43 - -/* X, Y, Z axis data len */ -#define LIS2DS_OUT_XYZ_SIZE 6 - -/* COMMON DEFINE FOR ACCEL SENSOR */ -#define LIS2DS_EN_BIT 0x01 -#define LIS2DS_DIS_BIT 0x00 - -#define LIS2DS_CTRL1_ADDR 0x20 -#define LIS2DS_CTRL2_ADDR 0x21 -#define LIS2DS_CTRL3_ADDR 0x22 -#define LIS2DS_TAP_X_EN 0x20 -#define LIS2DS_TAP_Y_EN 0x10 -#define LIS2DS_TAP_Z_EN 0x08 -#define LIS2DS_TAP_EN_MASK (LIS2DS_TAP_X_EN | \ - LIS2DS_TAP_Y_EN | \ - LIS2DS_TAP_Z_EN) -#define LIS2DS_TAP_EN_ALL 0x07 - -#define LIS2DS_CTRL4_ADDR 0x23 -#define LIS2DS_INT1_FTH 0x02 -#define LIS2DS_INT1_D_TAP 0x08 -#define LIS2DS_INT1_S_TAP 0x40 - -#define LIS2DS_CTRL5_ADDR 0x24 -#define LIS2DS_FIFO_CTRL_ADDR 0x25 -#define LIS2DS_FIFO_MODE_MASK 0xe0 -#define LIS2DS_FIFO_BYPASS_MODE 0 -#define LIS2DS_FIFO_MODE 1 -#define LIS2DS_FIFO_CONT_MODE 6 - -#define LIS2DS_STATUS_REG 0x27 -#define LIS2DS_STS_XLDA_UP 0x01 -#define LIS2DS_SINGLE_TAP_UP 0x08 -#define LIS2DS_DOUBLE_TAP_UP 0x10 -#define LIS2DS_FIFO_THS_UP 0x80 - -#define LIS2DS_OUT_X_L_ADDR 0x28 -#define LIS2DS_FIFO_THS_ADDR 0x2e - -#define LIS2DS_FIFO_SRC_ADDR 0x2f -#define LIS2DS_FIFO_DIFF_MASK 0xff -#define LIS2DS_FIFO_DIFF8_MASK 0x20 -#define LIS2DS_FIFO_OVR_MASK 0x40 -#define LIS2DS_FIFO_FTH_MASK 0x80 - -/* - * Concatenated with DIFF8 bit in FIFO_SRC (2Fh) register, it represents the - * number of unread samples stored in FIFO. (000000000 = FIFO empty; - * 100000000 = FIFO full, 256 unread samples). - */ -#define LIS2DS_FIFO_SAMPLES_ADDR 0x30 -#define LIS2DS_TAP_6D_THS_ADDR 0x31 -#define LIS2DS_INT_DUR_ADDR 0x32 -#define LIS2DS_WAKE_UP_THS_ADDR 0x33 - -#define LIS2DS_TAP_SRC_ADDR 0x38 -#define LIS2DS_TAP_EVENT_DETECT 0x40 - -/* Alias Register/Mask */ -#define LIS2DS_ACC_ODR_ADDR LIS2DS_CTRL1_ADDR -#define LIS2DS_ACC_ODR_MASK 0xf0 - -#define LIS2DS_BDU_ADDR LIS2DS_CTRL1_ADDR -#define LIS2DS_BDU_MASK 0x01 - -#define LIS2DS_SOFT_RESET_ADDR LIS2DS_CTRL2_ADDR -#define LIS2DS_SOFT_RESET_MASK 0x40 - -#define LIS2DS_LIR_ADDR LIS2DS_CTRL3_ADDR -#define LIS2DS_LIR_MASK 0x04 - -#define LIS2DS_H_ACTIVE_ADDR LIS2DS_CTRL3_ADDR -#define LIS2DS_H_ACTIVE_MASK 0x02 - -#define LIS2DS_INT1_FTH_ADDR LIS2DS_CTRL4_ADDR -#define LIS2DS_INT1_FTH_MASK 0x02 - -#define LIS2DS_INT2_ON_INT1_ADDR LIS2DS_CTRL5_ADDR -#define LIS2DS_INT2_ON_INT1_MASK 0x20 - -#define LIS2DS_DRDY_PULSED_ADDR LIS2DS_CTRL5_ADDR -#define LIS2DS_DRDY_PULSED_MASK 0x80 - -/* Acc data rate for HR mode */ -enum lis2ds_odr { - LIS2DS_ODR_POWER_OFF_VAL = 0x00, - LIS2DS_ODR_12HZ_VAL, - LIS2DS_ODR_25HZ_VAL, - LIS2DS_ODR_50HZ_VAL, - LIS2DS_ODR_100HZ_VAL, - LIS2DS_ODR_200HZ_VAL, - LIS2DS_ODR_400HZ_VAL, - LIS2DS_ODR_800HZ_VAL, - LIS2DS_ODR_LIST_NUM -}; - -/* Absolute Acc rate */ -#define LIS2DS_ODR_MIN_VAL 12500 -#define LIS2DS_ODR_MAX_VAL \ - MOTION_MAX_SENSOR_FREQUENCY(800000, LIS2DS_ODR_MIN_VAL) - -/* ODR reg value from selected data rate in mHz */ -#define LIS2DS_ODR_TO_REG(_odr) (__fls(_odr / LIS2DS_ODR_MIN_VAL) + 1) - -/* Normalized ODR value from selected ODR register value */ -#define LIS2DS_REG_TO_ODR(_reg) \ - (LIS2DS_ODR_MIN_VAL << (_reg - LIS2DS_ODR_12HZ_VAL)) - -/* Full scale range registers */ -#define LIS2DS_FS_ADDR LIS2DS_CTRL1_ADDR -#define LIS2DS_FS_MASK 0x0c - -/* Acc FS value */ -enum lis2ds_fs { - LIS2DS_FS_2G_VAL = 0x00, - LIS2DS_FS_16G_VAL, - LIS2DS_FS_4G_VAL, - LIS2DS_FS_8G_VAL, - LIS2DS_FS_LIST_NUM -}; - -#define LIS2DS_ACCEL_FS_MAX_VAL 16 -#define LIS2DS_ACCEL_FS_MIN_VAL 2 - -/* Reg value from Full Scale */ -#define LIS2DS_FS_REG(_fs) \ - (_fs == 2 ? LIS2DS_FS_2G_VAL : \ - _fs == 16 ? LIS2DS_FS_16G_VAL : \ - __fls(_fs)) - -/* - * Sensor resolution in number of bits. Sensor has two resolution: - * 10 and 14 bit for LP and HR mode resp. - */ -#define LIS2DS_RESOLUTION 16 - -extern const struct accelgyro_drv lis2ds_drv; - -void lis2ds_interrupt(enum gpio_signal signal); - -#endif /* __CROS_EC_ACCEL_LIS2DS_H */ diff --git a/driver/accel_lis2dw12.c b/driver/accel_lis2dw12.c deleted file mode 100644 index 1872e572f2..0000000000 --- a/driver/accel_lis2dw12.c +++ /dev/null @@ -1,609 +0,0 @@ -/* Copyright 2019 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. - */ - -/* - * LIS2DW12 accelerometer module for Chrome EC 3D digital accelerometer. - * For more details on LIS2DW12 device please refers to www.st.com. - */ -#include "accelgyro.h" -#include "common.h" -#include "console.h" -#include "accel_lis2dw12.h" -#include "hooks.h" -#include "hwtimer.h" -#include "math_util.h" -#include "motion_sense_fifo.h" -#include "task.h" -#include "util.h" - -#define CPRINTF(format, args...) cprintf(CC_ACCEL, format, ## args) -#define CPRINTS(format, args...) cprints(CC_ACCEL, format, ## args) - -#if defined(CONFIG_ACCEL_INTERRUPTS) && defined(CONFIG_ACCEL_LIS2DW_AS_BASE) -/* - * Enable interrupts and FIFO only when the accelerometer is the main sensor. - */ -#define LIS2DW12_ENABLE_FIFO -#endif - -#if defined(CONFIG_ZEPHYR) && defined(CONFIG_ACCEL_INTERRUPTS) -/* Get the motion sensor ID of the LIS2DW12 sensor that generates the - * interrupt. The interrupt is converted to the event and transferred to - * motion sense task that actually handles the interrupt. - * - * Here we use an alias (lis2dw12_int) to get the motion sensor ID. This alias - * MUST be defined for this driver to work. - * aliases { - * lis2dw12-int = &lid_accel; - * }; - */ -#if DT_NODE_EXISTS(DT_ALIAS(lis2dw12_int)) -#define CONFIG_ACCEL_LIS2DW12_INT_EVENT \ - TASK_EVENT_MOTION_SENSOR_INTERRUPT(SENSOR_ID(DT_ALIAS(lis2dw12_int))) -#endif -#endif - -STATIC_IF(LIS2DW12_ENABLE_FIFO) volatile uint32_t last_interrupt_timestamp; - -/** - * lis2dw12_enable_fifo - Enable/Disable FIFO in LIS2DW12 - * @s: Motion sensor pointer - * @mode: fifo_modes - */ -static __maybe_unused int lis2dw12_enable_fifo(const struct motion_sensor_t *s, - enum lis2dw12_fmode mode) -{ - return st_write_data_with_mask(s, LIS2DW12_FIFO_CTRL_ADDR, - LIS2DW12_FIFO_MODE_MASK, mode); -} - -/** - * Load data from internal sensor FIFO. - * @s: Motion sensor pointer - */ -static __maybe_unused int lis2dw12_load_fifo(struct motion_sensor_t *s, - int nsamples, uint32_t *last_fifo_read_ts) -{ - int ret, left, length, i; - struct ec_response_motion_sensor_data vect; - uint32_t interrupt_timestamp = last_interrupt_timestamp; - int *axis = s->raw_xyz; - uint8_t fifo[FIFO_READ_LEN]; - - /* Each sample are OUT_XYZ_SIZE bytes. */ - left = nsamples * OUT_XYZ_SIZE; - - do { - /* - * Limit FIFO read data to burst of FIFO_READ_LEN size because - * read operatios in under i2c mutex lock. - */ - if (left > FIFO_READ_LEN) - length = FIFO_READ_LEN; - else - length = left; - - ret = st_raw_read_n(s->port, s->i2c_spi_addr_flags, - LIS2DW12_OUT_X_L_ADDR, fifo, length); - *last_fifo_read_ts = __hw_clock_source_read(); - if (ret != EC_SUCCESS) - return ret; - - for (i = 0; i < length; i += OUT_XYZ_SIZE) { - /* Apply precision, sensitivity and rotation vector. */ - st_normalize(s, axis, &fifo[i]); - - /* Fill vector array. */ - vect.data[X] = axis[X]; - vect.data[Y] = axis[Y]; - vect.data[Z] = axis[Z]; - vect.flags = 0; - vect.sensor_num = s - motion_sensors; - motion_sense_fifo_stage_data(&vect, s, 3, - interrupt_timestamp); - } - left -= length; - } while (left > 0); - - motion_sense_fifo_commit_data(); - - return EC_SUCCESS; -} - -/** - * lis2dw12_get_fifo_samples - check for stored FIFO samples. - */ -static __maybe_unused int lis2dw12_get_fifo_samples(struct motion_sensor_t *s, - int *nsamples) -{ - int ret, tmp; - - ret = st_raw_read8(s->port, s->i2c_spi_addr_flags, - LIS2DW12_FIFO_SAMPLES_ADDR, &tmp); - if (ret != EC_SUCCESS) - return ret; - - *nsamples = tmp & LIS2DW12_FIFO_DIFF_MASK; - - return EC_SUCCESS; -} - -static __maybe_unused int fifo_data_avail(struct motion_sensor_t *s) -{ - int ret, nsamples; - - if (s->flags & MOTIONSENSE_FLAG_INT_SIGNAL) - return gpio_get_level(s->int_signal) == - !!(MOTIONSENSE_FLAG_INT_ACTIVE_HIGH & s->flags); - - ret = lis2dw12_get_fifo_samples(s, &nsamples); - /* If we failed to read the FIFO size assume empty. */ - if (ret != EC_SUCCESS) - return 0; - return nsamples; -} - -/** - * lis2dw12_config_interrupt- Configure interrupt for supported features. - * @s: Motion sensor pointer - * - * Must works with interface mutex locked - */ -static __maybe_unused int lis2dw12_config_interrupt( - const struct motion_sensor_t *s) -{ - int ret = EC_SUCCESS; - - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) { - /* Configure FIFO watermark level. */ - ret = st_write_data_with_mask(s, LIS2DW12_FIFO_CTRL_ADDR, - LIS2DW12_FIFO_THRESHOLD_MASK, 1); - if (ret != EC_SUCCESS) - return ret; - - /* Enable interrupt on FIFO watermark and route to int1. */ - ret = st_write_data_with_mask(s, LIS2DW12_INT1_FTH_ADDR, - LIS2DW12_INT1_FTH_MASK, LIS2DW12_EN_BIT); - if (ret != EC_SUCCESS) - return ret; - } - - if (IS_ENABLED(CONFIG_GESTURE_SENSOR_DOUBLE_TAP)) { - /* - * Configure D-TAP event detection on 3 axis. - * For more details please refer to AN5038. - */ - ret = st_raw_write8(s->port, s->i2c_spi_addr_flags, - LIS2DW12_TAP_THS_X_ADDR, 0x09); - if (ret != EC_SUCCESS) - return ret; - ret = st_raw_write8(s->port, s->i2c_spi_addr_flags, - LIS2DW12_TAP_THS_Y_ADDR, 0x09); - if (ret != EC_SUCCESS) - return ret; - ret = st_raw_write8(s->port, s->i2c_spi_addr_flags, - LIS2DW12_TAP_THS_Z_ADDR, 0xE9); - if (ret != EC_SUCCESS) - return ret; - ret = st_raw_write8(s->port, s->i2c_spi_addr_flags, - LIS2DW12_INT_DUR_ADDR, 0x7F); - if (ret != EC_SUCCESS) - return ret; - - /* Enable D-TAP event detection. */ - ret = st_write_data_with_mask(s, LIS2DW12_WAKE_UP_THS_ADDR, - LIS2DW12_SINGLE_DOUBLE_TAP, - LIS2DW12_EN_BIT); - if (ret != EC_SUCCESS) - return ret; - - /* - * Enable D-TAP detection on int_1 pad. In any case D-TAP event - * can be detected only if ODR is over 200 Hz. - */ - ret = st_write_data_with_mask(s, LIS2DW12_INT1_TAP_ADDR, - LIS2DW12_INT1_DTAP_MASK, - LIS2DW12_EN_BIT); - } - return ret; -} - -#ifdef LIS2DW12_ENABLE_FIFO -static void lis2dw12_handle_interrupt_for_fifo(uint32_t ts) -{ - if (IS_ENABLED(CONFIG_ACCEL_FIFO) && - time_after(ts, last_interrupt_timestamp)) - last_interrupt_timestamp = ts; - - task_set_event(TASK_ID_MOTIONSENSE, CONFIG_ACCEL_LIS2DW12_INT_EVENT); -} - -/** - * lis2dw12_interrupt - interrupt from int pin of sensor - * Schedule Motion Sense Task to manage Interrupts. - */ -void lis2dw12_interrupt(enum gpio_signal signal) -{ - lis2dw12_handle_interrupt_for_fifo(__hw_clock_source_read()); -} - -/** - * lis2dw12_irq_handler - bottom half of the interrupt stack. - */ -static int lis2dw12_irq_handler(struct motion_sensor_t *s, - uint32_t *event) -{ - int ret = EC_SUCCESS; - - if ((s->type != MOTIONSENSE_TYPE_ACCEL) || - (!(*event & CONFIG_ACCEL_LIS2DW12_INT_EVENT))) { - return EC_ERROR_NOT_HANDLED; - } - - if (IS_ENABLED(CONFIG_GESTURE_SENSOR_DOUBLE_TAP)) { - int status = 0; - - /* Read Status register to check TAP events. */ - st_raw_read8(s->port, s->i2c_spi_addr_flags, - LIS2DW12_STATUS_TAP, &status); - if (status & LIS2DW12_DOUBLE_TAP) - *event |= TASK_EVENT_MOTION_ACTIVITY_INTERRUPT( - MOTIONSENSE_ACTIVITY_DOUBLE_TAP); - } - - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) { - int nsamples; - uint32_t last_fifo_read_ts; - uint32_t triggering_interrupt_timestamp = - last_interrupt_timestamp; - - ret = lis2dw12_get_fifo_samples(s, &nsamples); - if (ret != EC_SUCCESS) - return ret; - - last_fifo_read_ts = __hw_clock_source_read(); - if (nsamples == 0) - return EC_SUCCESS; - - ret = lis2dw12_load_fifo(s, nsamples, &last_fifo_read_ts); - - /* - * Check if FIFO isn't empty and we never got an interrupt. - * This can happen if new entries were added to the FIFO after - * the count was read, but before the FIFO was cleared out. - * In the long term it might be better to use the last - * spread timestamp instead. - */ - if (fifo_data_avail(s) && - triggering_interrupt_timestamp == last_interrupt_timestamp) - lis2dw12_handle_interrupt_for_fifo(last_fifo_read_ts); - } - - return ret; -} -#endif - -/** - * set_power_mode - set sensor power mode - * @s: Motion sensor pointer - * @mode: LIS2DW12_LOW_POWER, LIS2DW12_HIGH_PERF - * @lpmode: LIS2DW12_LOW_POWER_MODE_2, - * LIS2DW12_LOW_POWER_MODE_3, - * LIS2DW12_LOW_POWER_MODE_4 - * - * TODO: LIS2DW12_LOW_POWER_MODE_1 not implemented because output differ - * in resolution - */ -static int set_power_mode(const struct motion_sensor_t *s, - enum lis2sw12_mode mode, - enum lis2sw12_lpmode lpmode) -{ - int ret = EC_SUCCESS; - - if (mode == LIS2DW12_LOW_POWER && - lpmode == LIS2DW12_LOW_POWER_MODE_1) - return EC_ERROR_UNIMPLEMENTED; - - /* Set Mode and Low Power Mode. */ - ret = st_write_data_with_mask(s, LIS2DW12_ACC_MODE_ADDR, - LIS2DW12_ACC_MODE_MASK, mode); - if (ret != EC_SUCCESS) - return ret; - - ret = st_write_data_with_mask(s, LIS2DW12_ACC_LPMODE_ADDR, - LIS2DW12_ACC_LPMODE_MASK, lpmode); - return ret; -} - -/** - * set_range - set full scale range - * @s: Motion sensor pointer - * @range: Range - * @rnd: Round up/down flag - */ -static int set_range(struct motion_sensor_t *s, int range, int rnd) -{ - int err = EC_SUCCESS; - uint8_t reg_val; - int newrange = range; - - /* Adjust and check rounded value. */ - if (rnd && (newrange < LIS2DW12_NORMALIZE_FS(newrange))) - newrange <<= 1; - - if (newrange > LIS2DW12_ACCEL_FS_MAX_VAL) - newrange = LIS2DW12_ACCEL_FS_MAX_VAL; - - reg_val = LIS2DW12_FS_REG(newrange); - - mutex_lock(s->mutex); - /* - * FIFO stop collecting events. Restart FIFO in Bypass mode. - * If Range is changed all samples in FIFO must be discharged because - * with a different sensitivity. - */ - if (IS_ENABLED(LIS2DW12_ENABLE_FIFO)) { - err = lis2dw12_enable_fifo(s, LIS2DW12_FIFO_BYPASS_MODE); - if (err != EC_SUCCESS) - goto unlock_rate; - } - - err = st_write_data_with_mask(s, LIS2DW12_FS_ADDR, LIS2DW12_FS_MASK, - reg_val); - if (err == EC_SUCCESS) - s->current_range = newrange; - else - goto unlock_rate; - - /* FIFO restart collecting events in Cont. mode. */ - if (IS_ENABLED(LIS2DW12_ENABLE_FIFO)) - err = lis2dw12_enable_fifo(s, LIS2DW12_FIFO_CONT_MODE); - -unlock_rate: - mutex_unlock(s->mutex); - - return err; -} - -/** - * ODR reg value from selected data rate in mHz. - */ -static uint8_t odr_to_reg(int odr) -{ - if (odr <= LIS2DW12_ODR_MIN_VAL) - return LIS2DW12_ODR_12HZ_VAL; - - return (__fls(odr / LIS2DW12_ODR_MIN_VAL) + LIS2DW12_ODR_12HZ_VAL); -} - -/** - * Normalized ODR value from selected data rate in mHz. - */ -static int odr_to_normalize(int odr) -{ - if (odr <= LIS2DW12_ODR_MIN_VAL) - return LIS2DW12_ODR_MIN_VAL; - - return (LIS2DW12_ODR_MIN_VAL << (__fls(odr / LIS2DW12_ODR_MIN_VAL))); -} - -static int set_data_rate(const struct motion_sensor_t *s, int rate, int rnd) -{ - int ret, normalized_rate; - struct stprivate_data *data = s->drv_data; - uint8_t reg_val; - - mutex_lock(s->mutex); - - /* FIFO stop collecting events. Restart FIFO in Bypass mode. */ - if (IS_ENABLED(LIS2DW12_ENABLE_FIFO)) { - ret = lis2dw12_enable_fifo(s, LIS2DW12_FIFO_BYPASS_MODE); - if (ret != EC_SUCCESS) - goto unlock_rate; - } - - if (rate == 0) { - ret = st_write_data_with_mask(s, LIS2DW12_ACC_ODR_ADDR, - LIS2DW12_ACC_ODR_MASK, - LIS2DW12_ODR_POWER_OFF_VAL); - if (ret == EC_SUCCESS) - data->base.odr = LIS2DW12_ODR_POWER_OFF_VAL; - - goto unlock_rate; - } - - reg_val = odr_to_reg(rate); - normalized_rate = odr_to_normalize(rate); - - if (rnd && (normalized_rate < rate)) { - reg_val++; - normalized_rate <<= 1; - } - - if (reg_val > LIS2DW12_ODR_1_6kHZ_VAL) { - reg_val = LIS2DW12_ODR_1_6kHZ_VAL; - normalized_rate = LIS2DW12_ODR_MAX_VAL; - } else if (reg_val < LIS2DW12_ODR_12HZ_VAL) { - reg_val = LIS2DW12_ODR_12HZ_VAL; - normalized_rate = LIS2DW12_ODR_MIN_VAL; - } - - /* lis2dwl supports 14 bit resolution only at high performance mode, - * and it will always stay at high performance mode from initialization. - * But lis2dw12 needs switch low power mode according to odr value. - */ - if (!IS_ENABLED(CONFIG_ACCEL_LIS2DWL)) { - if (reg_val > LIS2DW12_ODR_200HZ_VAL) - ret = set_power_mode(s, LIS2DW12_HIGH_PERF, 0); - else - ret = set_power_mode(s, LIS2DW12_LOW_POWER, - LIS2DW12_LOW_POWER_MODE_2); - } - - ret = st_write_data_with_mask(s, LIS2DW12_ACC_ODR_ADDR, - LIS2DW12_ACC_ODR_MASK, reg_val); - if (ret == EC_SUCCESS) - data->base.odr = normalized_rate; - - /* FIFO restart collecting events in continuous mode. */ - if (IS_ENABLED(LIS2DW12_ENABLE_FIFO)) - ret = lis2dw12_enable_fifo(s, LIS2DW12_FIFO_CONT_MODE); - -unlock_rate: - mutex_unlock(s->mutex); - - return ret; -} - -static int is_data_ready(const struct motion_sensor_t *s, int *ready) -{ - int ret, tmp; - - ret = st_raw_read8(s->port, s->i2c_spi_addr_flags, - LIS2DW12_STATUS_REG, &tmp); - if (ret != EC_SUCCESS) - return ret; - - *ready = (LIS2DW12_STS_DRDY_UP == (tmp & LIS2DW12_STS_DRDY_UP)); - - return EC_SUCCESS; -} - -static int read(const struct motion_sensor_t *s, intv3_t v) -{ - uint8_t raw[OUT_XYZ_SIZE]; - int ret, tmp = 0; - - ret = is_data_ready(s, &tmp); - if (ret != EC_SUCCESS) - return ret; - - /* - * If sensor data is not ready, return the previous read data. - * Note: return success so that motion senor task can read again - * to get the latest updated sensor data quickly. - */ - if (!tmp) { - if (v != s->raw_xyz) - memcpy(v, s->raw_xyz, sizeof(s->raw_xyz)); - return EC_SUCCESS; - } - - /* Read 6 bytes starting at xyz_reg. */ - ret = st_raw_read_n_noinc(s->port, s->i2c_spi_addr_flags, - LIS2DW12_OUT_X_L_ADDR, raw, - OUT_XYZ_SIZE); - if (ret != EC_SUCCESS) { - CPRINTS("%s type:0x%X RD XYZ Error", s->name, s->type); - return ret; - } - - /* Transform from LSB to real data with rotation and gain. */ - st_normalize(s, v, raw); - - return EC_SUCCESS; -} - -static int init(struct motion_sensor_t *s) -{ - int ret = 0, tmp, timeout = 0, status; - struct stprivate_data *data = s->drv_data; - - ret = st_raw_read8(s->port, s->i2c_spi_addr_flags, - LIS2DW12_WHO_AM_I_REG, &tmp); - if (ret != EC_SUCCESS) - return ret; - - if (tmp != LIS2DW12_WHO_AM_I) - return EC_ERROR_ACCESS_DENIED; - - /* - * This sensor can be powered through an EC reboot, so the state of - * the sensor is unknown here. Initiate software reset to restore - * sensor to default. - */ - mutex_lock(s->mutex); - ret = st_raw_write8(s->port, s->i2c_spi_addr_flags, - LIS2DW12_SOFT_RESET_ADDR, LIS2DW12_SOFT_RESET_MASK); - if (ret != EC_SUCCESS) - goto err_unlock; - - /* Wait End of Reset. */ - do { - if (timeout > 10) { - ret = EC_ERROR_TIMEOUT; - goto err_unlock; - } - - msleep(1); - timeout += 1; - ret = st_raw_read8(s->port, s->i2c_spi_addr_flags, - LIS2DW12_SOFT_RESET_ADDR, &status); - } while (ret != EC_SUCCESS || (status & LIS2DW12_SOFT_RESET_MASK) != 0); - - /* Enable BDU. */ - ret = st_write_data_with_mask(s, LIS2DW12_BDU_ADDR, LIS2DW12_BDU_MASK, - LIS2DW12_EN_BIT); - if (ret != EC_SUCCESS) - goto err_unlock; - - ret = st_write_data_with_mask(s, LIS2DW12_LIR_ADDR, LIS2DW12_LIR_MASK, - LIS2DW12_EN_BIT); - if (ret != EC_SUCCESS) - goto err_unlock; - - /* Interrupt trigger level of power-on-reset is HIGH */ - if (IS_ENABLED(LIS2DW12_ENABLE_FIFO) && - !(MOTIONSENSE_FLAG_INT_ACTIVE_HIGH & s->flags)) { - ret = st_write_data_with_mask(s, LIS2DW12_H_ACTIVE_ADDR, - LIS2DW12_H_ACTIVE_MASK, - LIS2DW12_EN_BIT); - if (ret != EC_SUCCESS) - goto err_unlock; - } - - if (IS_ENABLED(CONFIG_ACCEL_LIS2DWL)) - /* - * lis2dwl supports 14 bit resolution only - * at high performance mode - */ - ret = set_power_mode(s, LIS2DW12_HIGH_PERF, 0); - else - /* Set default Mode and Low Power Mode. */ - ret = set_power_mode(s, LIS2DW12_LOW_POWER, - LIS2DW12_LOW_POWER_MODE_2); - if (ret != EC_SUCCESS) - goto err_unlock; - - if (IS_ENABLED(LIS2DW12_ENABLE_FIFO)) { - ret = lis2dw12_config_interrupt(s); - if (ret != EC_SUCCESS) - goto err_unlock; - } - mutex_unlock(s->mutex); - - /* Set default resolution. */ - data->resol = LIS2DW12_RESOLUTION; - return sensor_init_done(s); - -err_unlock: - mutex_unlock(s->mutex); - CPRINTS("%s: MS Init type:0x%X Error(%d)", s->name, s->type, ret); - return ret; -} - -const struct accelgyro_drv lis2dw12_drv = { - .init = init, - .read = read, - .set_range = set_range, - .get_resolution = st_get_resolution, - .set_data_rate = set_data_rate, - .get_data_rate = st_get_data_rate, - .set_offset = st_set_offset, - .get_offset = st_get_offset, -#ifdef LIS2DW12_ENABLE_FIFO - .irq_handler = lis2dw12_irq_handler, -#endif /* CONFIG_ACCEL_INTERRUPTS && CONFIG_ACCEL_LIS2DW_AS_BASE */ -}; diff --git a/driver/accel_lis2dw12.h b/driver/accel_lis2dw12.h deleted file mode 100644 index 8e1c97464c..0000000000 --- a/driver/accel_lis2dw12.h +++ /dev/null @@ -1,209 +0,0 @@ -/* Copyright 2019 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. - */ - -/* - * LIS2DW12 accelerometer include file for Chrome EC 3D digital accelerometer. - * For more details on LIS2DW12 device please refer to www.st.com. - */ - -#ifndef __CROS_EC_ACCEL_LIS2DW12_H -#define __CROS_EC_ACCEL_LIS2DW12_H - -#include "driver/accel_lis2dw12_public.h" -#include "stm_mems_common.h" - -/* Who am I. */ -#define LIS2DW12_WHO_AM_I_REG 0x0f -#define LIS2DW12_WHO_AM_I 0x44 - -/* Registers sensor. */ -#define LIS2DW12_CTRL1_ADDR 0x20 -#define LIS2DW12_CTRL2_ADDR 0x21 -#define LIS2DW12_CTRL3_ADDR 0x22 - -#define LIS2DW12_CTRL4_ADDR 0x23 - -/* CTRL4 bits. */ -#define LIS2DW12_INT1_FTH 0x02 -#define LIS2DW12_INT1_D_TAP 0x08 -#define LIS2DW12_INT1_S_TAP 0x40 - -#define LIS2DW12_CTRL5_ADDR 0x24 - -/* CTRL5 bits. */ -#define LIS2DW12_INT2_FTH 0x02 - -#define LIS2DW12_CTRL6_ADDR 0x25 -#define LIS2DW12_STATUS_REG 0x27 - -/* STATUS bits. */ -#define LIS2DW12_STS_DRDY_UP 0x01 -#define LIS2DW12_SINGLE_TAP_UP 0x08 -#define LIS2DW12_DOUBLE_TAP_UP 0x10 -#define LIS2DW12_FIFO_THS_UP 0x80 - -#define LIS2DW12_OUT_X_L_ADDR 0x28 - -#define LIS2DW12_FIFO_CTRL_ADDR 0x2e - -/* FIFO_CTRL bits. */ -#define LIS2DW12_FIFO_MODE_MASK 0xe0 - -/* List of supported FIFO mode. */ -enum lis2dw12_fmode { - LIS2DW12_FIFO_BYPASS_MODE = 0, - LIS2DW12_FIFO_MODE, - LIS2DW12_FIFO_CONT_MODE = 6 -}; - -#define LIS2DW12_FIFO_THRESHOLD_MASK 0x1f - -#define LIS2DW12_FIFO_SAMPLES_ADDR 0x2f -#define LIS2DW12_TAP_THS_X_ADDR 0x30 -#define LIS2DW12_TAP_THS_Y_ADDR 0x31 -#define LIS2DW12_TAP_THS_Z_ADDR 0x32 -#define LIS2DW12_INT_DUR_ADDR 0x33 - -#define LIS2DW12_WAKE_UP_THS_ADDR 0x34 - -/* TAP bits. */ -#define LIS2DW12_SINGLE_DOUBLE_TAP 0x80 - -/* FIFO_SAMPLES bits. */ -#define LIS2DW12_FIFO_DIFF_MASK 0x3f -#define LIS2DW12_FIFO_OVR_MASK 0x40 -#define LIS2DW12_FIFO_FTH_MASK 0x80 - -#define LIS2DW12_ABS_INT_CFG_ADDR 0x3f - -/* INT Configuration bits. */ -#define LIS2DW12_DRDY_PULSED 0x80 -#define LIS2DW12_INT2_ON_INT1 0x40 -#define LIS2DW12_INT_ENABLE 0x20 - -/* Alias Registers/Masks. */ -#define LIS2DW12_ACC_ODR_ADDR LIS2DW12_CTRL1_ADDR -#define LIS2DW12_ACC_ODR_MASK 0xf0 - -#define LIS2DW12_ACC_MODE_ADDR LIS2DW12_CTRL1_ADDR -#define LIS2DW12_ACC_MODE_MASK 0x0c - -/* Power mode selection. */ -enum lis2sw12_mode { - LIS2DW12_LOW_POWER = 0, - LIS2DW12_HIGH_PERF, - LIS2DW12_SINGLE_DC, - LIS2DW12_LOW_POWER_LIST_NUM -}; - -#define LIS2DW12_ACC_LPMODE_ADDR LIS2DW12_CTRL1_ADDR -#define LIS2DW12_ACC_LPMODE_MASK 0x03 - -/* - * Low power mode selection. - * TODO: Support all Low Power Mode. Actually is not supported only - * LOW_POWER_MODE_1. - */ -enum lis2sw12_lpmode { - LIS2DW12_LOW_POWER_MODE_1 = 0, - LIS2DW12_LOW_POWER_MODE_2, - LIS2DW12_LOW_POWER_MODE_3, - LIS2DW12_LOW_POWER_MODE_4, - LIS2DW12_LOW_POWER_MODE_LIST_NUM -}; - -#define LIS2DW12_BDU_ADDR LIS2DW12_CTRL2_ADDR -#define LIS2DW12_BDU_MASK 0x08 - -#define LIS2DW12_SOFT_RESET_ADDR LIS2DW12_CTRL2_ADDR -#define LIS2DW12_SOFT_RESET_MASK 0x40 - -#define LIS2DW12_BOOT_ADDR LIS2DW12_CTRL2_ADDR -#define LIS2DW12_BOOT_MASK 0x80 - -#define LIS2DW12_LIR_ADDR LIS2DW12_CTRL3_ADDR -#define LIS2DW12_LIR_MASK 0x10 - -#define LIS2DW12_H_ACTIVE_ADDR LIS2DW12_CTRL3_ADDR -#define LIS2DW12_H_ACTIVE_MASK 0x08 - -#define LIS2DW12_INT1_FTH_ADDR LIS2DW12_CTRL4_ADDR -#define LIS2DW12_INT1_FTH_MASK LIS2DW12_INT1_FTH - -#define LIS2DW12_INT1_TAP_ADDR LIS2DW12_CTRL4_ADDR -#define LIS2DW12_INT1_DTAP_MASK 0x08 -#define LIS2DW12_INT1_STAP_MASK 0x40 - -#define LIS2DW12_INT1_D_TAP_EN LIS2DW12_INT1_DTAP_MASK - -#define LIS2DW12_STATUS_TAP LIS2DW12_STS_DRDY_UP -#define LIS2DW12_SINGLE_TAP LIS2DW12_SINGLE_TAP_UP -#define LIS2DW12_DOUBLE_TAP LIS2DW12_DOUBLE_TAP_UP - -#define LIS2DW12_INT2_ON_INT1_ADDR LIS2DW12_ABS_INT_CFG_ADDR -#define LIS2DW12_INT2_ON_INT1_MASK LIS2DW12_INT2_ON_INT1 - -#define LIS2DW12_DRDY_PULSED_ADDR LIS2DW12_ABS_INT_CFG_ADDR -#define LIS2DW12_DRDY_PULSED_MASK LIS2DW12_DRDY_PULSED - -/* Acc data rate for HR mode. */ -enum lis2dw12_odr { - LIS2DW12_ODR_POWER_OFF_VAL = 0x00, - LIS2DW12_ODR_12HZ_VAL = 0x02, - LIS2DW12_ODR_25HZ_VAL, - LIS2DW12_ODR_50HZ_VAL, - LIS2DW12_ODR_100HZ_VAL, - LIS2DW12_ODR_200HZ_VAL, - LIS2DW12_ODR_400HZ_VAL, - LIS2DW12_ODR_800HZ_VAL, - LIS2DW12_ODR_1_6kHZ_VAL, - LIS2DW12_ODR_LIST_NUM -}; - -/* Full scale range registers. */ -#define LIS2DW12_FS_ADDR LIS2DW12_CTRL6_ADDR -#define LIS2DW12_FS_MASK 0x30 - -/* Acc FS value. */ -enum lis2dw12_fs { - LIS2DW12_FS_2G_VAL = 0x00, - LIS2DW12_FS_4G_VAL, - LIS2DW12_FS_8G_VAL, - LIS2DW12_FS_16G_VAL, - LIS2DW12_FS_LIST_NUM -}; - -#define LIS2DW12_ACCEL_FS_MAX_VAL 16 - -/* Acc Gain value. */ -#define LIS2DW12_FS_2G_GAIN 3904 -#define LIS2DW12_FS_4G_GAIN (LIS2DW12_FS_2G_GAIN << 1) -#define LIS2DW12_FS_8G_GAIN (LIS2DW12_FS_2G_GAIN << 2) -#define LIS2DW12_FS_16G_GAIN (LIS2DW12_FS_2G_GAIN << 3) - -/* FS Full Scale value from Gain. */ -#define LIS2DW12_GAIN_FS(_gain) \ - (2 << (31 - __builtin_clz(_gain / LIS2DW12_FS_2G_GAIN))) - -/* Gain value from selected Full Scale. */ -#define LIS2DW12_FS_GAIN(_fs) \ - (LIS2DW12_FS_2G_GAIN << (30 - __builtin_clz(_fs))) - -/* Reg value from Full Scale. */ -#define LIS2DW12_FS_REG(_fs) \ - (30 - __builtin_clz(_fs)) - -/* Normalized FS value from Full Scale. */ -#define LIS2DW12_NORMALIZE_FS(_fs) \ - (1 << (30 - __builtin_clz(_fs))) - -/* - * Sensor resolution in number of bits. - * Sensor driver support 14 bits resolution. - * TODO: Support all "LP Power Mode" (res. 12/14 bits). - */ -#define LIS2DW12_RESOLUTION 14 - -#endif /* __CROS_EC_ACCEL_LIS2DW12_H */ diff --git a/driver/accelgyro_bmi160.c b/driver/accelgyro_bmi160.c deleted file mode 100644 index f92f61d181..0000000000 --- a/driver/accelgyro_bmi160.c +++ /dev/null @@ -1,780 +0,0 @@ -/* 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. - */ - -/** - * BMI160 accelerometer and gyro module for Chrome EC - * 3D digital accelerometer & 3D digital gyroscope - */ - -#include "accelgyro.h" -#include "common.h" -#include "console.h" -#include "accelgyro_bmi_common.h" -#include "accelgyro_bmi160.h" -#include "mag_bmm150.h" -#include "hwtimer.h" -#include "i2c.h" -#include "math_util.h" -#include "motion_orientation.h" -#include "motion_sense_fifo.h" -#include "spi.h" -#include "task.h" -#include "timer.h" -#include "util.h" - -#define CPUTS(outstr) cputs(CC_ACCEL, outstr) -#define CPRINTF(format, args...) cprintf(CC_ACCEL, format, ## args) -#define CPRINTS(format, args...) cprints(CC_ACCEL, format, ## args) - -#if defined(CONFIG_ZEPHYR) && defined(CONFIG_ACCEL_INTERRUPTS) -/* Get the motion sensor ID of the BMI160 sensor that generates the interrupt. - * The interrupt is converted to the event and transferred to motion sense task - * that actually handles the interrupt. - * - * Here we use an alias (bmi160_int) to get the motion sensor ID. This alias - * MUST be defined for this driver to work. - * aliases { - * bmi160-int = &base_accel; - * }; - */ -#if DT_NODE_EXISTS(DT_ALIAS(bmi160_int)) -#define CONFIG_ACCELGYRO_BMI160_INT_EVENT \ - TASK_EVENT_MOTION_SENSOR_INTERRUPT(SENSOR_ID(DT_ALIAS(bmi160_int))) -#endif -#endif - -STATIC_IF(CONFIG_BMI_ORIENTATION_SENSOR) void irq_set_orientation( - struct motion_sensor_t *s, - int interrupt); - -STATIC_IF(CONFIG_ACCEL_FIFO) volatile uint32_t last_interrupt_timestamp; - -static int wakeup_time[] = { - [MOTIONSENSE_TYPE_ACCEL] = 4, - [MOTIONSENSE_TYPE_GYRO] = 80, - [MOTIONSENSE_TYPE_MAG] = 1 -}; - -/** - * Control access to the compass on the secondary i2c interface: - * enable values are: - * 1: manual access, we can issue i2c to the compass - * 0: data access: BMI160 gather data periodically from the compass. - */ -static __maybe_unused int bmi160_sec_access_ctrl( - const int port, - const uint16_t i2c_spi_addr_flags, - const int enable) -{ - int mag_if_ctrl; - bmi_read8(port, i2c_spi_addr_flags, - BMI160_MAG_IF_1, &mag_if_ctrl); - if (enable) { - mag_if_ctrl |= BMI160_MAG_MANUAL_EN; - mag_if_ctrl &= ~BMI160_MAG_READ_BURST_MASK; - mag_if_ctrl |= BMI160_MAG_READ_BURST_1; - } else { - mag_if_ctrl &= ~BMI160_MAG_MANUAL_EN; - mag_if_ctrl &= ~BMI160_MAG_READ_BURST_MASK; - mag_if_ctrl |= BMI160_MAG_READ_BURST_8; - } - return bmi_write8(port, i2c_spi_addr_flags, - BMI160_MAG_IF_1, mag_if_ctrl); -} - -/** - * Read register from compass. - * Assuming we are in manual access mode, read compass i2c register. - */ -int bmi160_sec_raw_read8(const int port, - const uint16_t i2c_spi_addr_flags, - const uint8_t reg, int *data_ptr) -{ - /* Only read 1 bytes */ - bmi_write8(port, i2c_spi_addr_flags, - BMI160_MAG_I2C_READ_ADDR, reg); - return bmi_read8(port, i2c_spi_addr_flags, - BMI160_MAG_I2C_READ_DATA, data_ptr); -} - -/** - * Write register from compass. - * Assuming we are in manual access mode, write to compass i2c register. - */ -int bmi160_sec_raw_write8(const int port, - const uint16_t i2c_spi_addr_flags, - const uint8_t reg, int data) -{ - bmi_write8(port, i2c_spi_addr_flags, - BMI160_MAG_I2C_WRITE_DATA, data); - return bmi_write8(port, i2c_spi_addr_flags, - BMI160_MAG_I2C_WRITE_ADDR, reg); -} - -static int set_data_rate(const struct motion_sensor_t *s, - int rate, - int rnd) -{ - int ret, normalized_rate; - uint8_t reg_val; - struct accelgyro_saved_data_t *data = BMI_GET_SAVED_DATA(s); - - if (rate == 0) { - /* FIFO stop collecting events */ - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) - bmi_enable_fifo(s, 0); - - /* go to suspend mode */ - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_CMD_REG, - BMI160_CMD_MODE_SUSPEND(s->type)); - msleep(3); - data->odr = 0; - if (IS_ENABLED(CONFIG_MAG_BMI_BMM150) && - (s->type == MOTIONSENSE_TYPE_MAG)) { - struct mag_cal_t *moc = BMM150_CAL(s); - - moc->batch_size = 0; - } - - return ret; - } else if (data->odr == 0) { - /* back from suspend mode. */ - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_CMD_REG, - BMI160_CMD_MODE_NORMAL(s->type)); - msleep(wakeup_time[s->type]); - } - - ret = bmi_get_normalized_rate(s, rate, rnd, &normalized_rate, ®_val); - if (ret) - return ret; - - /* - * Lock accel resource to prevent another task from attempting - * to write accel parameters until we are done. - */ - mutex_lock(s->mutex); - - ret = bmi_set_reg8(s, BMI_CONF_REG(s->type), - reg_val, BMI_ODR_MASK); - if (ret != EC_SUCCESS) - goto accel_cleanup; - - /* Now that we have set the odr, update the driver's value. */ - data->odr = normalized_rate; - - if (IS_ENABLED(CONFIG_MAG_BMI_BMM150) && - (s->type == MOTIONSENSE_TYPE_MAG)) { - struct mag_cal_t *moc = BMM150_CAL(s); - - /* Reset the calibration */ - init_mag_cal(moc); - /* - * We need at least MIN_BATCH_SIZE amd we must have collected - * for at least MIN_BATCH_WINDOW_US. - * Given odr is in mHz, multiply by 1000x - */ - moc->batch_size = MAX( - MAG_CAL_MIN_BATCH_SIZE, - (data->odr * 1000) / (MAG_CAL_MIN_BATCH_WINDOW_US)); - CPRINTS("Batch size: %d", moc->batch_size); - } - - /* - * FIFO start collecting events. - * They will be discarded if AP does not want them. - */ - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) - bmi_enable_fifo(s, 1); - -accel_cleanup: - mutex_unlock(s->mutex); - return ret; -} - -static int set_offset(const struct motion_sensor_t *s, - const int16_t *offset, - int16_t temp) -{ - int ret, val98; - intv3_t v = { offset[X], offset[Y], offset[Z] }; - - rotate_inv(v, *s->rot_standard_ref, v); - - ret = bmi_read8(s->port, s->i2c_spi_addr_flags, - BMI160_OFFSET_EN_GYR98, &val98); - if (ret != 0) - return ret; - - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - ret = bmi_set_accel_offset(s, v); - if (ret != EC_SUCCESS) - return ret; - - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_OFFSET_EN_GYR98, - val98 | BMI160_OFFSET_ACC_EN); - break; - case MOTIONSENSE_TYPE_GYRO: - ret = bmi_set_gyro_offset(s, v, &val98); - if (ret != EC_SUCCESS) - return ret; - - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_OFFSET_EN_GYR98, - val98 | BMI160_OFFSET_GYRO_EN); - break; -#ifdef CONFIG_MAG_BMI_BMM150 - case MOTIONSENSE_TYPE_MAG: - ret = bmm150_set_offset(s, v); - break; -#endif /* defined(CONFIG_MAG_BMI_BMM150) */ - default: - ret = EC_RES_INVALID_PARAM; - } - return ret; -} - -static int perform_calib(struct motion_sensor_t *s, int enable) -{ - int ret, val, en_flag, status, rate, range = s->current_range; - timestamp_t deadline, timeout; - - if (!enable) - return EC_SUCCESS; - - rate = bmi_get_data_rate(s); - /* - * Temporary set frequency to 100Hz to get enough data in a short - * period of time. - */ - ret = set_data_rate(s, 100000, 0); - if (ret != EC_SUCCESS) - goto end_perform_calib; - - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - /* We assume the device is laying flat for calibration */ - if (s->rot_standard_ref == NULL || - (*s->rot_standard_ref)[2][2] > INT_TO_FP(0)) - val = BMI160_FOC_ACC_PLUS_1G; - else - val = BMI160_FOC_ACC_MINUS_1G; - val = (BMI160_FOC_ACC_0G << BMI160_FOC_ACC_X_OFFSET) | - (BMI160_FOC_ACC_0G << BMI160_FOC_ACC_Y_OFFSET) | - (val << BMI160_FOC_ACC_Z_OFFSET); - en_flag = BMI160_OFFSET_ACC_EN; - /* - * Temporary set range to minimum to run calibration with - * full sensitivity - */ - bmi_set_range(s, 2, 0); - /* Timeout for accelerometer calibration */ - timeout.val = 400 * MSEC; - break; - case MOTIONSENSE_TYPE_GYRO: - val = BMI160_FOC_GYRO_EN; - en_flag = BMI160_OFFSET_GYRO_EN; - /* - * Temporary set range to minimum to run calibration with - * full sensitivity - */ - bmi_set_range(s, 125, 0); - /* Timeout for gyroscope calibration */ - timeout.val = 800 * MSEC; - break; - default: - /* Not supported on Magnetometer */ - ret = EC_RES_INVALID_PARAM; - goto end_perform_calib; - } - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_FOC_CONF, val); - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_CMD_REG, BMI160_CMD_START_FOC); - deadline.val = get_time().val + timeout.val; - do { - if (timestamp_expired(deadline, NULL)) { - ret = EC_RES_TIMEOUT; - goto end_perform_calib; - } - msleep(50); - ret = bmi_read8(s->port, s->i2c_spi_addr_flags, - BMI160_STATUS, &status); - if (ret != EC_SUCCESS) - goto end_perform_calib; - } while ((status & BMI160_FOC_RDY) == 0); - - /* Calibration is successful, and loaded, use the result */ - ret = bmi_enable_reg8(s, BMI160_OFFSET_EN_GYR98, en_flag, 1); -end_perform_calib: - bmi_set_range(s, range, 0); - set_data_rate(s, rate, 0); - return ret; -} - -/* - * Manage gesture recognition. - * Defined even if host interface is not defined, to enable double tap even - * when the host does not deal with gesture. - */ -#ifdef CONFIG_GESTURE_HOST_DETECTION -static int manage_activity(const struct motion_sensor_t *s, - enum motionsensor_activity activity, - int enable, - const struct ec_motion_sense_activity *param) -{ - int ret; - struct bmi_drv_data_t *data = BMI_GET_DATA(s); - - switch (activity) { -#ifdef CONFIG_GESTURE_SIGMO - case MOTIONSENSE_ACTIVITY_SIG_MOTION: { - if (enable) { - /* We should use parameters from caller */ - bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_INT_MOTION_3, - BMI160_MOTION_PROOF_TIME( - CONFIG_GESTURE_SIGMO_PROOF_MS) << - BMI160_MOTION_PROOF_OFF | - BMI160_MOTION_SKIP_TIME( - CONFIG_GESTURE_SIGMO_SKIP_MS) << - BMI160_MOTION_SKIP_OFF | - BMI160_MOTION_SIG_MOT_SEL); - bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_INT_MOTION_1, - BMI160_MOTION_TH(s, - CONFIG_GESTURE_SIGMO_THRES_MG)); - } - ret = bmi_enable_reg8(s, BMI160_INT_EN_0, - BMI160_INT_ANYMO_X_EN | - BMI160_INT_ANYMO_Y_EN | - BMI160_INT_ANYMO_Z_EN, - enable); - if (ret) - ret = EC_RES_UNAVAILABLE; - break; - } -#endif -#ifdef CONFIG_GESTURE_SENSOR_DOUBLE_TAP - case MOTIONSENSE_ACTIVITY_DOUBLE_TAP: { - /* Set double tap interrupt */ - ret = bmi_enable_reg8(s, BMI160_INT_EN_0, - BMI160_INT_D_TAP_EN, - enable); - if (ret) - ret = EC_RES_UNAVAILABLE; - break; - } -#endif - default: - ret = EC_RES_INVALID_PARAM; - } - if (ret == EC_RES_SUCCESS) { - if (enable) { - data->enabled_activities |= 1 << activity; - data->disabled_activities &= ~BIT(activity); - } else { - data->enabled_activities &= ~BIT(activity); - data->disabled_activities |= 1 << activity; - } - } - return ret; -} -#endif - -static __maybe_unused int config_interrupt(const struct motion_sensor_t *s) -{ - int ret, tmp; - - if (s->type != MOTIONSENSE_TYPE_ACCEL) - return EC_SUCCESS; - - mutex_lock(s->mutex); - bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_CMD_REG, BMI160_CMD_FIFO_FLUSH); - bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_CMD_REG, BMI160_CMD_INT_RESET); - - if (IS_ENABLED(CONFIG_GESTURE_SENSOR_DOUBLE_TAP)) { - bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_INT_TAP_0, - BMI160_TAP_DUR(s, CONFIG_GESTURE_TAP_MAX_INTERSTICE_T)); - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_INT_TAP_1, - BMI160_TAP_TH(s, CONFIG_GESTURE_TAP_THRES_MG)); - } - /* only use orientation sensor on the lid sensor */ - if (IS_ENABLED(CONFIG_BMI_ORIENTATION_SENSOR) && - (s->location == MOTIONSENSE_LOC_LID)) { - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_INT_ORIENT_0, - BMI160_INT_ORIENT_0_INIT_VAL); - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_INT_ORIENT_1, - BMI160_INT_ORIENT_1_INIT_VAL); - } - - if (IS_ENABLED(CONFIG_ACCELGYRO_BMI160_INT2_OUTPUT)) { - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_INT_LATCH, BMI160_LATCH_5MS); - } else { - /* Also, configure int2 as an external input. */ - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_INT_LATCH, - BMI160_INT2_INPUT_EN | BMI160_LATCH_5MS); - } - - /* configure int1 as an interrupt */ - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_INT_OUT_CTRL, - BMI160_INT_CTRL(1, OUTPUT_EN)); - - /* Map activity interrupt to int 1 */ - tmp = 0; - if (IS_ENABLED(CONFIG_GESTURE_SIGMO)) { - tmp |= BMI160_INT_ANYMOTION; - } else if (IS_ENABLED(CONFIG_GESTURE_SENSOR_DOUBLE_TAP)) { - tmp |= BMI160_INT_D_TAP; - } else if (IS_ENABLED(CONFIG_BMI_ORIENTATION_SENSOR) && - (s->location == MOTIONSENSE_LOC_LID)) { - /* enable orientation interrupt for lid sensor only */ - tmp |= BMI160_INT_ORIENT; - } - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_INT_MAP_REG(1), tmp); - - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) { - /* map fifo water mark to int 1 */ - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_INT_FIFO_MAP, - BMI160_INT_MAP(1, FWM) | - BMI160_INT_MAP(1, FFULL)); - - /* - * Configure fifo watermark to int whenever there's any data in - * there - */ - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_FIFO_CONFIG_0, 1); - if (IS_ENABLED(CONFIG_ACCELGYRO_BMI160_INT2_OUTPUT)) - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_FIFO_CONFIG_1, - BMI160_FIFO_HEADER_EN); - else - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_FIFO_CONFIG_1, - BMI160_FIFO_TAG_INT2_EN | - BMI160_FIFO_HEADER_EN); - - /* Set fifo*/ - bmi_enable_reg8(s, BMI160_INT_EN_1, - BMI160_INT_FWM_EN | BMI160_INT_FFUL_EN, 1); - } - mutex_unlock(s->mutex); - return ret; -} - -#ifdef CONFIG_ACCEL_INTERRUPTS -#ifdef CONFIG_BMI_ORIENTATION_SENSOR -static void irq_set_orientation(struct motion_sensor_t *s, - int interrupt) -{ - int shifted_masked_orientation = - (interrupt >> 24) & BMI160_ORIENT_XY_MASK; - if (BMI_GET_DATA(s)->raw_orientation != shifted_masked_orientation) { - enum motionsensor_orientation orientation = - MOTIONSENSE_ORIENTATION_UNKNOWN; - - BMI_GET_DATA(s)->raw_orientation = - shifted_masked_orientation; - - switch (shifted_masked_orientation) { - case BMI160_ORIENT_PORTRAIT: - orientation = MOTIONSENSE_ORIENTATION_PORTRAIT; - break; - case BMI160_ORIENT_PORTRAIT_INVERT: - orientation = - MOTIONSENSE_ORIENTATION_UPSIDE_DOWN_PORTRAIT; - break; - case BMI160_ORIENT_LANDSCAPE: - orientation = MOTIONSENSE_ORIENTATION_LANDSCAPE; - break; - case BMI160_ORIENT_LANDSCAPE_INVERT: - orientation = - MOTIONSENSE_ORIENTATION_UPSIDE_DOWN_LANDSCAPE; - break; - default: - break; - } - orientation = motion_orientation_remap(s, orientation); - *motion_orientation_ptr(s) = orientation; - } -} -#endif /* CONFIG_BMI_ORIENTATION_SENSOR */ - -/** - * bmi160_interrupt - called when the sensor activates the interrupt line. - * - * This is a "top half" interrupt handler, it just asks motion sense ask - * to schedule the "bottom half", ->irq_handler(). - */ -void bmi160_interrupt(enum gpio_signal signal) -{ - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) - last_interrupt_timestamp = __hw_clock_source_read(); - - task_set_event(TASK_ID_MOTIONSENSE, CONFIG_ACCELGYRO_BMI160_INT_EVENT); -} - -/** - * irq_handler - bottom half of the interrupt stack. - * Ran from the motion_sense task, finds the events that raised the interrupt. - * - * For now, we just print out. We should set a bitmask motion sense code will - * act upon. - */ -static int irq_handler(struct motion_sensor_t *s, - uint32_t *event) -{ - uint32_t interrupt; - int8_t has_read_fifo = 0; - int rv; - - if ((s->type != MOTIONSENSE_TYPE_ACCEL) || - (!(*event & CONFIG_ACCELGYRO_BMI160_INT_EVENT))) - return EC_ERROR_NOT_HANDLED; - - do { - rv = bmi_read16(s->port, s->i2c_spi_addr_flags, - BMI160_INT_STATUS_0, &interrupt); - /* - * Bail out of this loop there was an error reading the register - */ - if (rv) - return rv; - - if (IS_ENABLED(CONFIG_GESTURE_SENSOR_DOUBLE_TAP) && - (interrupt & BMI160_D_TAP_INT)) - *event |= TASK_EVENT_MOTION_ACTIVITY_INTERRUPT( - MOTIONSENSE_ACTIVITY_DOUBLE_TAP); - if (IS_ENABLED(CONFIG_GESTURE_SIGMO) && - (interrupt & BMI160_SIGMOT_INT)) - *event |= TASK_EVENT_MOTION_ACTIVITY_INTERRUPT( - MOTIONSENSE_ACTIVITY_SIG_MOTION); - if (IS_ENABLED(CONFIG_ACCEL_FIFO) && - (interrupt & (BMI160_FWM_INT | BMI160_FFULL_INT))) { - bmi_load_fifo(s, last_interrupt_timestamp); - has_read_fifo = 1; - } - if (IS_ENABLED(CONFIG_BMI_ORIENTATION_SENSOR)) - irq_set_orientation(s, interrupt); - } while (interrupt != 0); - - if (IS_ENABLED(CONFIG_ACCEL_FIFO) && has_read_fifo) - motion_sense_fifo_commit_data(); - - return EC_SUCCESS; -} -#endif /* CONFIG_ACCEL_INTERRUPTS */ - -static int init(struct motion_sensor_t *s) -{ - int ret = 0, tmp, i; - struct accelgyro_saved_data_t *saved_data = BMI_GET_SAVED_DATA(s); - - ret = bmi_read8(s->port, s->i2c_spi_addr_flags, - BMI160_CHIP_ID, &tmp); - if (ret) - return EC_ERROR_UNKNOWN; - - if (tmp != BMI160_CHIP_ID_MAJOR && tmp != BMI168_CHIP_ID_MAJOR) { - /* The device may be lock on paging mode. Try to unlock it. */ - bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_CMD_REG, BMI160_CMD_EXT_MODE_EN_B0); - bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_CMD_REG, BMI160_CMD_EXT_MODE_EN_B1); - bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_CMD_REG, BMI160_CMD_EXT_MODE_EN_B2); - bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_CMD_EXT_MODE_ADDR, BMI160_CMD_PAGING_EN); - bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_CMD_EXT_MODE_ADDR, 0); - return EC_ERROR_ACCESS_DENIED; - } - - - if (s->type == MOTIONSENSE_TYPE_ACCEL) { - struct bmi_drv_data_t *data = BMI_GET_DATA(s); - - /* Reset the chip to be in a good state */ - bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_CMD_REG, BMI160_CMD_SOFT_RESET); - msleep(1); - data->flags &= ~(BMI_FLAG_SEC_I2C_ENABLED | - (BMI_FIFO_ALL_MASK << - BMI_FIFO_FLAG_OFFSET)); - if (IS_ENABLED(CONFIG_GESTURE_HOST_DETECTION)) { - data->enabled_activities = 0; - data->disabled_activities = 0; - if (IS_ENABLED(CONFIG_GESTURE_SIGMO)) - data->disabled_activities |= - BIT(MOTIONSENSE_ACTIVITY_SIG_MOTION); - if (IS_ENABLED(CONFIG_GESTURE_SENSOR_DOUBLE_TAP)) - data->disabled_activities |= - BIT(MOTIONSENSE_ACTIVITY_DOUBLE_TAP); - } - /* To avoid gyro wakeup */ - bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_PMU_TRIGGER, 0); - } - -#ifdef CONFIG_BMI_SEC_I2C - if (s->type == MOTIONSENSE_TYPE_MAG) { - struct bmi_drv_data_t *data = BMI_GET_DATA(s); - - /* - * To be able to configure the real magnetometer, we must set - * the BMI160 magnetometer part (a pass through) in normal mode. - */ - bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_CMD_REG, BMI160_CMD_MODE_NORMAL(s->type)); - msleep(wakeup_time[s->type]); - - if ((data->flags & BMI_FLAG_SEC_I2C_ENABLED) == 0) { - int ext_page_reg; - /* Enable secondary interface */ - /* - * This is not part of the normal configuration but from - * code on Bosh github repo: - * https://github.com/BoschSensortec/BMI160_driver - * - * Magic command sequences - */ - bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_CMD_REG, BMI160_CMD_EXT_MODE_EN_B0); - bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_CMD_REG, BMI160_CMD_EXT_MODE_EN_B1); - bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_CMD_REG, BMI160_CMD_EXT_MODE_EN_B2); - - /* - * Change the register page to target mode, to change - * the internal pull ups of the secondary interface. - */ - bmi_enable_reg8(s, BMI160_CMD_EXT_MODE_ADDR, - BMI160_CMD_TARGET_PAGE, 1); - bmi_enable_reg8(s, BMI160_CMD_EXT_MODE_ADDR, - BMI160_CMD_PAGING_EN, 1); - bmi_enable_reg8(s, BMI160_COM_C_TRIM_ADDR, - BMI160_COM_C_TRIM, 1); - bmi_enable_reg8(s, BMI160_CMD_EXT_MODE_ADDR, - BMI160_CMD_TARGET_PAGE, 0); - bmi_read8(s->port, s->i2c_spi_addr_flags, - BMI160_CMD_EXT_MODE_ADDR, &ext_page_reg); - - /* Set the i2c address of the compass */ - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_MAG_IF_0, - I2C_STRIP_FLAGS( - CONFIG_ACCELGYRO_SEC_ADDR_FLAGS) - << 1); - - /* Enable the secondary interface as I2C */ - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_IF_CONF, - BMI160_IF_MODE_AUTO_I2C << - BMI160_IF_MODE_OFF); - data->flags |= BMI_FLAG_SEC_I2C_ENABLED; - } - - - bmi160_sec_access_ctrl(s->port, s->i2c_spi_addr_flags, 1); - - ret = bmm150_init(s); - if (ret) - /* Leave the compass open for tinkering. */ - return ret; - - /* Leave the address for reading the data */ - bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI160_MAG_I2C_READ_ADDR, BMM150_BASE_DATA); - /* - * Put back the secondary interface in normal mode. - * BMI160 will poll based on the configure ODR. - */ - bmi160_sec_access_ctrl(s->port, s->i2c_spi_addr_flags, 0); - - /* - * Clean interrupt event that may have occurred while the - * BMI160 was in management mode. - */ - task_set_event(TASK_ID_MOTIONSENSE, - CONFIG_ACCELGYRO_BMI160_INT_EVENT); - } -#endif - - for (i = X; i <= Z; i++) - saved_data->scale[i] = MOTION_SENSE_DEFAULT_SCALE; - /* - * The sensor is in Suspend mode at init, - * so set data rate to 0. - */ - saved_data->odr = 0; - - if (IS_ENABLED(CONFIG_ACCEL_INTERRUPTS) && - (s->type == MOTIONSENSE_TYPE_ACCEL)) - ret = config_interrupt(s); - - return sensor_init_done(s); -} - -const struct accelgyro_drv bmi160_drv = { - .init = init, - .read = bmi_read, - .set_range = bmi_set_range, - .get_resolution = bmi_get_resolution, - .set_data_rate = set_data_rate, - .get_data_rate = bmi_get_data_rate, - .set_offset = set_offset, - .get_scale = bmi_get_scale, - .set_scale = bmi_set_scale, - .get_offset = bmi_get_offset, - .perform_calib = perform_calib, - .read_temp = bmi_read_temp, -#ifdef CONFIG_ACCEL_INTERRUPTS - .irq_handler = irq_handler, -#endif -#ifdef CONFIG_GESTURE_HOST_DETECTION - .manage_activity = manage_activity, - .list_activities = bmi_list_activities, -#endif -#ifdef CONFIG_BODY_DETECTION - .get_rms_noise = bmi_get_rms_noise, -#endif -}; - -#ifdef CONFIG_CMD_I2C_STRESS_TEST_ACCEL -struct i2c_stress_test_dev bmi160_i2c_stress_test_dev = { - .reg_info = { - .read_reg = BMI160_CHIP_ID, - .read_val = BMI160_CHIP_ID_MAJOR, - .write_reg = BMI160_PMU_TRIGGER, - }, - .i2c_read = &bmi_read8, - .i2c_write = &bmi_write8, -}; -#endif /* CONFIG_CMD_I2C_STRESS_TEST_ACCEL */ - -/* - * TODO(chingkang): Replace bmi160_get_sensor_temp in some board config to - * bmi_get_sensor_temp. Then, remove this definition. - */ -int bmi160_get_sensor_temp(int idx, int *temp_ptr) -{ - return bmi_get_sensor_temp(idx, temp_ptr); -} diff --git a/driver/accelgyro_bmi260.c b/driver/accelgyro_bmi260.c deleted file mode 100644 index 9fb669e122..0000000000 --- a/driver/accelgyro_bmi260.c +++ /dev/null @@ -1,601 +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. - */ - -/** - * BMI260 accelerometer and gyro module for Chrome EC - * 3D digital accelerometer & 3D digital gyroscope - */ - -#include "accelgyro.h" -#include "console.h" -#include "accelgyro_bmi_common.h" -#include "accelgyro_bmi260.h" -#include "bmi260/accelgyro_bmi260_config_tbin.h" -#include "hwtimer.h" -#include "i2c.h" -#include "init_rom.h" -#include "math_util.h" -#include "motion_sense_fifo.h" -#include "spi.h" -#include "task.h" -#include "timer.h" -#include "util.h" -#include "watchdog.h" - -#define CPUTS(outstr) cputs(CC_ACCEL, outstr) -#define CPRINTF(format, args...) cprintf(CC_ACCEL, format, ## args) -#define CPRINTS(format, args...) cprints(CC_ACCEL, format, ## args) - -#if defined(CONFIG_ZEPHYR) && defined(CONFIG_ACCEL_INTERRUPTS) -/* - * Get the mostion sensor ID of the BMI260 sensor that - * generates the interrupt. - * The interrupt is converted to the event and transferred to motion - * sense task that actually handles the interrupt. - * - * Here, we use alias to get the motion sensor ID - * - * e.g) base_accel is the label of a child node in /motionsense-sensors - * aliases { - * bmi260-int = &base_accel; - * }; - */ -#if DT_NODE_EXISTS(DT_ALIAS(bmi260_int)) -#define CONFIG_ACCELGYRO_BMI260_INT_EVENT \ - TASK_EVENT_MOTION_SENSOR_INTERRUPT(SENSOR_ID(DT_ALIAS(bmi260_int))) -#endif -#endif - -STATIC_IF(CONFIG_ACCEL_FIFO) volatile uint32_t last_interrupt_timestamp; - -/* - * The gyro start-up time is 45ms in normal mode - * 2ms in fast start-up mode - */ -static int wakeup_time[] = { - [MOTIONSENSE_TYPE_ACCEL] = 2, - [MOTIONSENSE_TYPE_GYRO] = 45, - [MOTIONSENSE_TYPE_MAG] = 1 -}; - -static int enable_sensor(const struct motion_sensor_t *s, int enable) -{ - int ret; - - ret = bmi_enable_reg8(s, BMI260_PWR_CTRL, - BMI260_PWR_EN(s->type), - enable); - if (ret) - return ret; - - if (s->type == MOTIONSENSE_TYPE_GYRO) { - /* switch to performance mode */ - ret = bmi_enable_reg8(s, BMI_CONF_REG(s->type), - BMI260_FILTER_PERF | - BMI260_GYR_NOISE_PERF, - enable); - } else { - ret = bmi_enable_reg8(s, BMI_CONF_REG(s->type), - BMI260_FILTER_PERF, - enable); - } - return ret; - -} - -static int set_data_rate(const struct motion_sensor_t *s, - int rate, - int rnd) -{ - int ret, normalized_rate; - uint8_t reg_val; - struct accelgyro_saved_data_t *data = BMI_GET_SAVED_DATA(s); - - if (rate == 0) { - /* FIFO stop collecting events */ - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) - bmi_enable_fifo(s, 0); - /* disable sensor */ - ret = enable_sensor(s, 0); - msleep(3); - data->odr = 0; - return ret; - } else if (data->odr == 0) { - /* enable sensor */ - ret = enable_sensor(s, 1); - if (ret) - return ret; - /* Wait for accel/gyro to wake up */ - msleep(wakeup_time[s->type]); - } - - ret = bmi_get_normalized_rate(s, rate, rnd, - &normalized_rate, ®_val); - if (ret) - return ret; - - /* - * Lock accel resource to prevent another task from attempting - * to write accel parameters until we are done. - */ - mutex_lock(s->mutex); - - ret = bmi_set_reg8(s, BMI_CONF_REG(s->type), - reg_val, BMI_ODR_MASK); - if (ret != EC_SUCCESS) - goto accel_cleanup; - - /* Now that we have set the odr, update the driver's value. */ - data->odr = normalized_rate; - - /* - * FIFO start collecting events. - * They will be discarded if AP does not want them. - */ - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) - bmi_enable_fifo(s, 1); -accel_cleanup: - mutex_unlock(s->mutex); - return ret; -} - -static int set_offset(const struct motion_sensor_t *s, - const int16_t *offset, - int16_t temp) -{ - int ret, val98, val_nv_conf; - intv3_t v = { offset[X], offset[Y], offset[Z] }; - - rotate_inv(v, *s->rot_standard_ref, v); - - ret = bmi_read8(s->port, s->i2c_spi_addr_flags, - BMI260_OFFSET_EN_GYR98, &val98); - if (ret) - return ret; - ret = bmi_read8(s->port, s->i2c_spi_addr_flags, - BMI260_NV_CONF, &val_nv_conf); - if (ret) - return ret; - - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - ret = bmi_set_accel_offset(s, v); - if (ret != EC_SUCCESS) - return ret; - - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI260_NV_CONF, - val_nv_conf | BMI260_ACC_OFFSET_EN); - break; - case MOTIONSENSE_TYPE_GYRO: - ret = bmi_set_gyro_offset(s, v, &val98); - if (ret != EC_SUCCESS) - return ret; - - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI260_OFFSET_EN_GYR98, - val98 | BMI260_OFFSET_GYRO_EN); - break; - default: - ret = EC_RES_INVALID_PARAM; - } - return ret; -} - -static int wait_and_read_data(const struct motion_sensor_t *s, - intv3_t v, int try_cnt, int msec) -{ - uint8_t data[6]; - int ret, status = 0; - - /* Check if data is ready */ - while (try_cnt && !(status & BMI260_DRDY_ACC)) { - msleep(msec); - ret = bmi_read8(s->port, s->i2c_spi_addr_flags, - BMI260_STATUS, &status); - if (ret) - return ret; - try_cnt -= 1; - } - if (!(status & BMI260_DRDY_ACC)) - return EC_ERROR_TIMEOUT; - /* Read 6 bytes starting at xyz_reg */ - ret = bmi_read_n(s->port, s->i2c_spi_addr_flags, - bmi_get_xyz_reg(s), data, 6); - bmi_normalize(s, v, data); - return ret; -} - -static int calibrate_offset(const struct motion_sensor_t *s, - int range, intv3_t target, int16_t *offset) -{ - int ret = EC_ERROR_UNKNOWN; - int i, n_sample = 32; - int data_diff[3] = {0}; - - /* Manually offset compensation */ - for (i = 0; i < n_sample; ++i) { - intv3_t v; - /* Wait data for at most 3 * 10 msec */ - ret = wait_and_read_data(s, v, 3, 10); - if (ret) - return ret; - data_diff[X] += v[X] - target[X]; - data_diff[Y] += v[Y] - target[Y]; - data_diff[Z] += v[Z] - target[Z]; - } - - /* The data LSB: 1000 * range / 32768 (mdps | mg)*/ - for (i = X; i <= Z; ++i) - offset[i] -= ((int64_t)(data_diff[i] / n_sample) * - 1000 * range) >> 15; - return ret; -} - -static int perform_calib(struct motion_sensor_t *s, int enable) -{ - int ret, rate; - int16_t temp; - int16_t offset[3]; - intv3_t target = {0, 0, 0}; - /* Get sensor range for calibration*/ - int range = s->current_range; - - if (!enable) - return EC_SUCCESS; - rate = bmi_get_data_rate(s); - ret = set_data_rate(s, 100000, 0); - if (ret) - return ret; - - ret = bmi_get_offset(s, offset, &temp); - if (ret) - goto end_perform_calib; - - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - target[Z] = BMI260_ACC_DATA_PLUS_1G(range); - break; - case MOTIONSENSE_TYPE_GYRO: - break; - default: - /* Not supported on Magnetometer */ - ret = EC_RES_INVALID_PARAM; - goto end_perform_calib; - } - - /* Get the calibrated offset */ - ret = calibrate_offset(s, range, target, offset); - if (ret) - goto end_perform_calib; - - ret = set_offset(s, offset, temp); - if (ret) - goto end_perform_calib; - -end_perform_calib: - if (ret == EC_ERROR_TIMEOUT) - CPRINTS("%s timeout", __func__); - set_data_rate(s, rate, 0); - return ret; -} - -#ifdef CONFIG_ACCEL_INTERRUPTS - -/** - * bmi260_interrupt - called when the sensor activates the interrupt line. - * - * This is a "top half" interrupt handler, it just asks motion sense ask - * to schedule the "bottom half", ->irq_handler(). - */ -void bmi260_interrupt(enum gpio_signal signal) -{ - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) - last_interrupt_timestamp = __hw_clock_source_read(); - - task_set_event(TASK_ID_MOTIONSENSE, CONFIG_ACCELGYRO_BMI260_INT_EVENT); -} - -static int config_interrupt(const struct motion_sensor_t *s) -{ - int ret; - - if (s->type != MOTIONSENSE_TYPE_ACCEL) - return EC_SUCCESS; - - mutex_lock(s->mutex); - bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI260_CMD_REG, BMI260_CMD_FIFO_FLUSH); - - /* configure int1 as an interrupt */ - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI260_INT1_IO_CTRL, - BMI260_INT1_OUTPUT_EN); - if (IS_ENABLED(CONFIG_ACCELGYRO_BMI260_INT2_OUTPUT)) - /* TODO(chingkang): Test it if we want int2 as an interrupt */ - /* configure int2 as an interrupt */ - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI260_INT2_IO_CTRL, - BMI260_INT2_OUTPUT_EN); - else - /* configure int2 as an external input. */ - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI260_INT2_IO_CTRL, - BMI260_INT2_INPUT_EN); - - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) { - /* map fifo water mark to int 1 */ - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI260_INT_MAP_DATA, - BMI260_INT_MAP_DATA_REG(1, FWM) | - BMI260_INT_MAP_DATA_REG(1, FFULL)); - - /* - * Configure fifo watermark to int whenever there's any data in - * there - */ - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI260_FIFO_WTM_0, 1); - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI260_FIFO_WTM_1, 0); - if (IS_ENABLED(CONFIG_ACCELGYRO_BMI260_INT2_OUTPUT)) - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI260_FIFO_CONFIG_1, - BMI260_FIFO_HEADER_EN); - else - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI260_FIFO_CONFIG_1, - (BMI260_FIFO_TAG_INT_LEVEL << - BMI260_FIFO_TAG_INT2_EN_OFFSET) | - BMI260_FIFO_HEADER_EN); - /* disable FIFO sensortime frame */ - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI260_FIFO_CONFIG_0, 0); - } - mutex_unlock(s->mutex); - return ret; -} - -/** - * irq_handler - bottom half of the interrupt stack. - * Ran from the motion_sense task, finds the events that raised the interrupt. - * - * For now, we just print out. We should set a bitmask motion sense code will - * act upon. - */ -static int irq_handler(struct motion_sensor_t *s, uint32_t *event) -{ - /* use uint16_t interrupt can cause error. */ - uint32_t interrupt = 0; - int8_t has_read_fifo = 0; - int rv; - - if ((s->type != MOTIONSENSE_TYPE_ACCEL) || - (!(*event & CONFIG_ACCELGYRO_BMI260_INT_EVENT))) - return EC_ERROR_NOT_HANDLED; - - do { - rv = bmi_read16(s->port, s->i2c_spi_addr_flags, - BMI260_INT_STATUS_0, &interrupt); - /* - * Bail out of this loop there was an error reading the register - */ - if (rv) - return rv; - - if (IS_ENABLED(CONFIG_ACCEL_FIFO) && - interrupt & (BMI260_FWM_INT | BMI260_FFULL_INT)) { - bmi_load_fifo(s, last_interrupt_timestamp); - has_read_fifo = 1; - } - } while (interrupt != 0); - - if (IS_ENABLED(CONFIG_ACCEL_FIFO) && has_read_fifo) - motion_sense_fifo_commit_data(); - - return EC_SUCCESS; -} -#endif /* CONFIG_ACCEL_INTERRUPTS */ - -/* - * If the .init_rom section is not memory mapped, we need a static - * buffer in RAM to access the BMI configuration data. - */ -#ifdef CONFIG_CHIP_INIT_ROM_REGION -#define BMI_RAM_BUFFER_SIZE 256 -static uint8_t bmi_ram_buffer[BMI_RAM_BUFFER_SIZE]; -#else -#define BMI_RAM_BUFFER_SIZE 0 -static uint8_t *bmi_ram_buffer; -#endif - -static int bmi_config_load(const struct motion_sensor_t *s) -{ - int ret = EC_SUCCESS; - uint16_t i; - const uint8_t *bmi_config = NULL; - /* - * Due to i2c transaction timeout limit, - * burst_write_len should not be above 2048 to prevent timeout. - */ - int burst_write_len = 2048; - - /* - * The BMI config data may be linked into .rodata or the .init_rom - * section. Get the actual memory mapped address. - */ - bmi_config = init_rom_map(g_bmi260_config_tbin, - g_bmi260_config_tbin_len); - - /* - * init_rom_map() only returns NULL when the CONFIG_CHIP_INIT_ROM_REGION - * option is enabled and flash memory is not memory mapped. In this - * case copy the BMI config data through a RAM buffer and limit the - * I2C burst to the size of the RAM buffer. - */ - if (!bmi_config) - burst_write_len = MIN(BMI_RAM_BUFFER_SIZE, burst_write_len); - - /* We have to write the config even bytes of data every time */ - ASSERT(((burst_write_len & 1) == 0) && (burst_write_len != 0)); - - for (i = 0; i < g_bmi260_config_tbin_len; i += burst_write_len) { - uint8_t addr[2]; - const int len = MIN(burst_write_len, - g_bmi260_config_tbin_len - i); - - addr[0] = (i / 2) & 0xF; - addr[1] = (i / 2) >> 4; - ret = bmi_write_n(s->port, s->i2c_spi_addr_flags, - BMI260_INIT_ADDR_0, addr, 2); - if (ret) - break; - - if (!bmi_config) { - /* - * init_rom region isn't memory mapped. Copy the - * data through a RAM buffer. - */ - ret = init_rom_copy((int)&g_bmi260_config_tbin[i], len, - bmi_ram_buffer); - if (ret) - break; - - ret = bmi_write_n(s->port, s->i2c_spi_addr_flags, - BMI260_INIT_DATA, - bmi_ram_buffer, len); - } else { - ret = bmi_write_n(s->port, s->i2c_spi_addr_flags, - BMI260_INIT_DATA, - &bmi_config[i], len); - } - - if (ret) - break; - } - - /* - * Unmap the BMI config data, required when init_rom_map() returns - * a non NULL value. - */ - if (bmi_config) - init_rom_unmap(g_bmi260_config_tbin, g_bmi260_config_tbin_len); - - return ret; -} - -static int init_config(const struct motion_sensor_t *s) -{ - int init_status, ret; - uint16_t i; - - /* disable advance power save but remain fifo self wakeup*/ - bmi_write8(s->port, s->i2c_spi_addr_flags, BMI260_PWR_CONF, 2); - msleep(1); - /* prepare for config load */ - bmi_write8(s->port, s->i2c_spi_addr_flags, BMI260_INIT_CTRL, 0); - - /* load config file to INIT_DATA */ - ret = bmi_config_load(s); - - /* finish config load */ - bmi_write8(s->port, s->i2c_spi_addr_flags, BMI260_INIT_CTRL, 1); - /* return error if load config failed */ - if (ret) - return ret; - /* wait INTERNAL_STATUS.message to be 0x1 which take at most 150ms */ - for (i = 0; i < 15; ++i) { - msleep(10); - ret = bmi_read8(s->port, s->i2c_spi_addr_flags, - BMI260_INTERNAL_STATUS, &init_status); - if (ret) - break; - init_status &= BMI260_MESSAGE_MASK; - if (init_status == BMI260_INIT_OK) - break; - } - if (ret || init_status != BMI260_INIT_OK) - return EC_ERROR_INVALID_CONFIG; - return EC_SUCCESS; -} - -static int init(struct motion_sensor_t *s) -{ - int ret = 0, tmp, i; - struct accelgyro_saved_data_t *saved_data = BMI_GET_SAVED_DATA(s); - - ret = bmi_read8(s->port, s->i2c_spi_addr_flags, - BMI260_CHIP_ID, &tmp); - if (ret) - return EC_ERROR_UNKNOWN; - - if (tmp != BMI260_CHIP_ID_MAJOR) - return EC_ERROR_ACCESS_DENIED; - - if (s->type == MOTIONSENSE_TYPE_ACCEL) { - struct bmi_drv_data_t *data = BMI_GET_DATA(s); - - /* Reset the chip to be in a good state */ - bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI260_CMD_REG, BMI260_CMD_SOFT_RESET); - msleep(2); - if (init_config(s)) - return EC_ERROR_INVALID_CONFIG; - - data->flags &= ~(BMI_FLAG_SEC_I2C_ENABLED | - (BMI_FIFO_ALL_MASK << - BMI_FIFO_FLAG_OFFSET)); - } - - for (i = X; i <= Z; i++) - saved_data->scale[i] = MOTION_SENSE_DEFAULT_SCALE; - /* - * The sensor is in Suspend mode at init, - * so set data rate to 0. - */ - saved_data->odr = 0; - - if (IS_ENABLED(CONFIG_ACCEL_INTERRUPTS) && - (s->type == MOTIONSENSE_TYPE_ACCEL)) - ret = config_interrupt(s); - - return sensor_init_done(s); -} - -const struct accelgyro_drv bmi260_drv = { - .init = init, - .read = bmi_read, - .set_range = bmi_set_range, - .get_resolution = bmi_get_resolution, - .set_data_rate = set_data_rate, - .get_data_rate = bmi_get_data_rate, - .set_offset = set_offset, - .get_scale = bmi_get_scale, - .set_scale = bmi_set_scale, - .get_offset = bmi_get_offset, - .perform_calib = perform_calib, - .read_temp = bmi_read_temp, -#ifdef CONFIG_ACCEL_INTERRUPTS - .irq_handler = irq_handler, -#endif -#ifdef CONFIG_GESTURE_HOST_DETECTION - .list_activities = bmi_list_activities, -#endif -#ifdef CONFIG_BODY_DETECTION - .get_rms_noise = bmi_get_rms_noise, -#endif -}; - -#ifdef CONFIG_CMD_I2C_STRESS_TEST_ACCEL -struct i2c_stress_test_dev bmi260_i2c_stress_test_dev = { - .reg_info = { - .read_reg = BMI260_CHIP_ID, - .read_val = BMI260_CHIP_ID_MAJOR, - .write_reg = BMI260_PMU_TRIGGER, - }, - .i2c_read = &bmi_read8, - .i2c_write = &bmi_write8, -}; -#endif /* CONFIG_CMD_I2C_STRESS_TEST_ACCEL */ diff --git a/driver/accelgyro_bmi323.h b/driver/accelgyro_bmi323.h deleted file mode 100644 index 544e9a4527..0000000000 --- a/driver/accelgyro_bmi323.h +++ /dev/null @@ -1,15 +0,0 @@ -/* Copyright 2021 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. - */ - -/* BMI323 gsensor module for Chrome EC */ - -#ifndef __CROS_EC_ACCELGYRO_BMI323_H -#define __CROS_EC_ACCELGYRO_BMI323_H - -#include "accelgyro_bmi3xx.h" - -#define BMI323_CHIP_ID 0x43 - -#endif /* __CROS_EC_ACCELGYRO_BMI323_H */ diff --git a/driver/accelgyro_bmi3xx.c b/driver/accelgyro_bmi3xx.c deleted file mode 100644 index ee9b30a9cf..0000000000 --- a/driver/accelgyro_bmi3xx.c +++ /dev/null @@ -1,1132 +0,0 @@ -/* Copyright 2021 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. - */ - -/** - * BMI3XX accelerometer and gyroscope module for Chrome EC - * 3D digital accelerometer & 3D digital gyroscope - */ - -#include "accelgyro.h" -#include "accelgyro_bmi323.h" -#include "accelgyro_bmi_common.h" -#include "console.h" -#include "hwtimer.h" -#include "i2c.h" -#include "init_rom.h" -#include "math_util.h" -#include "motion_sense_fifo.h" -#include "spi.h" -#include "task.h" -#include "timer.h" -#include "util.h" -#include "watchdog.h" - -#define CPUTS(outstr) cputs(CC_ACCEL, outstr) -#define CPRINTF(format, args...) cprintf(CC_ACCEL, format, ## args) -#define CPRINTS(format, args...) cprints(CC_ACCEL, format, ## args) - -/* Sensor definition */ -STATIC_IF(CONFIG_BMI_ORIENTATION_SENSOR) void irq_set_orientation( - struct motion_sensor_t *s); - -STATIC_IF(CONFIG_ACCEL_FIFO) volatile uint32_t last_interrupt_timestamp; - -static inline int bmi3_read_n(const struct motion_sensor_t *s, const int reg, - uint8_t *data_ptr, const int len) -{ - return bmi_read_n(s->port, s->i2c_spi_addr_flags, reg, data_ptr, len); -} - -static inline int bmi3_write_n(const struct motion_sensor_t *s, const int reg, - uint8_t *data_ptr, const int len) -{ - return bmi_write_n(s->port, s->i2c_spi_addr_flags, reg, data_ptr, len); -} - -#ifdef CONFIG_ACCEL_INTERRUPTS - -#ifdef CONFIG_BMI_ORIENTATION_SENSOR - -static void irq_set_orientation(struct motion_sensor_t *s) -{ - int ret; - uint8_t reg_data[4]; - uint8_t orient_data; - - enum motionsensor_orientation orientation = - MOTIONSENSE_ORIENTATION_UNKNOWN; - - RETURN_ERROR(bmi3_read_n(s, BMI3_FEATURE_EVENT_EXT, reg_data, 4)); - - orient_data = reg_data[2] & BMI3_PORTRAIT_LANDSCAPE_MASK; - - if (BMI_GET_DATA(s)->raw_orientation != orient_data) { - BMI_GET_DATA(s)->raw_orientation = orient_data; - - switch (orient_data) { - case BMI3_ORIENT_PORTRAIT: - orientation = MOTIONSENSE_ORIENTATION_PORTRAIT; - break; - case BMI3_PORTRAIT_INVERT: - orientation = - MOTIONSENSE_ORIENTATION_UPSIDE_DOWN_PORTRAIT; - break; - case BMI3_LANDSCAPE: - orientation = MOTIONSENSE_ORIENTATION_LANDSCAPE; - break; - case BMI3_LANDSCAPE_INVERT: - orientation = - MOTIONSENSE_ORIENTATION_UPSIDE_DOWN_LANDSCAPE; - break; - default: - break; - } - - orientation = motion_orientation_remap(s, orientation); - *motion_orientation_ptr(s) = orientation; - } -} - -#endif /* CONFIG_BMI_ORIENTATION_SENSOR */ - -/* - * bmi3xx_interrupt - called when the sensor activates the interrupt line. - * - * This is a "top half" interrupt handler, it just asks motion sense ask - * to schedule the "bottom half", ->irq_handler(). - */ -void bmi3xx_interrupt(enum gpio_signal signal) -{ - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) - last_interrupt_timestamp = __hw_clock_source_read(); - - task_set_event(TASK_ID_MOTIONSENSE, CONFIG_ACCELGYRO_BMI3XX_INT_EVENT); -} - -static int enable_fifo(const struct motion_sensor_t *s, int enable) -{ - struct bmi_drv_data_t *data = BMI_GET_DATA(s); - /* Set FIFO config to enable accel gyro data */ - uint8_t reg_data[4]; - - RETURN_ERROR(bmi3_read_n(s, BMI3_REG_FIFO_CONF, reg_data, 4)); - - if (enable) { - if (s->type == MOTIONSENSE_TYPE_ACCEL) - reg_data[3] |= BMI3_FIFO_ACC_EN; - else - reg_data[3] |= BMI3_FIFO_GYR_EN; - - data->flags |= 1 << (s->type + BMI_FIFO_FLAG_OFFSET); - } else { - if (s->type == MOTIONSENSE_TYPE_ACCEL) - reg_data[3] &= ~BMI3_FIFO_ACC_EN; - else - reg_data[3] &= ~BMI3_FIFO_GYR_EN; - - data->flags &= ~(1 << (s->type + BMI_FIFO_FLAG_OFFSET)); - } - - return bmi3_write_n(s, BMI3_REG_FIFO_CONF, ®_data[2], 2); -} - -static int config_interrupt(const struct motion_sensor_t *s) -{ - int ret; - uint8_t reg_data[6] = {0}; - - if (s->type != MOTIONSENSE_TYPE_ACCEL) - return EC_SUCCESS; - - mutex_lock(s->mutex); - - /* Clear the FIFO using Flush command */ - reg_data[0] = BMI3_ENABLE; - reg_data[1] = 0; - ret = bmi3_write_n(s, BMI3_REG_FIFO_CTRL, reg_data, 2); - if (ret) - goto err_unlock; - - /* Map FIFO water-mark and FIFO full to INT1 pin */ - ret = bmi3_read_n(s, BMI3_REG_INT_MAP1, reg_data, 6); - if (ret) - goto err_unlock; - - reg_data[5] = BMI3_SET_BITS(reg_data[5], BMI3_FWM_INT, BMI3_INT1); - reg_data[5] = BMI3_SET_BITS(reg_data[5], BMI3_FFULL_INT, BMI3_INT1); - if (IS_ENABLED(CONFIG_BMI_ORIENTATION_SENSOR)) { - /* Map orientation to INT1 pin */ - reg_data[2] = BMI3_SET_BITS(reg_data[2], BMI3_ORIENT_INT, - BMI3_INT1); - } - - ret = bmi3_write_n(s, BMI3_REG_INT_MAP1, ®_data[2], 4); - if (ret) - goto err_unlock; - - /* Set FIFO water-mark to read data whenever available */ - reg_data[0] = BMI3_FIFO_ENTRY; - reg_data[1] = 0; - - ret = bmi3_write_n(s, BMI3_REG_FIFO_WATERMARK, reg_data, 2); - if (ret) - goto err_unlock; - - /* Get the previous configuration data */ - ret = bmi3_read_n(s, BMI3_REG_IO_INT_CTRL, reg_data, 4); - if (ret) - goto err_unlock; - - reg_data[2] = BMI3_SET_BIT_POS0(reg_data[2], BMI3_INT1_LVL, - BMI3_INT_ACTIVE_LOW); - - reg_data[2] = BMI3_SET_BITS(reg_data[2], BMI3_INT1_OD, - BMI3_INT_PUSH_PULL); - - reg_data[2] = BMI3_SET_BITS(reg_data[2], BMI3_INT1_OUTPUT_EN, - BMI3_INT_OUTPUT_ENABLE); - - /* - * Set the interrupt pin configurations - */ - ret = bmi3_write_n(s, BMI3_REG_IO_INT_CTRL, ®_data[2], 2); - if (ret) - goto err_unlock; - - if (IS_ENABLED(CONFIG_BMI_ORIENTATION_SENSOR)) { - /* Enable the orientation feature in BMI3 */ - ret = bmi3_read_n(s, BMI3_FEATURE_IO_0, reg_data, 4); - if (ret) - goto err_unlock; - - reg_data[2] |= BMI3_ANY_MOTION_X_EN_MASK; - ret = bmi3_write_n(s, BMI3_FEATURE_IO_0, ®_data[2], 2); - if (ret) - goto err_unlock; - - /* Write to feature engine */ - reg_data[0] = 1; - reg_data[1] = 0; - ret = bmi3_write_n(s, BMI3_FEATURE_IO_STATUS, reg_data, 2); - } - -err_unlock: - mutex_unlock(s->mutex); - return ret; -} - -static void bmi3_parse_fifo_data(struct motion_sensor_t *s, - struct bmi3_fifo_frame *fifo_frame, - uint32_t last_ts) -{ - struct bmi_drv_data_t *data = BMI_GET_DATA(s); - struct ec_response_motion_sensor_data vect; - uint16_t reg_data; - intv3_t v; - int i; - - /* Start index for FIFO parsing after I2C sync word removal */ - size_t fifo_index = 1; - - /* Variable to store I2C sync data which will get in FIFO data */ - uint16_t i2c_sync_data, fifo_size; - - if (!(data->flags & (BMI_FIFO_ALL_MASK << BMI_FIFO_FLAG_OFFSET))) { - /* - * The FIFO was disabled while we were processing it - * Flush potential left over: - * When sensor is resumed, we won't read old data. - */ - - /* Clear the FIFO using Flush command */ - reg_data = BMI3_ENABLE; - bmi3_write_n(s, BMI3_REG_FIFO_CTRL, (uint8_t *)®_data, 2); - return; - } - - /* Parse the length of data read excluding I2C sync word */ - fifo_size = fifo_frame->available_fifo_len - 1; - - while (fifo_size > 0) { - for (i = 0; i < NUM_OF_PRIMARY_SENSOR; i++) { - struct motion_sensor_t *sens_output = s + i; - - if (data->flags & BIT(i + BMI_FIFO_FLAG_OFFSET)) { - /* - * In-case of FIFO read fail it has only - * 0x8000. - */ - if (fifo_frame->data[fifo_index] == 0x8000) - break; - - /* - * In case the frame has been cut, FIFO was - * greater than our buffer. - */ - if (fifo_size < BMI3_FIFO_ENTRY) - break; - - /* Frame is complete, but may have no data. */ - fifo_size -= BMI3_FIFO_ENTRY; - i2c_sync_data = fifo_frame->data[fifo_index++]; - if (i2c_sync_data == - BMI3_FIFO_ACCEL_I2C_SYNC_FRAME + i) { - fifo_index += 2; - continue; - } - - v[X] = i2c_sync_data; - v[Y] = fifo_frame->data[fifo_index++]; - v[Z] = fifo_frame->data[fifo_index++]; - - rotate(v, *sens_output->rot_standard_ref, v); - - vect.data[X] = v[X]; - vect.data[Y] = v[Y]; - vect.data[Z] = v[Z]; - vect.flags = 0; - vect.sensor_num = sens_output - motion_sensors; - motion_sense_fifo_stage_data(&vect, - sens_output, 3, last_ts); - } - } - } -} - -/* - * irq_handler - bottom half of the interrupt stack. - * Ran from the motion_sense task, finds the events that raised the interrupt. - * - * For now, we just print out. We should set a bitmask motion sense code will - * act upon. - */ -static int irq_handler(struct motion_sensor_t *s, - uint32_t *event) -{ - bool has_read_fifo = false; - uint16_t int_status[2]; - uint16_t reg_data[2]; - struct bmi3_fifo_frame fifo_frame; - - if ((s->type != MOTIONSENSE_TYPE_ACCEL) || - (!(*event & CONFIG_ACCELGYRO_BMI3XX_INT_EVENT))) - return EC_ERROR_NOT_HANDLED; - - /* Get the interrupt status */ - do { - RETURN_ERROR(bmi3_read_n(s, BMI3_REG_INT_STATUS_INT1, - (uint8_t *)int_status, 4)); - - if (IS_ENABLED(CONFIG_BMI_ORIENTATION_SENSOR) && - (BMI3_INT_STATUS_ORIENTATION & int_status[1])) - irq_set_orientation(s); - - if ((int_status[1] & - (BMI3_INT_STATUS_FWM | BMI3_INT_STATUS_FFULL)) == 0) - break; - - /* Get the FIFO fill level in words */ - RETURN_ERROR(bmi3_read_n(s, BMI3_REG_FIFO_FILL_LVL, - (uint8_t *)reg_data, 4)); - - reg_data[1] = BMI3_GET_BIT_POS0(reg_data[1], - BMI3_FIFO_FILL_LVL); - - /* Add space for the initial 16bit read. */ - fifo_frame.available_fifo_len = reg_data[1] + 1; - - /* - * If fill level is greater than buffer size then wrap it to - * buffer size. - */ - if (fifo_frame.available_fifo_len > ARRAY_SIZE(fifo_frame.data)) - CPRINTS("unexpected large FIFO: %d", - fifo_frame.available_fifo_len); - - fifo_frame.available_fifo_len = - MIN(fifo_frame.available_fifo_len, - ARRAY_SIZE(fifo_frame.data)); - /* Read FIFO data */ - RETURN_ERROR(bmi3_read_n(s, BMI3_REG_FIFO_DATA, - (uint8_t *)fifo_frame.data, - fifo_frame.available_fifo_len * - sizeof(uint16_t))); - - bmi3_parse_fifo_data(s, &fifo_frame, last_interrupt_timestamp); - has_read_fifo = true; - } while (true); - - if (IS_ENABLED(CONFIG_ACCEL_FIFO) && has_read_fifo) - motion_sense_fifo_commit_data(); - - return EC_SUCCESS; -} -#endif /* CONFIG_ACCEL_INTERRUPTS */ - -static int read_temp(const struct motion_sensor_t *s, int *temp_ptr) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -int get_gyro_offset(const struct motion_sensor_t *s, intv3_t v) -{ - int i; - uint8_t reg_data[14] = { 0 }; - - /* Get the accel offset values */ - RETURN_ERROR(bmi3_read_n(s, GYR_DP_OFF_X, reg_data, 14)); - - v[0] = ((uint16_t)(reg_data[3] << 8) | reg_data[2]) & 0x03FF; - v[1] = ((uint16_t)(reg_data[7] << 8) | reg_data[6]) & 0x03FF; - v[2] = ((uint16_t)(reg_data[11] << 8) | reg_data[10]) & 0x03FF; - - for (i = X; i <= Z; ++i) { - if (v[i] > 0x01FF) - v[i] = -1024 + v[i]; - - v[i] = round_divide((int64_t)v[i] * BMI_OFFSET_GYRO_MULTI_MDS, - BMI_OFFSET_GYRO_DIV_MDS); - } - - return EC_SUCCESS; -} - -int set_gyro_offset(const struct motion_sensor_t *s, intv3_t v) -{ - uint8_t reg_data[6] = { 0 }; - uint8_t base_addr[2] = { BMI3_GYRO_OFFSET_ADDR, 0 }; - int i, val[3]; - - for (i = X; i <= Z; ++i) { - val[i] = round_divide((int64_t)v[i] * BMI_OFFSET_GYRO_DIV_MDS, - BMI_OFFSET_GYRO_MULTI_MDS); - if (val[i] > 511) - val[i] = 511; - if (val[i] < -512) - val[i] = -512; - if (val[i] < 0) - val[i] = 1024 + val[i]; - } - - /* - * Set the user accel offset base address to feature engine - * transmission address to start DMA transaction - */ - RETURN_ERROR(bmi3_write_n(s, BMI3_FEATURE_ENGINE_DMA_TX, base_addr, 2)); - - reg_data[0] = (uint8_t)(val[0] & BMI3_SET_LOW_BYTE); - reg_data[1] = (uint8_t)((val[0] & 0x0300) >> 8); - reg_data[2] = (uint8_t)(val[1] & BMI3_SET_LOW_BYTE); - reg_data[3] = (uint8_t)((val[1] & 0x0300) >> 8); - reg_data[4] = (uint8_t)(val[2] & BMI3_SET_LOW_BYTE); - reg_data[5] = (uint8_t)((val[2] & 0x0300) >> 8); - - /* Set the configuration to the feature engine register */ - RETURN_ERROR(bmi3_write_n(s, BMI3_FEATURE_ENGINE_DMA_TX_DATA, reg_data, - 6)); - - /* Update the offset to the sensor engine */ - reg_data[0] = (uint8_t)(BMI3_CMD_USR_GAIN_OFFS_UPDATE & - BMI3_SET_LOW_BYTE); - reg_data[1] = (uint8_t)((BMI3_CMD_USR_GAIN_OFFS_UPDATE & - BMI3_SET_HIGH_BYTE) >> 8); - RETURN_ERROR(bmi3_write_n(s, BMI3_REG_CMD, reg_data, 2)); - - return EC_SUCCESS; -} - -int get_accel_offset(const struct motion_sensor_t *s, intv3_t v) -{ - int i; - uint8_t reg_data[14] = { 0 }; - - /* Get the accel offset values from user registers */ - RETURN_ERROR(bmi3_read_n(s, ACC_DP_OFF_X, reg_data, 14)); - - v[0] = ((uint16_t)(reg_data[3] << 8) | reg_data[2]) & 0x1FFF; - v[1] = ((uint16_t)(reg_data[7] << 8) | reg_data[6]) & 0x1FFF; - v[2] = ((uint16_t)(reg_data[11] << 8) | reg_data[10]) & 0x1FFF; - - for (i = X; i <= Z; ++i) { - if (v[i] > 0x0FFF) - v[i] = -8192 + v[i]; - - v[i] = round_divide((int64_t)v[i] * BMI3_OFFSET_ACC_MULTI_MG, - BMI_OFFSET_ACC_DIV_MG); - } - - return EC_SUCCESS; -} - -int set_accel_offset(const struct motion_sensor_t *s, intv3_t v) -{ - uint8_t reg_data[6] = { 0 }; - uint8_t base_addr[2] = { BMI3_ACC_OFFSET_ADDR, 0 }; - uint8_t saved_conf[6] = { 0 }; - int i, val[3]; - - for (i = X; i <= Z; ++i) { - val[i] = round_divide((int64_t)v[i] * BMI_OFFSET_ACC_DIV_MG, - BMI3_OFFSET_ACC_MULTI_MG); - if (val[i] > 4095) - val[i] = 4095; - if (val[i] < -4096) - val[i] = -4096; - if (val[i] < 0) - val[i] += 8192; - } - - /* Set the power mode as suspend */ - RETURN_ERROR(bmi3_read_n(s, BMI3_REG_ACC_CONF, saved_conf, 6)); - - /* Ignore two i2c sync bytes and store consecutive bytes in reg_data */ - reg_data[0] = saved_conf[2]; - reg_data[1] = 0x00; - reg_data[2] = saved_conf[4]; - reg_data[3] = 0x00; - RETURN_ERROR(bmi3_write_n(s, BMI3_REG_ACC_CONF, reg_data, 4)); - - /* - * Set the user accel offset base address to feature engine - * transmission address to start DMA transaction - */ - RETURN_ERROR(bmi3_write_n(s, BMI3_FEATURE_ENGINE_DMA_TX, base_addr, 2)); - - reg_data[0] = (uint8_t)(val[0] & BMI3_SET_LOW_BYTE); - reg_data[1] = (uint8_t)((val[0] & 0x1F00) >> 8); - reg_data[2] = (uint8_t)(val[1] & BMI3_SET_LOW_BYTE); - reg_data[3] = (uint8_t)((val[1] & 0x1F00) >> 8); - reg_data[4] = (uint8_t)(val[2] & BMI3_SET_LOW_BYTE); - reg_data[5] = (uint8_t)((val[2] & 0x1F00) >> 8); - - /* Set the configuration to the feature engine register */ - RETURN_ERROR(bmi3_write_n(s, BMI3_FEATURE_ENGINE_DMA_TX_DATA, reg_data, - 6)); - - /* Restore ACC_CONF by storing saved_conf data */ - RETURN_ERROR(bmi3_read_n(s, BMI3_REG_ACC_CONF, saved_conf, 6)); - - /* Update the offset to the sensor engine */ - reg_data[0] = (uint8_t)(BMI3_CMD_USR_GAIN_OFFS_UPDATE & - BMI3_SET_LOW_BYTE); - - reg_data[1] = (uint8_t)((BMI3_CMD_USR_GAIN_OFFS_UPDATE & - BMI3_SET_HIGH_BYTE) >> 8); - - RETURN_ERROR(bmi3_write_n(s, BMI3_REG_CMD, reg_data, 2)); - - return EC_SUCCESS; -} - -static int wait_and_read_data(const struct motion_sensor_t *s, - intv3_t accel_data) -{ - uint8_t reg_data[8] = {0}; - - /* Retry 5 times */ - uint8_t try_cnt = FOC_TRY_COUNT; - - /* Check if data is ready */ - while (try_cnt && (!(reg_data[2] & BMI3_STAT_DATA_RDY_ACCEL_MSK))) { - /* 20ms delay for 50Hz ODR */ - msleep(FOC_DELAY); - - /* Read the status register */ - RETURN_ERROR(bmi3_read_n(s, BMI3_REG_STATUS, reg_data, 4)); - try_cnt--; - } - - if (!(reg_data[2] & BMI3_STAT_DATA_RDY_ACCEL_MSK)) - return EC_ERROR_TIMEOUT; - - /* Read the sensor data */ - RETURN_ERROR(bmi3_read_n(s, BMI3_REG_ACC_DATA_X, reg_data, 8)); - - accel_data[0] = ((int16_t)((reg_data[3] << 8) | reg_data[2])); - accel_data[1] = ((int16_t)((reg_data[5] << 8) | reg_data[4])); - accel_data[2] = ((int16_t)((reg_data[7] << 8) | reg_data[6])); - - rotate(accel_data, *s->rot_standard_ref, accel_data); - - return EC_SUCCESS; -} - -/*! - * @brief This internal API performs Fast Offset Compensation for accelerometer. - */ -static int8_t perform_accel_foc(struct motion_sensor_t *s, int *target, - int sens_range) -{ - intv3_t accel_data, offset; - int32_t delta_value[3] = {0, 0, 0}; - - /* Variable to define count */ - uint8_t i, loop, sample_count = 0; - - for (loop = 0; loop < BMI3_FOC_SAMPLE_LIMIT; loop++) { - - RETURN_ERROR(wait_and_read_data(s, accel_data)); - - sample_count++; - - /* Store the data in a temporary structure */ - delta_value[0] += accel_data[0] - target[X]; - delta_value[1] += accel_data[1] - target[Y]; - delta_value[2] += accel_data[2] - target[Z]; - } - - /* The data is in LSB so -> [(LSB)*1000*range/2^15] (mdps | mg) */ - for (i = X; i <= Z; ++i) { - offset[i] = (((int64_t)(delta_value[i] * 1000 * sens_range - / sample_count) >> 15) * -1); - } - - rotate_inv(offset, *s->rot_standard_ref, offset); - - RETURN_ERROR(set_accel_offset(s, offset)); - - return EC_SUCCESS; -} - -static int set_gyro_foc_config(struct motion_sensor_t *s) -{ - uint8_t reg_data[4] = { 0 }; - uint8_t base_addr[2] = { BMI3_BASE_ADDR_SC, 0 }; - - /* - * Set the user accel offset base address to feature engine - * transmission address to start DMA transaction - */ - RETURN_ERROR(bmi3_write_n(s, BMI3_FEATURE_ENGINE_DMA_TX, base_addr, 2)); - - /* Read the configuration from the feature engine register */ - RETURN_ERROR(bmi3_read_n(s, BMI3_FEATURE_ENGINE_DMA_TX_DATA, reg_data, - 4)); - /* Enable self calibration */ - reg_data[2] |= 0x07; - - RETURN_ERROR(bmi3_write_n(s, BMI3_FEATURE_ENGINE_DMA_TX, base_addr, 2)); - - /* Set the configuration to the feature engine register */ - RETURN_ERROR(bmi3_write_n(s, BMI3_FEATURE_ENGINE_DMA_TX_DATA, - ®_data[2], 2)); - - /* Trigger bmi3 gyro self calibration */ - reg_data[0] = (uint8_t)(BMI3_CMD_SELF_CALIB & BMI3_SET_LOW_BYTE); - reg_data[1] = (uint8_t)((BMI3_CMD_SELF_CALIB & BMI3_SET_HIGH_BYTE) - >> 8); - - RETURN_ERROR(bmi3_write_n(s, BMI3_REG_CMD, reg_data, 2)); - - return EC_SUCCESS; -} - -static int get_calib_result(struct motion_sensor_t *s) -{ - uint8_t i, reg_data[4]; - - for (i = 0; i < 25; i++) { - /* A delay of 120ms is required to read this status register */ - msleep(120); - - /* Read the configuration from the feature engine register */ - RETURN_ERROR(bmi3_read_n(s, BMI3_FEATURE_IO_1, reg_data, 4)); - - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - if ((reg_data[3] & BMI3_UGAIN_OFFS_UPD_COMPLETE) - && ((reg_data[2] & BMI3_FEATURE_IO_1_ERROR_MASK) - == BMI3_FEATURE_IO_1_NO_ERROR)) { - return EC_SUCCESS; - } - break; - case MOTIONSENSE_TYPE_GYRO: - if (reg_data[2] & BMI3_SC_ST_STATUS_MASK) { - /* Check calibration result */ - if (reg_data[2] & BMI3_SC_RESULT_MASK) - return EC_SUCCESS; - } - break; - default: - return EC_ERROR_UNIMPLEMENTED; - } - } - - return EC_ERROR_NOT_CALIBRATED; -} - -static int perform_calib(struct motion_sensor_t *s, int enable) -{ - int ret; - intv3_t target = {0, 0, 0}; - uint8_t saved_conf[6] = {0}; - - /* Sensor is configured to be in 16G range */ - int sens_range = 16; - - /* Variable to set the accelerometer configuration value 50Hz for FOC */ - uint8_t acc_conf_data[2] = {BMI3_FOC_ACC_CONF_VAL_LSB, - BMI3_FOC_ACC_CONF_VAL_MSB}; - - if (!enable) - return EC_SUCCESS; - - /* Get default configurations for the type of feature selected. */ - RETURN_ERROR(bmi3_read_n(s, BMI3_REG_ACC_CONF, saved_conf, - 6)); - - ret = bmi3_write_n(s, BMI3_REG_ACC_CONF, acc_conf_data, 2); - if (ret) - goto end_calib; - - msleep(FOC_DELAY); - - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - target[Z] = BMI3_ACC_DATA_PLUS_1G(sens_range); - - /* Perform accel calibration */ - ret = perform_accel_foc(s, target, sens_range); - if (ret) - goto end_calib; - - /* Get caliration results */ - ret = get_calib_result(s); - if (ret) - goto end_calib; - - break; - case MOTIONSENSE_TYPE_GYRO: - ret = set_gyro_foc_config(s); - if (ret) - goto end_calib; - - ret = get_calib_result(s); - if (ret) - goto end_calib; - - break; - default: - /* Not supported on Magnetometer */ - ret = EC_RES_INVALID_PARAM; - goto end_calib; - } - - -end_calib: - /* Restore ACC_CONF before exiting */ - RETURN_ERROR(bmi3_write_n(s, BMI3_REG_ACC_CONF, &saved_conf[2], 4)); - - return ret; -} - -static int get_offset(const struct motion_sensor_t *s, int16_t *offset, - int16_t *temp) -{ - int i; - intv3_t v; - - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - /* - * The offset of the accelerometer is a 8 bit - * two-complement number in units of 3.9 mg independent of the - * range selected for the accelerometer. - */ - RETURN_ERROR(get_accel_offset(s, v)); - break; - case MOTIONSENSE_TYPE_GYRO: - /* Gyro offset is in milli-dps */ - RETURN_ERROR(get_gyro_offset(s, v)); - break; - default: - for (i = X; i <= Z; i++) - v[i] = 0; - } - - rotate(v, *s->rot_standard_ref, v); - offset[X] = v[X]; - offset[Y] = v[Y]; - offset[Z] = v[Z]; - /* Saving temperature at calibration not supported yet */ - *temp = (int16_t)EC_MOTION_SENSE_INVALID_CALIB_TEMP; - - return EC_SUCCESS; -} - -static int set_offset(const struct motion_sensor_t *s, - const int16_t *offset, - int16_t temp) -{ - intv3_t v = { offset[X], offset[Y], offset[Z] }; - (void)temp; - - rotate_inv(v, *s->rot_standard_ref, v); - - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - /* Offset should be in units of mg */ - RETURN_ERROR(set_accel_offset(s, v)); - break; - case MOTIONSENSE_TYPE_GYRO: - /* Offset should be in units of mdps */ - RETURN_ERROR(set_gyro_offset(s, v)); - break; - default: - return EC_RES_INVALID_PARAM; - } - - return EC_SUCCESS; -} - -#ifdef CONFIG_BODY_DETECTION -int get_rms_noise(const struct motion_sensor_t *s) -{ - return EC_ERROR_UNIMPLEMENTED; -} -#endif - -static int set_scale(const struct motion_sensor_t *s, const uint16_t *scale, - int16_t temp) -{ - struct accelgyro_saved_data_t *saved_data = BMI_GET_SAVED_DATA(s); - - saved_data->scale[X] = scale[X]; - saved_data->scale[Y] = scale[Y]; - saved_data->scale[Z] = scale[Z]; - - return EC_SUCCESS; -} - -static int get_scale(const struct motion_sensor_t *s, uint16_t *scale, - int16_t *temp) -{ - struct accelgyro_saved_data_t *saved_data = BMI_GET_SAVED_DATA(s); - - scale[X] = saved_data->scale[X]; - scale[Y] = saved_data->scale[Y]; - scale[Z] = saved_data->scale[Z]; - - *temp = (int16_t)EC_MOTION_SENSE_INVALID_CALIB_TEMP; - - return EC_SUCCESS; -} - - -static int get_data_rate(const struct motion_sensor_t *s) -{ - struct accelgyro_saved_data_t *saved_data = BMI_GET_SAVED_DATA(s); - - return saved_data->odr; -} - -static int set_data_rate(const struct motion_sensor_t *s, - int rate, int rnd) -{ - int ret; - int normalized_rate = 0; - uint8_t reg_data[4]; - uint8_t reg_val = 0; - - struct accelgyro_saved_data_t *saved_data = BMI_GET_SAVED_DATA(s); - - if (rate > 0) - RETURN_ERROR(bmi_get_normalized_rate(s, rate, rnd, - &normalized_rate, ®_val)); - - /* - * Lock accel resource to prevent another task from attempting - * to write accel parameters until we are done. - */ - mutex_lock(s->mutex); - - /* - * Get default configurations for the type of feature selected. - */ - ret = bmi3_read_n(s, BMI3_REG_ACC_CONF + s->type, reg_data, 4); - if (ret) { - mutex_unlock(s->mutex); - return ret; - } - - if (s->type == MOTIONSENSE_TYPE_ACCEL) { - if (rate == 0) { - /* FIFO stop collecting events */ - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) - ret = enable_fifo(s, 0); - - /* - * Disable accel to set rate equal to zero. - * Accel does not have suspend mode. - */ - reg_data[3] = BMI3_SET_BITS(reg_data[3], - BMI3_POWER_MODE, - BMI3_ACC_MODE_DISABLE); - - saved_data->odr = 0; - } else if (saved_data->odr == 0) { - /* - * Power mode changed from suspend to - * normal - */ - reg_data[3] = BMI3_SET_BITS(reg_data[3], - BMI3_POWER_MODE, - BMI3_ACC_MODE_NORMAL); - } - } else if (s->type == MOTIONSENSE_TYPE_GYRO) { - if (rate == 0) { - /* FIFO stop collecting events */ - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) - ret = enable_fifo(s, 0); - - /* - * Set gyro to suspend mode to disable gyro - * however keep internal driver enabled - */ - reg_data[3] = BMI3_SET_BITS(reg_data[3], - BMI3_POWER_MODE, - BMI3_GYR_MODE_SUSPEND); - - saved_data->odr = 0; - } else if (saved_data->odr == 0) { - /* Power mode changed from suspend to - * normal - */ - reg_data[3] = BMI3_SET_BITS(reg_data[3], - BMI3_POWER_MODE, - BMI3_GYR_MODE_NORMAL); - } - } - - /* Set accelerometer ODR */ - reg_data[2] = BMI3_SET_BIT_POS0(reg_data[2], BMI3_SENS_ODR, reg_val); - - /* Set the accel/gyro configurations. */ - ret = bmi3_write_n(s, BMI3_REG_ACC_CONF + s->type, ®_data[2], 2); - if (ret) { - mutex_unlock(s->mutex); - return ret; - } - - saved_data->odr = normalized_rate; - - /* - * If rate is non zero, FIFO start collecting events. - * They will be discarded if AP does not want them. - */ - if (rate > 0) - ret = enable_fifo(s, 1); - - mutex_unlock(s->mutex); - return ret; -} - -static int get_resolution(const struct motion_sensor_t *s) -{ - return BMI3_16_BIT_RESOLUTION; -} - -static int set_range(struct motion_sensor_t *s, int range, int rnd) -{ - int ret; - uint8_t index, sens_size = 0; - uint8_t reg_data[4] = { 0 }; - int (*sensor_range)[2]; - - int acc_sensor_range[4][2] = { - { 2, BMI3_ACC_RANGE_2G }, - { 4, BMI3_ACC_RANGE_4G }, - { 8, BMI3_ACC_RANGE_8G }, - { 16, BMI3_ACC_RANGE_16G }, - }; - - int gyr_sensor_range[5][2] = { - { 125, BMI3_GYR_RANGE_125DPS }, - { 250, BMI3_GYR_RANGE_250DPS }, - { 500, BMI3_GYR_RANGE_500DPS }, - { 1000, BMI3_GYR_RANGE_1000DPS }, - { 2000, BMI3_GYR_RANGE_2000DPS }, - }; - - if (s->type == MOTIONSENSE_TYPE_ACCEL) { - sens_size = ARRAY_SIZE(acc_sensor_range); - sensor_range = acc_sensor_range; - } else { - sens_size = ARRAY_SIZE(gyr_sensor_range); - sensor_range = gyr_sensor_range; - } - - for (index = 0; index < sens_size - 1; index++) { - if (range <= sensor_range[index][0]) - break; - - if (range < sensor_range[index + 1][0] && rnd) { - index++; - break; - } - } - - mutex_lock(s->mutex); - - /* - * Read the range register from sensor for accelerometer/gyroscope - * s->type should have MOTIONSENSE_TYPE_ACCEL = 0 ; - * MOTIONSENSE_TYPE_GYRO = 1 - */ - ret = bmi3_read_n(s, BMI3_REG_ACC_CONF + s->type, reg_data, 4); - - if (ret == EC_SUCCESS) { - /* Set accelerometer/Gyroscope range */ - /* Gravity range of the sensor (+/- 2G, 4G, 8G, 16G). */ - reg_data[2] = BMI3_SET_BITS(reg_data[2], BMI3_SENS_RANGE, - sensor_range[index][1]); - - /* Set the accel/gyro configurations. */ - ret = bmi3_write_n(s, BMI3_REG_ACC_CONF + s->type, - ®_data[2], 2); - - /* Now that we have set the range, update the driver's value. */ - if (ret == EC_SUCCESS) - s->current_range = sensor_range[index][0]; - } - - mutex_unlock(s->mutex); - - return ret; -} - -static int read(const struct motion_sensor_t *s, intv3_t v) -{ - int ret; - uint8_t reg_data[8] = { 0 }; - uint16_t status_val = 0; - - mutex_lock(s->mutex); - - /* Read the status register */ - ret = bmi3_read_n(s, BMI3_REG_STATUS, reg_data, 4); - - if (ret == EC_SUCCESS) { - status_val = (reg_data[2] | ((uint16_t)reg_data[3] << 8)); - /* - * If sensor data is not ready, return the previous read data. - * Note: return success so that motion sensor task can read - * again to get the latest updated sensor data quickly. - */ - if (!(status_val & BMI3_DRDY_MASK(s->type))) { - if (v != s->raw_xyz) - memcpy(v, s->raw_xyz, sizeof(s->raw_xyz)); - - mutex_unlock(s->mutex); - - return EC_SUCCESS; - } - - if (s->type == MOTIONSENSE_TYPE_ACCEL) { - /* Read the sensor data */ - ret = bmi3_read_n(s, BMI3_REG_ACC_DATA_X, reg_data, 8); - } else if (s->type == MOTIONSENSE_TYPE_GYRO) { - /* Read the sensor data */ - ret = bmi3_read_n(s, BMI3_REG_GYR_DATA_X, reg_data, 8); - } - - if (ret == EC_SUCCESS) { - v[0] = ((int16_t)((reg_data[3] << 8) | reg_data[2])); - v[1] = ((int16_t)((reg_data[5] << 8) | reg_data[4])); - v[2] = ((int16_t)((reg_data[7] << 8) | reg_data[6])); - - rotate(v, *s->rot_standard_ref, v); - } - } - - mutex_unlock(s->mutex); - - return ret; -} - -static int init(struct motion_sensor_t *s) -{ - /* Status of communication result */ - uint8_t i; - uint8_t reg_data[4] = { 0 }; - - /* Store the sensor configurations */ - struct accelgyro_saved_data_t *saved_data = BMI_GET_SAVED_DATA(s); - struct bmi_drv_data_t *data = BMI_GET_DATA(s); - - /* This driver requires a mutex */ - ASSERT(s->mutex); - - /* - * BMI3xx driver only supports MOTIONSENSE_TYPE_ACCEL and - * MOTIONSENSE_TYPE_GYR0 - */ - if (s->type != MOTIONSENSE_TYPE_ACCEL - && s->type != MOTIONSENSE_TYPE_GYRO) - return EC_ERROR_UNIMPLEMENTED; - - /* Read chip id */ - RETURN_ERROR(bmi3_read_n(s, BMI3_REG_CHIP_ID, reg_data, 4)); - - if (reg_data[2] != BMI323_CHIP_ID) - return EC_ERROR_HW_INTERNAL; - - if (s->type == MOTIONSENSE_TYPE_ACCEL) { - /* Reset bmi3 device */ - reg_data[0] = (uint8_t)(BMI3_CMD_SOFT_RESET - & BMI3_SET_LOW_BYTE); - reg_data[1] = (uint8_t)((BMI3_CMD_SOFT_RESET - & BMI3_SET_HIGH_BYTE) >> 8); - - RETURN_ERROR(bmi3_write_n(s, BMI3_REG_CMD, reg_data, 2)); - - /* Delay of 2ms after soft reset*/ - msleep(2); - - /* Enable feature engine bit */ - reg_data[0] = BMI3_ENABLE; - reg_data[1] = 0; - - RETURN_ERROR(bmi3_write_n(s, BMI3_REG_FEATURE_ENGINE_GLOB_CTRL, - reg_data, 2)); - - if (IS_ENABLED(CONFIG_ACCEL_INTERRUPTS)) - RETURN_ERROR(config_interrupt(s)); - } - - for (i = X; i <= Z; i++) - saved_data->scale[i] = MOTION_SENSE_DEFAULT_SCALE; - - /* The sensor is in Suspend mode at init, so set data rate to 0*/ - saved_data->odr = 0; - - /* Flags used in FIFO parsing */ - data->flags &= ~(BMI_FLAG_SEC_I2C_ENABLED - | (BMI_FIFO_ALL_MASK << BMI_FIFO_FLAG_OFFSET)); - - return sensor_init_done(s); -} - -/* Accelerometer/Gyroscope base driver structure */ -const struct accelgyro_drv bmi3xx_drv = { - .init = init, - .read = read, - .set_range = set_range, - .get_resolution = get_resolution, - .set_data_rate = set_data_rate, - .get_data_rate = get_data_rate, - .get_scale = get_scale, - .set_scale = set_scale, - .set_offset = set_offset, - .get_offset = get_offset, - .perform_calib = perform_calib, - .read_temp = read_temp, -#ifdef CONFIG_ACCEL_INTERRUPTS - .irq_handler = irq_handler, -#endif -#ifdef CONFIG_BODY_DETECTION - .get_rms_noise = get_rms_noise, -#endif -}; diff --git a/driver/accelgyro_bmi3xx.h b/driver/accelgyro_bmi3xx.h deleted file mode 100644 index b52d503f92..0000000000 --- a/driver/accelgyro_bmi3xx.h +++ /dev/null @@ -1,261 +0,0 @@ -/* Copyright 2021 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. - */ - -/* BMI3XX gsensor module for Chrome EC */ - -#ifndef __CROS_EC_ACCELGYRO_BMI3XX_H -#define __CROS_EC_ACCELGYRO_BMI3XX_H - -/* Sensor Specific macros */ -#define BMI3_ADDR_I2C_PRIM 0x68 -#define BMI3_ADDR_I2C_SEC 0x69 -#define BMI3_16_BIT_RESOLUTION 16 - -/* Chip-specific registers */ -#define BMI3_REG_CHIP_ID 0x00 - -#define BMI3_REG_STATUS 0x02 -#define BMI3_STAT_DATA_RDY_ACCEL_POS 7 -#define BMI3_STAT_DATA_RDY_ACCEL_MSK 0x80 - -#define BMI3_REG_ACC_DATA_X 0x03 -#define BMI3_ACC_RANGE_2G 0x00 -#define BMI3_ACC_RANGE_4G 0x01 -#define BMI3_ACC_RANGE_8G 0x02 -#define BMI3_ACC_RANGE_16G 0x03 -#define BMI3_ACC_MODE_DISABLE 0x00 -#define BMI3_ACC_MODE_LOW_PWR 0x03 -#define BMI3_ACC_MODE_NORMAL 0X04 -#define BMI3_ACC_MODE_HIGH_PERF 0x07 - -#define BMI3_REG_GYR_DATA_X 0x06 -#define BMI3_GYR_RANGE_125DPS 0x00 -#define BMI3_GYR_RANGE_250DPS 0x01 -#define BMI3_GYR_RANGE_500DPS 0x02 -#define BMI3_GYR_RANGE_1000DPS 0x03 -#define BMI3_GYR_RANGE_2000DPS 0x04 -#define BMI3_GYR_MODE_DISABLE 0x00 -#define BMI3_GYR_MODE_SUSPEND 0X01 -#define BMI3_GYR_MODE_ULTRA_LOW_PWR 0X02 -#define BMI3_GYR_MODE_LOW_PWR 0x03 -#define BMI3_GYR_MODE_NORMAL 0X04 -#define BMI3_GYR_MODE_HIGH_PERF 0x07 - -#define BMI3_REG_INT_STATUS_INT1 0x0D -#define BMI3_REG_FIFO_FILL_LVL 0x15 -#define BMI3_REG_FIFO_DATA 0x16 -#define BMI3_REG_ACC_CONF 0x20 -#define BMI3_REG_GYR_CONF 0x21 -#define BMI3_REG_INT_MAP1 0x3A -#define BMI3_REG_FIFO_WATERMARK 0x35 - -#define BMI3_REG_FIFO_CONF 0x36 -#define BMI3_FIFO_STOP_ON_FULL 0x01 -#define BMI3_FIFO_TIME_EN 0x01 -#define BMI3_FIFO_ACC_EN 0x02 -#define BMI3_FIFO_GYR_EN 0x04 -#define BMI3_FIFO_TEMP_EN 0x08 -#define BMI3_FIFO_ALL_EN 0x0F - -#define BMI3_REG_FIFO_CTRL 0x37 -#define BMI3_REG_IO_INT_CTRL 0x38 -#define BMI3_INT1_LVL_MASK 0x01 -#define BMI3_INT1_OD_MASK 0x02 -#define BMI3_INT1_OD_POS 1 -#define BMI3_INT1_OUTPUT_EN_MASK 0x04 -#define BMI3_INT1_OUTPUT_EN_POS 2 -#define BMI3_INT_PUSH_PULL 0 -#define BMI3_INT_OPEN_DRAIN 1 -#define BMI3_INT_ACTIVE_LOW 0 -#define BMI3_INT_ACTIVE_HIGH 1 - -#define BMI3_REG_IO_INT_CONF 0x39 -#define BMI3_INT_LATCH_EN 1 -#define BMI3_INT_LATCH_DISABLE 0 - -#define BMI3_REG_FEATURE_ENGINE_GLOB_CTRL 0x40 - -#define BMI3_FEATURE_EVENT_EXT 0x47 -#define BMI3_PORTRAIT_LANDSCAPE_MASK 0x03 -#define BMI3_PORTRAIT 0 -#define BMI3_LANDSCAPE 1 -#define BMI3_PORTRAIT_INVERT 2 -#define BMI3_LANDSCAPE_INVERT 3 - -#define ACC_DP_OFF_X 0x60 -#define GYR_DP_OFF_X 0x66 - -#define BMI3_REG_CMD 0x7E -#define BMI3_CMD_SOFT_RESET 0xDEAF - -/* BMI3 Interrupt Output Enable */ -#define BMI3_INT_OUTPUT_DISABLE 0 -#define BMI3_INT_OUTPUT_ENABLE 1 - -/* FIFO sensor data length (in word), Accel or Gyro */ -#define BMI3_FIFO_ENTRY 0x3 -/* Macro to define accelerometer configuration value for FOC */ -#define BMI3_FOC_ACC_CONF_VAL_LSB 0xB7 -#define BMI3_FOC_ACC_CONF_VAL_MSB 0x40 -/* Macro to define the accel FOC range */ -#define BMI3_ACC_FOC_2G_REF 16384 -#define BMI3_ACC_FOC_4G_REF 8192 -#define BMI3_ACC_FOC_8G_REF 4096 -#define BMI3_ACC_FOC_16G_REF 2048 -#define BMI3_FOC_SAMPLE_LIMIT 32 - -/* 20ms delay for 50Hz ODR */ -#define FOC_TRY_COUNT 5 -#define FOC_DELAY 20 -#define BMI3_INT_STATUS_FWM 0x4000 -#define BMI3_INT_STATUS_FFULL 0x8000 -#define BMI3_INT_STATUS_ORIENTATION 0x0008 - - -#define BMI3_FIFO_GYRO_I2C_SYNC_FRAME 0x7f02 -#define BMI3_FIFO_ACCEL_I2C_SYNC_FRAME 0x7f01 - -/* Gyro self calibration address */ -#define BMI3_BASE_ADDR_SC 0x26 -#define BMI3_CMD_SELF_CALIB 0x0101 - -/* Feature engine General purpose register 1. */ -#define BMI3_FEATURE_IO_0 0x10 -#define BMI3_ANY_MOTION_X_EN_MASK 0x08 - -#define BMI3_FEATURE_IO_1 0x11 -#define BMI3_FEATURE_IO_1_ERROR_MASK 0x0F -#define BMI3_FEATURE_IO_1_NO_ERROR 0x05 -#define BMI3_SC_ST_STATUS_MASK 0x10 -#define BMI3_SC_RESULT_MASK 0x20 -#define BMI3_UGAIN_OFFS_UPD_COMPLETE 0x01 - -#define BMI3_FEATURE_IO_STATUS 0x14 - -/* - * The max positive value of accel data is 0x7FFF, equal to range(g) - * So, in order to get +1g, divide the 0x7FFF by range - */ -#define BMI3_ACC_DATA_PLUS_1G(range) (0x7FFF / (range)) -#define BMI3_ACC_DATA_MINUS_1G(range) (-BMI3_ACC_DATA_PLUS_1G(range)) - -/* Offset DMA registers */ -#define BMI3_ACC_OFFSET_ADDR 0x40 -#define BMI3_GYRO_OFFSET_ADDR 0x46 - -/* - * Start address of the DMA transaction. Has to be written to initiate a - * transaction. - */ -#define BMI3_FEATURE_ENGINE_DMA_TX 0x41 - -/* DMA read/write data. On read transaction expect first word to be zero. */ -#define BMI3_FEATURE_ENGINE_DMA_TX_DATA 0x42 - -/* Command for offset update */ -#define BMI3_CMD_USR_GAIN_OFFS_UPDATE 0x301 - -/* 1LSB - 31 Micro-G */ -#define BMI3_OFFSET_ACC_MULTI_MG (31 * 1000) - -/* 1LSB = 61 milli-dps*/ -#define BMI3_OFFSET_GYR_MDPS (61 * 1000) - -#define BMI3_FIFO_BUFFER 32 - -/* General Macro Definitions */ -/* LSB and MSB mask definitions */ -#define BMI3_SET_LOW_BYTE 0x00FF -#define BMI3_SET_HIGH_BYTE 0xFF00 - -/* For enable and disable */ -#define BMI3_ENABLE 0x1 -#define BMI3_DISABLE 0x0 - -/* Defines mode of operation for Accelerometer */ -#define BMI3_POWER_MODE_MASK 0x70 -#define BMI3_POWER_MODE_POS 4 - -#define BMI3_SENS_ODR_MASK 0x0F - -/* Full scale, Resolution */ -#define BMI3_SENS_RANGE_MASK 0x70 -#define BMI3_SENS_RANGE_POS 4 - -#define BMI3_CHIP_ID_MASK 0xFF - -/* Map FIFO water-mark interrupt to either INT1 or INT2 or IBI */ -#define BMI3_FWM_INT_MASK 0x30 -#define BMI3_FWM_INT_POS 4 - -/* Map FIFO full interrupt to either INT1 or INT2 or IBI */ -#define BMI3_FFULL_INT_MASK 0xC0 -#define BMI3_FFULL_INT_POS 6 - -#define BMI3_ORIENT_INT_MASK 0xC0 -#define BMI3_ORIENT_INT_POS 6 - - - -/* Mask definitions for interrupt pin configuration */ -#define BMI3_INT_LATCH_MASK 0x0001 - -/** - * Current fill level of FIFO buffer - * An empty FIFO corresponds to 0x000. The word counter may be reset by reading - * out all frames from the FIFO buffer or when the FIFO is reset through - * fifo_flush. The word counter is updated each time a complete frame was read - * or written. - */ -#define BMI3_FIFO_FILL_LVL_MASK 0x07FF - -/* Enum to define interrupt lines */ -enum bmi3_hw_int_pin { - BMI3_INT_NONE, - BMI3_INT1, - BMI3_INT2, - BMI3_I3C_INT, - BMI3_INT_PIN_MAX -}; - -/* Structure to define FIFO frame configuration */ -struct bmi3_fifo_frame { - uint16_t data[BMI3_FIFO_BUFFER + 1]; - - /* Available fifo length */ - uint16_t available_fifo_len; -}; - -enum sensor_index_t { - FIRST_CONT_SENSOR = 0, - SENSOR_ACCEL = FIRST_CONT_SENSOR, - SENSOR_GYRO, - NUM_OF_PRIMARY_SENSOR, -}; - -#define BMI3_DRDY_OFF(_sensor) (7 - (_sensor)) -#define BMI3_DRDY_MASK(_sensor) (1 << BMI3_DRDY_OFF(_sensor)) - -/* Utility macros */ -#define BMI3_SET_BITS(reg_data, bitname, data) \ - ((reg_data & ~(bitname##_MASK)) | \ - ((data << bitname##_POS) & bitname##_MASK)) - -#define BMI3_GET_BITS(reg_data, bitname) \ - ((reg_data & (bitname##_MASK)) >> \ - (bitname##_POS)) - -#define BMI3_SET_BIT_POS0(reg_data, bitname, data) \ - ((reg_data & ~(bitname##_MASK)) | \ - (data & bitname##_MASK)) - -#define BMI3_GET_BIT_POS0(reg_data, bitname) \ - (reg_data & (bitname##_MASK)) - -extern const struct accelgyro_drv bmi3xx_drv; - -void bmi3xx_interrupt(enum gpio_signal signal); - -#endif /* __CROS_EC_ACCELGYRO_BMI3XX_H */ diff --git a/driver/accelgyro_bmi_common.c b/driver/accelgyro_bmi_common.c deleted file mode 100644 index 2da407427e..0000000000 --- a/driver/accelgyro_bmi_common.c +++ /dev/null @@ -1,902 +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. - */ - -/** - * BMI accelerometer and gyro module for Chrome EC - * 3D digital accelerometer & 3D digital gyroscope - */ - - -#include "accelgyro.h" -#include "console.h" -#include "accelgyro_bmi_common.h" -#include "mag_bmm150.h" -#include "mag_lis2mdl.h" -#include "i2c.h" -#include "math_util.h" -#include "motion_sense_fifo.h" -#include "spi.h" - -#define CPUTS(outstr) cputs(CC_ACCEL, outstr) -#define CPRINTF(format, args...) cprintf(CC_ACCEL, format, ## args) -#define CPRINTS(format, args...) cprints(CC_ACCEL, format, ## args) - -#if !defined(CONFIG_ACCELGYRO_BMI160) && !defined(CONFIG_ACCELGYRO_BMI260) \ -&& !defined(CONFIG_ACCELGYRO_BMI3XX) -#error "Must use following sensors BMI160 BMI260 BMI3XX" -#endif - -#if defined(CONFIG_ACCELGYRO_BMI260) && !defined(CONFIG_ACCELGYRO_BMI160) -#define V(s_) 1 -#elif defined(CONFIG_ACCELGYRO_BMI160) && !defined(CONFIG_ACCELGYRO_BMI260) -#define V(s_) 0 -#else -#define V(s_) ((s_)->chip == MOTIONSENSE_CHIP_BMI260) -#endif -/* Index for which table to use. */ -#if !defined(CONFIG_ACCELGYRO_BMI160) || !defined(CONFIG_ACCELGYRO_BMI260) -#define T(s_) 0 -#else -#define T(s_) V(s_) -#endif - -/* List of range values in +/-G's and their associated register values. */ -const struct bmi_accel_param_pair g_ranges[][4] = { -#ifdef CONFIG_ACCELGYRO_BMI160 - { {2, BMI160_GSEL_2G}, - {4, BMI160_GSEL_4G}, - {8, BMI160_GSEL_8G}, - {16, BMI160_GSEL_16G} }, -#endif -#ifdef CONFIG_ACCELGYRO_BMI260 - { {2, BMI260_GSEL_2G}, - {4, BMI260_GSEL_4G}, - {8, BMI260_GSEL_8G}, - {16, BMI260_GSEL_16G} }, -#endif -}; - -/* - * List of angular rate range values in +/-dps's - * and their associated register values. - */ -const struct bmi_accel_param_pair dps_ranges[][5] = { -#ifdef CONFIG_ACCELGYRO_BMI160 - { {125, BMI160_DPS_SEL_125}, - {250, BMI160_DPS_SEL_250}, - {500, BMI160_DPS_SEL_500}, - {1000, BMI160_DPS_SEL_1000}, - {2000, BMI160_DPS_SEL_2000} }, -#endif -#ifdef CONFIG_ACCELGYRO_BMI260 - { {125, BMI260_DPS_SEL_125}, - {250, BMI260_DPS_SEL_250}, - {500, BMI260_DPS_SEL_500}, - {1000, BMI260_DPS_SEL_1000}, - {2000, BMI260_DPS_SEL_2000} }, -#endif -}; - -int bmi_get_xyz_reg(const struct motion_sensor_t *s) -{ - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - return BMI_ACC_DATA(V(s)); - case MOTIONSENSE_TYPE_GYRO: - return BMI_GYR_DATA(V(s)); - case MOTIONSENSE_TYPE_MAG: - return BMI_AUX_DATA(V(s)); - default: - return -1; - } -} - -const struct bmi_accel_param_pair *bmi_get_range_table( - const struct motion_sensor_t *s, int *psize) -{ - if (s->type == MOTIONSENSE_TYPE_ACCEL) { - if (psize) - *psize = ARRAY_SIZE(g_ranges[T(s)]); - return g_ranges[T(s)]; - } - if (psize) - *psize = ARRAY_SIZE(dps_ranges[T(s)]); - return dps_ranges[T(s)]; -} - -/** - * @return reg value that matches the given engineering value passed in. - * The round_up flag is used to specify whether to round up or down. - * Note, this function always returns a valid reg value. If the request is - * outside the range of values, it returns the closest valid reg value. - */ -int bmi_get_reg_val(const int eng_val, const int round_up, - const struct bmi_accel_param_pair *pairs, - const int size) -{ - int i; - - for (i = 0; i < size - 1; i++) { - if (eng_val <= pairs[i].val) - break; - - if (eng_val < pairs[i+1].val) { - if (round_up) - i += 1; - break; - } - } - return pairs[i].reg_val; -} - -/** - * @return engineering value that matches the given reg val - */ -int bmi_get_engineering_val(const int reg_val, - const struct bmi_accel_param_pair *pairs, - const int size) -{ - int i; - - for (i = 0; i < size; i++) { - if (reg_val == pairs[i].reg_val) - break; - } - return pairs[i].val; -} - -#ifdef CONFIG_ACCELGYRO_BMI_COMM_SPI -static int bmi_spi_raw_read(const int addr, const uint8_t reg, - uint8_t *data, const int len) -{ - uint8_t cmd = 0x80 | reg; - - return spi_transaction(&spi_devices[addr], &cmd, 1, data, len); -} -#endif - -/** - * Read 8bit register from accelerometer. - */ -int bmi_read8(const int port, const uint16_t i2c_spi_addr_flags, - const int reg, int *data_ptr) -{ - int rv; - -#ifdef CONFIG_ACCELGYRO_BMI_COMM_SPI - { - uint8_t val; - - rv = bmi_spi_raw_read(ACCEL_GET_SPI_ADDR(i2c_spi_addr_flags), - reg, &val, 1); - if (rv == EC_SUCCESS) - *data_ptr = val; - } -#else - rv = i2c_read8(port, i2c_spi_addr_flags, reg, data_ptr); -#endif - return rv; -} - -/** - * Write 8bit register from accelerometer. - */ -int bmi_write8(const int port, const uint16_t i2c_spi_addr_flags, - const int reg, int data) -{ - int rv; - -#ifdef CONFIG_ACCELGYRO_BMI_COMM_SPI - { - uint8_t cmd[2] = { reg, data }; - - rv = spi_transaction( - &spi_devices[ACCEL_GET_SPI_ADDR(i2c_spi_addr_flags)], - cmd, 2, NULL, 0); - } -#else - rv = i2c_write8(port, i2c_spi_addr_flags, reg, data); -#endif - /* - * From Bosch: BMI needs a delay of 450us after each write if it - * is in suspend mode, otherwise the operation may be ignored by - * the sensor. Given we are only doing write during init, add - * the delay unconditionally. - */ - msleep(1); - - return rv; -} - -/** - * Read 16bit register from accelerometer. - */ -int bmi_read16(const int port, const uint16_t i2c_spi_addr_flags, - const uint8_t reg, int *data_ptr) -{ -#ifdef CONFIG_ACCELGYRO_BMI_COMM_SPI - return bmi_spi_raw_read(ACCEL_GET_SPI_ADDR(i2c_spi_addr_flags), reg, - (uint8_t *)data_ptr, 2); -#else - return i2c_read16(port, i2c_spi_addr_flags, reg, data_ptr); -#endif -} - -/** - * Write 16bit register from accelerometer. - */ -int bmi_write16(const int port, const uint16_t i2c_spi_addr_flags, - const int reg, int data) -{ - int rv = -EC_ERROR_PARAM1; - -#ifdef CONFIG_ACCELGYRO_BMI_COMM_SPI - CPRINTS("%s() spi part is not implemented", __func__); -#else - rv = i2c_write16(port, i2c_spi_addr_flags, reg, data); -#endif - /* - * From Bosch: BMI needs a delay of 450us after each write if it - * is in suspend mode, otherwise the operation may be ignored by - * the sensor. Given we are only doing write during init, add - * the delay unconditionally. - */ - msleep(1); - return rv; -} - -/** - * Read 32bit register from accelerometer. - */ -int bmi_read32(const int port, const uint16_t i2c_spi_addr_flags, - const uint8_t reg, int *data_ptr) -{ -#ifdef CONFIG_ACCELGYRO_BMI_COMM_SPI - return bmi_spi_raw_read(ACCEL_GET_SPI_ADDR(i2c_spi_addr_flags), reg, - (uint8_t *)data_ptr, 4); -#else - return i2c_read32(port, i2c_spi_addr_flags, reg, data_ptr); -#endif -} - -/** - * Read n bytes from accelerometer. - */ -int bmi_read_n(const int port, const uint16_t i2c_spi_addr_flags, - const uint8_t reg, uint8_t *data_ptr, const int len) -{ -#ifdef CONFIG_ACCELGYRO_BMI_COMM_SPI - return bmi_spi_raw_read(ACCEL_GET_SPI_ADDR(i2c_spi_addr_flags), reg, - data_ptr, len); -#else - return i2c_read_block(port, i2c_spi_addr_flags, reg, data_ptr, len); -#endif -} - -/** - * Write n bytes from accelerometer. - */ -int bmi_write_n(const int port, const uint16_t i2c_spi_addr_flags, - const uint8_t reg, const uint8_t *data_ptr, const int len) -{ - int rv = -EC_ERROR_PARAM1; - -#ifdef CONFIG_ACCELGYRO_BMI_COMM_SPI - CPRINTS("%s() spi part is not implemented", __func__); -#else - rv = i2c_write_block(port, i2c_spi_addr_flags, reg, data_ptr, len); -#endif - /* - * From Bosch: BMI needs a delay of 450us after each write if it - * is in suspend mode, otherwise the operation may be ignored by - * the sensor. Given we are only doing write during init, add - * the delay unconditionally. - */ - msleep(1); - - return rv; -} -/* - * Enable/Disable specific bit set of a 8-bit reg. - */ -int bmi_enable_reg8(const struct motion_sensor_t *s, int reg, uint8_t bits, - int enable) -{ - if (enable) - return bmi_set_reg8(s, reg, bits, 0); - return bmi_set_reg8(s, reg, 0, bits); -} - -/* - * Set specific bit set to certain value of a 8-bit reg. - */ -int bmi_set_reg8(const struct motion_sensor_t *s, int reg, uint8_t bits, - int mask) -{ - int ret, val; - - ret = bmi_read8(s->port, s->i2c_spi_addr_flags, reg, &val); - if (ret) - return ret; - val = (val & ~mask) | bits; - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, reg, val); - return ret; -} - -void bmi_normalize(const struct motion_sensor_t *s, intv3_t v, uint8_t *input) -{ - int i; - struct accelgyro_saved_data_t *data = BMI_GET_SAVED_DATA(s); - - if (IS_ENABLED(CONFIG_MAG_BMI_BMM150) && - (s->type == MOTIONSENSE_TYPE_MAG)) { - bmm150_normalize(s, v, input); - } else if (IS_ENABLED(CONFIG_MAG_BMI_LIS2MDL) && - (s->type == MOTIONSENSE_TYPE_MAG)) { - lis2mdl_normalize(s, v, input); - } else { - v[0] = ((int16_t)((input[1] << 8) | input[0])); - v[1] = ((int16_t)((input[3] << 8) | input[2])); - v[2] = ((int16_t)((input[5] << 8) | input[4])); - } - rotate(v, *s->rot_standard_ref, v); - for (i = X; i <= Z; i++) - v[i] = SENSOR_APPLY_SCALE(v[i], data->scale[i]); -} - -int bmi_decode_header(struct motion_sensor_t *accel, enum fifo_header hdr, - uint32_t last_ts, uint8_t **bp, uint8_t *ep) -{ - if ((hdr & BMI_FH_MODE_MASK) == BMI_FH_EMPTY && - (hdr & BMI_FH_PARM_MASK) != 0) { - int i, size = 0; - /* Check if there is enough space for the data frame */ - for (i = MOTIONSENSE_TYPE_MAG; i >= MOTIONSENSE_TYPE_ACCEL; - i--) { - if (hdr & (1 << (i + BMI_FH_PARM_OFFSET))) - size += (i == MOTIONSENSE_TYPE_MAG ? 8 : 6); - } - if (*bp + size > ep) { - /* frame is not complete, it will be retransmitted. */ - *bp = ep; - return 1; - } - for (i = MOTIONSENSE_TYPE_MAG; i >= MOTIONSENSE_TYPE_ACCEL; - i--) { - struct motion_sensor_t *s = accel + i; - - if (hdr & (1 << (i + BMI_FH_PARM_OFFSET))) { - struct ec_response_motion_sensor_data vector; - int *v = s->raw_xyz; - - vector.flags = 0; - bmi_normalize(s, v, *bp); - if (IS_ENABLED(CONFIG_ACCEL_SPOOF_MODE) && - s->flags & MOTIONSENSE_FLAG_IN_SPOOF_MODE) - v = s->spoof_xyz; - vector.data[X] = v[X]; - vector.data[Y] = v[Y]; - vector.data[Z] = v[Z]; - vector.sensor_num = s - motion_sensors; - motion_sense_fifo_stage_data(&vector, s, 3, - last_ts); - *bp += (i == MOTIONSENSE_TYPE_MAG ? 8 : 6); - } - } - - return 1; - } else { - return 0; - } -} - -enum fifo_state { - FIFO_HEADER, - FIFO_DATA_SKIP, - FIFO_DATA_TIME, - FIFO_DATA_CONFIG, -}; - -#define BMI_FIFO_BUFFER 64 -static uint8_t bmi_buffer[BMI_FIFO_BUFFER]; - -int bmi_load_fifo(struct motion_sensor_t *s, uint32_t last_ts) -{ - struct bmi_drv_data_t *data = BMI_GET_DATA(s); - uint16_t length; - enum fifo_state state = FIFO_HEADER; - uint8_t *bp = bmi_buffer; - uint8_t *ep; - uint32_t beginning; - - if (s->type != MOTIONSENSE_TYPE_ACCEL) - return EC_SUCCESS; - - if (!(data->flags & (BMI_FIFO_ALL_MASK << BMI_FIFO_FLAG_OFFSET))) { - /* - * The FIFO was disabled while we were processing it. - * - * Flush potential left over: - * When sensor is resumed, we won't read old data. - */ - bmi_write8(s->port, s->i2c_spi_addr_flags, BMI_CMD_REG(V(s)), - BMI_CMD_FIFO_FLUSH); - return EC_SUCCESS; - } - - bmi_read_n(s->port, s->i2c_spi_addr_flags, BMI_FIFO_LENGTH_0(V(s)), - (uint8_t *)&length, sizeof(length)); - length &= BMI_FIFO_LENGTH_MASK(V(s)); - - /* - * We have not requested timestamp, no extra frame to read. - * if we have too much to read, read the whole buffer. - */ - if (length == 0) { - /* - * Disable this message on BMI260, due to this seems to always - * happen after we complete to read the data. - * TODO(chingkang): check why this happen on BMI260. - */ - if (V(s) == 0) - CPRINTS("unexpected empty FIFO"); - return EC_SUCCESS; - } - - /* Add one byte to get an empty FIFO frame.*/ - length++; - - if (length > sizeof(bmi_buffer)) - CPRINTS("unexpected large FIFO: %d", length); - length = MIN(length, sizeof(bmi_buffer)); - - bmi_read_n(s->port, s->i2c_spi_addr_flags, BMI_FIFO_DATA(V(s)), - bmi_buffer, length); - beginning = *(uint32_t *)bmi_buffer; - ep = bmi_buffer + length; - /* - * FIFO is invalid when reading while the sensors are all - * suspended. - * Instead of returning the empty frame, it can return a - * pattern that looks like a valid header: 84 or 40. - * If we see those, assume the sensors have been disabled - * while this thread was running. - */ - if (beginning == 0x84848484 || (beginning & 0xdcdcdcdc) == 0x40404040) { - CPRINTS("Suspended FIFO: accel ODR/rate: %d/%d: 0x%08x", - BASE_ODR(s->config[SENSOR_CONFIG_AP].odr), - BMI_GET_SAVED_DATA(s)->odr, beginning); - return EC_SUCCESS; - } - - while (bp < ep) { - switch (state) { - case FIFO_HEADER: { - enum fifo_header hdr = *bp++; - - if (bmi_decode_header(s, hdr, last_ts, &bp, ep)) - continue; - /* Other cases */ - hdr &= 0xdc; - switch (hdr) { - case BMI_FH_EMPTY: - return EC_SUCCESS; - case BMI_FH_SKIP: - state = FIFO_DATA_SKIP; - break; - case BMI_FH_TIME: - state = FIFO_DATA_TIME; - break; - case BMI_FH_CONFIG: - state = FIFO_DATA_CONFIG; - break; - default: - CPRINTS("Unknown header: 0x%02x @ %zd", hdr, - bp - bmi_buffer); - bmi_write8(s->port, s->i2c_spi_addr_flags, - BMI_CMD_REG(V(s)), - BMI_CMD_FIFO_FLUSH); - return EC_ERROR_NOT_HANDLED; - } - break; - } - case FIFO_DATA_SKIP: - CPRINTS("@ %zd - %d, skipped %d frames", - bp - bmi_buffer, length, *bp); - bp++; - state = FIFO_HEADER; - break; - case FIFO_DATA_CONFIG: - CPRINTS("@ %zd - %d, config change: 0x%02x", - bp - bmi_buffer, length, *bp); - bp++; - if (V(s)) - state = FIFO_DATA_TIME; - else - state = FIFO_HEADER; - break; - case FIFO_DATA_TIME: - if (bp + 3 > ep) { - bp = ep; - continue; - } - /* We are not requesting timestamp */ - CPRINTS("timestamp %d", - (bp[2] << 16) | (bp[1] << 8) | bp[0]); - state = FIFO_HEADER; - bp += 3; - break; - default: - CPRINTS("Unknown data: 0x%02x", *bp++); - state = FIFO_HEADER; - } - } - - return EC_SUCCESS; -} - -int bmi_set_range(struct motion_sensor_t *s, int range, int rnd) -{ - int ret, range_tbl_size; - uint8_t reg_val, ctrl_reg; - const struct bmi_accel_param_pair *ranges; - - if (s->type == MOTIONSENSE_TYPE_MAG) { - s->current_range = range; - return EC_SUCCESS; - } - - ctrl_reg = BMI_RANGE_REG(s->type); - ranges = bmi_get_range_table(s, &range_tbl_size); - reg_val = bmi_get_reg_val(range, rnd, ranges, range_tbl_size); - - ret = bmi_write8(s->port, s->i2c_spi_addr_flags, ctrl_reg, reg_val); - /* Now that we have set the range, update the driver's value. */ - if (ret == EC_SUCCESS) - s->current_range = bmi_get_engineering_val(reg_val, ranges, - range_tbl_size); - return ret; -} - -int bmi_get_data_rate(const struct motion_sensor_t *s) -{ - struct accelgyro_saved_data_t *data = BMI_GET_SAVED_DATA(s); - - return data->odr; -} - -int bmi_get_offset(const struct motion_sensor_t *s, int16_t *offset, - int16_t *temp) -{ - int i, ret = EC_SUCCESS; - intv3_t v; - - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - /* - * The offset of the accelerometer off_acc_[xyz] is a 8 bit - * two-complement number in units of 3.9 mg independent of the - * range selected for the accelerometer. - */ - ret = bmi_accel_get_offset(s, v); - break; - case MOTIONSENSE_TYPE_GYRO: - /* - * The offset of the gyroscope off_gyr_[xyz] is a 10 bit - * two-complement number in units of 0.061 °/s. - * Therefore a maximum range that can be compensated is - * -31.25 °/s to +31.25 °/s - */ - ret = bmi_gyro_get_offset(s, v); - break; -#ifdef CONFIG_MAG_BMI_BMM150 - case MOTIONSENSE_TYPE_MAG: - ret = bmm150_get_offset(s, v); - break; -#endif /* defined(CONFIG_MAG_BMI_BMM150) */ - default: - for (i = X; i <= Z; i++) - v[i] = 0; - } - - if (ret != EC_SUCCESS) - return ret; - - rotate(v, *s->rot_standard_ref, v); - offset[X] = v[X]; - offset[Y] = v[Y]; - offset[Z] = v[Z]; - /* Saving temperature at calibration not supported yet */ - *temp = EC_MOTION_SENSE_INVALID_CALIB_TEMP; - return EC_SUCCESS; -} - -#ifdef CONFIG_BODY_DETECTION -int bmi_get_rms_noise(const struct motion_sensor_t *s) -{ - int ret; - fp_t noise_100hz, rate, sqrt_rate_ratio; - - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - /* change unit of ODR to Hz to prevent INT_TO_FP() overflow */ - rate = INT_TO_FP(bmi_get_data_rate(s) / 1000); - /* - * Since the noise is proportional to sqrt(ODR) in BMI, and we - * have rms noise in 100 Hz, we multiply it with the sqrt(ratio - * of ODR to 100Hz) to get current noise. - */ - noise_100hz = INT_TO_FP(BMI_ACCEL_RMS_NOISE_100HZ(V(s))); - sqrt_rate_ratio = - fp_sqrtf(fp_div(rate, INT_TO_FP(BMI_ACCEL_100HZ))); - ret = FP_TO_INT(fp_mul(noise_100hz, sqrt_rate_ratio)); - break; - default: - CPRINTS("%s with gyro/mag is not implemented", __func__); - return 0; - } - return ret; -} -#endif - -int bmi_get_resolution(const struct motion_sensor_t *s) -{ - return BMI_RESOLUTION; -} - -int bmi_set_scale(const struct motion_sensor_t *s, const uint16_t *scale, - int16_t temp) -{ - struct accelgyro_saved_data_t *data = BMI_GET_SAVED_DATA(s); - - data->scale[X] = scale[X]; - data->scale[Y] = scale[Y]; - data->scale[Z] = scale[Z]; - return EC_SUCCESS; -} - -int bmi_get_scale(const struct motion_sensor_t *s, uint16_t *scale, - int16_t *temp) -{ - struct accelgyro_saved_data_t *data = BMI_GET_SAVED_DATA(s); - - scale[X] = data->scale[X]; - scale[Y] = data->scale[Y]; - scale[Z] = data->scale[Z]; - *temp = EC_MOTION_SENSE_INVALID_CALIB_TEMP; - return EC_SUCCESS; -} - -int bmi_enable_fifo(const struct motion_sensor_t *s, int enable) -{ - struct bmi_drv_data_t *data = BMI_GET_DATA(s); - int ret; - - /* FIFO start/stop collecting events */ - ret = bmi_enable_reg8(s, BMI_FIFO_CONFIG_1(V(s)), - BMI_FIFO_SENSOR_EN(V(s), s->type), enable); - if (ret) - return ret; - - if (enable) - data->flags |= 1 << (s->type + BMI_FIFO_FLAG_OFFSET); - else - data->flags &= ~(1 << (s->type + BMI_FIFO_FLAG_OFFSET)); - - return ret; -} - -int bmi_read(const struct motion_sensor_t *s, intv3_t v) -{ - uint8_t data[6]; - int ret, status = 0; - - ret = bmi_read8(s->port, s->i2c_spi_addr_flags, BMI_STATUS(V(s)), - &status); - if (ret != EC_SUCCESS) - return ret; - - /* - * If sensor data is not ready, return the previous read data. - * Note: return success so that motion senor task can read again - * to get the latest updated sensor data quickly. - */ - if (!(status & BMI_DRDY_MASK(s->type))) { - if (v != s->raw_xyz) - memcpy(v, s->raw_xyz, sizeof(s->raw_xyz)); - return EC_SUCCESS; - } - - /* Read 6 bytes starting at xyz_reg */ - ret = bmi_read_n(s->port, s->i2c_spi_addr_flags, bmi_get_xyz_reg(s), - data, 6); - - if (ret != EC_SUCCESS) { - CPRINTS("%s: type:0x%X RD XYZ Error %d", s->name, s->type, ret); - return ret; - } - bmi_normalize(s, v, data); - return EC_SUCCESS; -} - -int bmi_read_temp(const struct motion_sensor_t *s, int *temp_ptr) -{ - return bmi_get_sensor_temp(s - motion_sensors, temp_ptr); -} - -int bmi_get_sensor_temp(int idx, int *temp_ptr) -{ - struct motion_sensor_t *s = &motion_sensors[idx]; - int16_t temp; - int ret; - - ret = bmi_read_n(s->port, s->i2c_spi_addr_flags, - BMI_TEMPERATURE_0(V(s)), (uint8_t *)&temp, - sizeof(temp)); - - if (ret || temp == (int16_t)BMI_INVALID_TEMP) - return EC_ERROR_NOT_POWERED; - - *temp_ptr = C_TO_K(23 + ((temp + 256) >> 9)); - return 0; -} - -int bmi_get_normalized_rate(const struct motion_sensor_t *s, int rate, int rnd, - int *normalized_rate_ptr, uint8_t *reg_val_ptr) -{ - *reg_val_ptr = BMI_ODR_TO_REG(rate); - *normalized_rate_ptr = BMI_REG_TO_ODR(*reg_val_ptr); - if (rnd && (*normalized_rate_ptr < rate)) { - (*reg_val_ptr)++; - *normalized_rate_ptr = BMI_REG_TO_ODR(*reg_val_ptr); - } - - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - if (*normalized_rate_ptr > BMI_ACCEL_MAX_FREQ || - *normalized_rate_ptr < BMI_ACCEL_MIN_FREQ) - return EC_RES_INVALID_PARAM; - break; - case MOTIONSENSE_TYPE_GYRO: - if (*normalized_rate_ptr > BMI_GYRO_MAX_FREQ || - *normalized_rate_ptr < BMI_GYRO_MIN_FREQ) - return EC_RES_INVALID_PARAM; - break; -#ifdef CONFIG_MAG_BMI_BMM150 - case MOTIONSENSE_TYPE_MAG: - /* We use the regular preset we can go about 100Hz */ - if (*reg_val_ptr > BMI_ODR_100HZ || - *reg_val_ptr < BMI_ODR_0_78HZ) - return EC_RES_INVALID_PARAM; - break; -#endif - - default: - return EC_RES_INVALID_PARAM; - } - return EC_SUCCESS; -} - -int bmi_accel_get_offset(const struct motion_sensor_t *accel, intv3_t v) -{ - int i, val, ret; - - for (i = X; i <= Z; i++) { - ret = bmi_read8(accel->port, accel->i2c_spi_addr_flags, - BMI_OFFSET_ACC70(V(accel)) + i, &val); - if (ret != EC_SUCCESS) - return ret; - - if (val > 0x7f) - val = -256 + val; - v[i] = round_divide((int64_t)val * BMI_OFFSET_ACC_MULTI_MG, - BMI_OFFSET_ACC_DIV_MG); - } - - return EC_SUCCESS; -} - -int bmi_gyro_get_offset(const struct motion_sensor_t *gyro, intv3_t v) -{ - int i, val, val98, ret; - - /* Read the MSB first */ - ret = bmi_read8(gyro->port, gyro->i2c_spi_addr_flags, - BMI_OFFSET_EN_GYR98(V(gyro)), &val98); - if (ret != EC_SUCCESS) - return ret; - - for (i = X; i <= Z; i++) { - ret = bmi_read8(gyro->port, gyro->i2c_spi_addr_flags, - BMI_OFFSET_GYR70(V(gyro)) + i, &val); - if (ret != EC_SUCCESS) - return ret; - - val |= ((val98 >> (2 * i)) & 0x3) << 8; - if (val > 0x1ff) - val = -1024 + val; - v[i] = round_divide((int64_t)val * BMI_OFFSET_GYRO_MULTI_MDS, - BMI_OFFSET_GYRO_DIV_MDS); - } - - return EC_SUCCESS; -} - -int bmi_set_accel_offset(const struct motion_sensor_t *accel, intv3_t v) -{ - int i, val, ret; - - for (i = X; i <= Z; ++i) { - val = round_divide((int64_t)v[i] * BMI_OFFSET_ACC_DIV_MG, - BMI_OFFSET_ACC_MULTI_MG); - if (val > 127) - val = 127; - if (val < -128) - val = -128; - if (val < 0) - val = 256 + val; - ret = bmi_write8(accel->port, accel->i2c_spi_addr_flags, - BMI_OFFSET_ACC70(V(accel)) + i, val); - if (ret != EC_SUCCESS) - return ret; - } - - return EC_SUCCESS; -} - -int bmi_set_gyro_offset(const struct motion_sensor_t *gyro, intv3_t v, - int *val98_ptr) -{ - int i, val, ret; - - for (i = X; i <= Z; i++) { - val = round_divide((int64_t)v[i] * BMI_OFFSET_GYRO_DIV_MDS, - BMI_OFFSET_GYRO_MULTI_MDS); - if (val > 511) - val = 511; - if (val < -512) - val = -512; - if (val < 0) - val = 1024 + val; - ret = bmi_write8(gyro->port, gyro->i2c_spi_addr_flags, - BMI_OFFSET_GYR70(V(gyro)) + i, val & 0xFF); - if (ret != EC_SUCCESS) - return ret; - - *val98_ptr &= ~(0x3 << (2 * i)); - *val98_ptr |= (val >> 8) << (2 * i); - } - - return EC_SUCCESS; -} - -#ifdef CONFIG_BMI_ORIENTATION_SENSOR -bool motion_orientation_changed(const struct motion_sensor_t *s) -{ - return BMI_GET_DATA(s)->orientation != - BMI_GET_DATA(s)->last_orientation; -} - -enum motionsensor_orientation * -motion_orientation_ptr(const struct motion_sensor_t *s) -{ - return &BMI_GET_DATA(s)->orientation; -} - -void motion_orientation_update(const struct motion_sensor_t *s) -{ - BMI_GET_DATA(s)->last_orientation = BMI_GET_DATA(s)->orientation; -} -#endif - -int bmi_list_activities(const struct motion_sensor_t *s, - uint32_t *enabled, - uint32_t *disabled) -{ - struct bmi_drv_data_t *data = BMI_GET_DATA(s); - *enabled = data->enabled_activities; - *disabled = data->disabled_activities; - return EC_RES_SUCCESS; -} diff --git a/driver/accelgyro_icm42607.c b/driver/accelgyro_icm42607.c deleted file mode 100644 index ae831c5918..0000000000 --- a/driver/accelgyro_icm42607.c +++ /dev/null @@ -1,1132 +0,0 @@ -/* Copyright 2021 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. - */ - -/** - * ICM-42607 accelerometer and gyroscope module for Chrome EC - * 3D digital accelerometer & 3D digital gyroscope - */ - -#include "accelgyro.h" -#include "console.h" -#include "driver/accelgyro_icm_common.h" -#include "driver/accelgyro_icm42607.h" -#include "hwtimer.h" -#include "i2c.h" -#include "math_util.h" -#include "motion_sense.h" -#include "motion_sense_fifo.h" -#include "spi.h" -#include "task.h" -#include "timer.h" -#include "util.h" - -#define CPUTS(outstr) cputs(CC_ACCEL, outstr) -#define CPRINTF(format, args...) cprintf(CC_ACCEL, format, ## args) -#define CPRINTS(format, args...) cprints(CC_ACCEL, format, ## args) - -STATIC_IF(CONFIG_ACCEL_FIFO) volatile uint32_t last_interrupt_timestamp; - -static int icm_switch_on_mclk(const struct motion_sensor_t *s) -{ - int val; - int i, ret; - - ret = icm_field_update8(s, ICM42607_REG_PWR_MGMT0, ICM42607_IDLE, - ICM42607_IDLE); - if (ret) - return ret; - - /* Check if MCLK is ready */ - for (i = 0; i < 10; ++i) { - ret = icm_read8(s, ICM42607_REG_MCLK_RDY, &val); - if (ret) - return ret; - - if (val & ICM42607_MCLK_RDY) - return EC_SUCCESS; - } - - return EC_ERROR_HW_INTERNAL; -} - -static int icm_switch_off_mclk(const struct motion_sensor_t *s) -{ - return icm_field_update8(s, ICM42607_REG_PWR_MGMT0, ICM42607_IDLE, 0); -} - -static int icm_read_mclk_reg(const struct motion_sensor_t *s, const int reg, - int *buf) -{ - const int blk_sel = (reg & 0xFF00) >> 8; - const int val = reg & 0x00FF; - int ret; - - /* optimize by changing BLK_SEL only if not 0 */ - if (blk_sel) { - ret = icm_write8(s, ICM42607_REG_BLK_SEL_R, blk_sel); - if (ret) - return ret; - } - - ret = icm_write8(s, ICM42607_REG_MADDR_R, val); - if (ret) - return ret; - - udelay(10); - - ret = icm_read8(s, ICM42607_REG_M_R, buf); - if (ret) - return ret; - - udelay(10); - - if (blk_sel) { - ret = icm_write8(s, ICM42607_REG_BLK_SEL_R, 0); - if (ret) - return ret; - } - - return EC_SUCCESS; -} - -static int icm_write_mclk_reg(const struct motion_sensor_t *s, const int reg, - const int buf) -{ - const int blk_sel = (reg & 0xFF00) >> 8; - const int val = reg & 0x00FF; - int ret; - - /* optimize by changing BLK_SEL only if not 0 */ - if (blk_sel) { - ret = icm_write8(s, ICM42607_REG_BLK_SEL_W, blk_sel); - if (ret) - return ret; - } - - ret = icm_write8(s, ICM42607_REG_MADDR_W, val); - if (ret) - return ret; - - ret = icm_write8(s, ICM42607_REG_M_W, buf); - if (ret) - return ret; - - udelay(10); - - if (blk_sel) { - ret = icm_write8(s, ICM42607_REG_BLK_SEL_W, 0); - if (ret) - return ret; - } - - return EC_SUCCESS; -} - -static int icm_field_update_mclk_reg(const struct motion_sensor_t *s, - const int reg, const uint8_t field_mask, - const uint8_t set_value) -{ - int val, ret; - - ret = icm_read_mclk_reg(s, reg, &val); - if (ret) - return ret; - - val = (val & ~field_mask) | set_value; - - return icm_write_mclk_reg(s, reg, val); -} - -static int icm42607_normalize(const struct motion_sensor_t *s, intv3_t v, - const uint8_t *raw) -{ - struct accelgyro_saved_data_t *data = ICM_GET_SAVED_DATA(s); - int i; - - /* sensor data is configured as little-endian */ - v[X] = (int16_t)UINT16_FROM_BYTE_ARRAY_LE(raw, 0); - v[Y] = (int16_t)UINT16_FROM_BYTE_ARRAY_LE(raw, 2); - v[Z] = (int16_t)UINT16_FROM_BYTE_ARRAY_LE(raw, 4); - - /* check if data is valid */ - if (v[X] == ICM42607_INVALID_DATA && - v[Y] == ICM42607_INVALID_DATA && - v[Z] == ICM42607_INVALID_DATA) { - return EC_ERROR_INVAL; - } - - rotate(v, *s->rot_standard_ref, v); - - for (i = X; i <= Z; i++) - v[i] = SENSOR_APPLY_SCALE(v[i], data->scale[i]); - - return EC_SUCCESS; -} - -static int icm42607_check_sensor_stabilized(const struct motion_sensor_t *s, - uint32_t ts) -{ - int32_t rem; - - rem = icm_get_sensor_stabilized(s, ts); - if (rem == 0) - return EC_SUCCESS; - if (rem > 0) - return EC_ERROR_BUSY; - - /* rem < 0: reset check since ts has passed stabilize_ts */ - icm_reset_stabilize_ts(s); - return EC_SUCCESS; -} - -static int __maybe_unused icm42607_flush_fifo(const struct motion_sensor_t *s) -{ - int i, val, ret; - - ret = icm_write8(s, ICM42607_REG_SIGNAL_PATH_RESET, - ICM42607_FIFO_FLUSH); - if (ret) - return ret; - - udelay(10); - - for (i = 0; i < 10; ++i) { - ret = icm_read8(s, ICM42607_REG_SIGNAL_PATH_RESET, &val); - if (ret) - return ret; - - if (!(val & ICM42607_FIFO_FLUSH)) - return EC_SUCCESS; - - udelay(1); - } - - return EC_ERROR_HW_INTERNAL; -} - -/* use FIFO threshold interrupt on INT1 */ -#define ICM42607_FIFO_INT_EN ICM42607_FIFO_THS_INT1_EN -#define ICM42607_FIFO_INT_STATUS ICM42607_FIFO_THS_INT - -static int __maybe_unused icm42607_enable_fifo(const struct motion_sensor_t *s, - int enable) -{ - int ret; - - if (enable) { - /* enable FIFO interrupts */ - ret = icm_field_update8(s, ICM42607_REG_INT_SOURCE0, - ICM42607_FIFO_INT_EN, - ICM42607_FIFO_INT_EN); - if (ret) - return ret; - - /* enable FIFO in streaming mode */ - ret = icm_write8(s, ICM42607_REG_FIFO_CONFIG1, - ICM42607_FIFO_MODE_STREAM); - if (ret) - return ret; - } else { - /* disable FIFO interrupts */ - ret = icm_field_update8(s, ICM42607_REG_INT_SOURCE0, - ICM42607_FIFO_INT_EN, 0); - if (ret) - return ret; - - /* set FIFO in bypass mode */ - ret = icm_write8(s, ICM42607_REG_FIFO_CONFIG1, - ICM42607_FIFO_BYPASS); - if (ret) - return ret; - - /* flush FIFO data */ - ret = icm42607_flush_fifo(s); - if (ret) - return ret; - } - - return EC_SUCCESS; -} - -static int __maybe_unused icm42607_config_fifo(const struct motion_sensor_t *s, - int enable) -{ - struct icm_drv_data_t *st = ICM_GET_DATA(s); - int val; - uint8_t old_fifo_en, fifo_en; - int ret; - - mutex_lock(s->mutex); - - /* compute new FIFO enable bits and update FIFO config */ - fifo_en = st->fifo_en; - if (enable) - fifo_en |= BIT(s->type); - else - fifo_en &= ~BIT(s->type); - - val = ICM42607_FIFO_WM_GT_TH; - if (fifo_en & BIT(MOTIONSENSE_TYPE_ACCEL)) - val |= ICM42607_FIFO_ACCEL_EN; - if (fifo_en & BIT(MOTIONSENSE_TYPE_GYRO)) - val |= ICM42607_FIFO_GYRO_EN; - - ret = icm_switch_on_mclk(s); - if (ret) - goto out_unlock; - - ret = icm_write_mclk_reg(s, ICM42607_MREG_FIFO_CONFIG5, val); - if (ret) - goto out_unlock; - - ret = icm_switch_off_mclk(s); - if (ret) - goto out_unlock; - - old_fifo_en = st->fifo_en; - st->fifo_en = fifo_en; - - if (!old_fifo_en && st->fifo_en) { - /* 1st sensor enabled => turn FIFO on */ - ret = icm42607_enable_fifo(s, 1); - if (ret != EC_SUCCESS) - goto out_unlock; - } else if (old_fifo_en && !st->fifo_en) { - /* last sensor disabled => turn FIFO off */ - ret = icm42607_enable_fifo(s, 0); - if (ret != EC_SUCCESS) - goto out_unlock; - } - -out_unlock: - mutex_unlock(s->mutex); - return ret; -} - -static void __maybe_unused icm42607_push_fifo_data(struct motion_sensor_t *s, - const uint8_t *raw, uint32_t ts) -{ - intv3_t v; - struct ec_response_motion_sensor_data vect; - int ret; - - if (s == NULL) - return; - - ret = icm42607_normalize(s, v, raw); - if (ret == EC_SUCCESS) { - vect.data[X] = v[X]; - vect.data[Y] = v[Y]; - vect.data[Z] = v[Z]; - vect.flags = 0; - vect.sensor_num = s - motion_sensors; - motion_sense_fifo_stage_data(&vect, s, 3, ts); - } -} - -static int __maybe_unused icm42607_load_fifo(struct motion_sensor_t *s, - uint32_t ts) -{ - struct icm_drv_data_t *st = ICM_GET_DATA(s); - int count, i, size; - const uint8_t *accel, *gyro; - int ret; - - ret = icm_read16(s, ICM42607_REG_FIFO_COUNT, &count); - if (ret != EC_SUCCESS) - return ret; - - if (count <= 0) - return EC_ERROR_INVAL; - - /* flush FIFO if buffer is not large enough */ - if (count > ICM_FIFO_BUFFER) { - CPRINTS("It should not happen, the EC is too slow for the ODR"); - /* flush FIFO data */ - ret = icm42607_flush_fifo(s); - if (ret) - return ret; - - return EC_ERROR_OVERFLOW; - } - - ret = icm_read_n(s, ICM42607_REG_FIFO_DATA, st->fifo_buffer, count); - if (ret != EC_SUCCESS) - return ret; - - for (i = 0; i < count; i += size) { - size = icm_fifo_decode_packet(&st->fifo_buffer[i], - &accel, &gyro); - /* exit if error or FIFO is empty */ - if (size <= 0) - return -size; - if (accel != NULL) { - ret = icm42607_check_sensor_stabilized(s, ts); - if (ret == EC_SUCCESS) - icm42607_push_fifo_data(s, accel, ts); - } - if (gyro != NULL) { - ret = icm42607_check_sensor_stabilized(s + 1, ts); - if (ret == EC_SUCCESS) - icm42607_push_fifo_data(s + 1, gyro, ts); - } - } - - return EC_SUCCESS; -} - -#ifdef CONFIG_ACCEL_INTERRUPTS - -/** - * icm42607_interrupt - called when the sensor activates the interrupt line. - * - * This is a "top half" interrupt handler, it just asks motion sense ask - * to schedule the "bottom half", ->icm42607_irq_handler(). - */ -void icm42607_interrupt(enum gpio_signal signal) -{ - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) - last_interrupt_timestamp = __hw_clock_source_read(); - - task_set_event(TASK_ID_MOTIONSENSE, - CONFIG_ACCELGYRO_ICM42607_INT_EVENT); -} - -/** - * icm42607_irq_handler - bottom half of the interrupt stack. - * Ran from the motion_sense task, finds the events that raised the interrupt. - */ -static int icm42607_irq_handler(struct motion_sensor_t *s, uint32_t *event) -{ - int status; - int ret; - - if ((s->type != MOTIONSENSE_TYPE_ACCEL) || - (!(*event & CONFIG_ACCELGYRO_ICM42607_INT_EVENT))) - return EC_ERROR_NOT_HANDLED; - - mutex_lock(s->mutex); - - /* read and clear interrupt status */ - ret = icm_read8(s, ICM42607_REG_INT_STATUS, &status); - if (ret != EC_SUCCESS) - goto out_unlock; - - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) { - if (status & ICM42607_FIFO_INT_STATUS) { - ret = icm42607_load_fifo(s, last_interrupt_timestamp); - if (ret == EC_SUCCESS) - motion_sense_fifo_commit_data(); - } - } - -out_unlock: - mutex_unlock(s->mutex); - return ret; -} - -static int icm42607_config_interrupt(const struct motion_sensor_t *s) -{ - struct icm_drv_data_t *st = ICM_GET_DATA(s); - int val, mask, ret; - - /* configure INT1 pin: push-pull active low */ - ret = icm_write8(s, ICM42607_REG_INT_CONFIG, ICM42607_INT1_PUSH_PULL); - if (ret != EC_SUCCESS) - return ret; - - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) { - /* configure FIFO in little endian */ - mask = ICM42607_FIFO_COUNT_ENDIAN | ICM42607_SENSOR_DATA_ENDIAN; - ret = icm_field_update8(s, ICM42607_REG_INTF_CONFIG0, mask, 0); - if (ret != EC_SUCCESS) - return ret; - - ret = icm_switch_on_mclk(s); - if (ret != EC_SUCCESS) - return ret; - - /* - * configure FIFO: - * - enable continuous watermark interrupt - * - disable all FIFO en bits - */ - val = ICM42607_FIFO_WM_GT_TH; - ret = icm_write_mclk_reg(s, ICM42607_MREG_FIFO_CONFIG5, val); - if (ret != EC_SUCCESS) - return ret; - - ret = icm_switch_off_mclk(s); - if (ret != EC_SUCCESS) - return ret; - - /* clear internal FIFO enable bits tracking */ - st->fifo_en = 0; - - /* set FIFO watermark to 1 data packet (8 bytes) */ - ret = icm_write16(s, ICM42607_REG_FIFO_WM, 8); - if (ret != EC_SUCCESS) - return ret; - } - - return EC_SUCCESS; -} - -#endif /* CONFIG_ACCEL_INTERRUPTS */ - -static int icm42607_enable_sensor(const struct motion_sensor_t *s, int enable) -{ - uint32_t delay, stop_delay; - int32_t rem; - uint8_t mask; - int val; - int ret; - - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - mask = ICM42607_ACCEL_MODE_MASK; - if (enable) { - delay = ICM42607_ACCEL_START_TIME; - stop_delay = ICM42607_ACCEL_STOP_TIME; - val = ICM42607_ACCEL_MODE(ICM42607_MODE_LOW_POWER); - } else { - delay = ICM42607_ACCEL_STOP_TIME; - val = ICM42607_ACCEL_MODE(ICM42607_MODE_OFF); - } - break; - case MOTIONSENSE_TYPE_GYRO: - mask = ICM42607_GYRO_MODE_MASK; - if (enable) { - delay = ICM42607_GYRO_START_TIME; - stop_delay = ICM42607_GYRO_STOP_TIME; - val = ICM42607_GYRO_MODE(ICM42607_MODE_LOW_NOISE); - } else { - delay = ICM42607_GYRO_STOP_TIME; - val = ICM42607_GYRO_MODE(ICM42607_MODE_OFF); - } - break; - default: - return EC_ERROR_INVAL; - } - - /* check stop delay and sleep if required */ - if (enable) { - rem = icm_get_sensor_stabilized(s, __hw_clock_source_read()); - /* rem > stop_delay means counter rollover */ - if (rem > 0 && rem <= stop_delay) - usleep(rem); - } - - mutex_lock(s->mutex); - - ret = icm_field_update8(s, ICM42607_REG_PWR_MGMT0, mask, val); - if (ret == EC_SUCCESS) { - icm_set_stabilize_ts(s, delay); - /* when turning sensor on block any register write for 200 us */ - if (enable) - usleep(200); - } - - mutex_unlock(s->mutex); - - return ret; -} - -static int icm42607_set_data_rate(const struct motion_sensor_t *s, int rate, - int rnd) -{ - struct accelgyro_saved_data_t *data = ICM_GET_SAVED_DATA(s); - int reg, reg2, ret, reg_val, reg2_val; - int normalized_rate; - int max_rate, min_rate; - - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - reg = ICM42607_REG_ACCEL_CONFIG0; - reg2 = ICM42607_REG_ACCEL_CONFIG1; - min_rate = ICM42607_ACCEL_MIN_FREQ; - max_rate = ICM42607_ACCEL_MAX_FREQ; - break; - case MOTIONSENSE_TYPE_GYRO: - reg = ICM42607_REG_GYRO_CONFIG0; - reg2 = ICM42607_REG_GYRO_CONFIG1; - min_rate = ICM42607_GYRO_MIN_FREQ; - max_rate = ICM42607_GYRO_MAX_FREQ; - break; - default: - return EC_RES_INVALID_PARAM; - } - - if (rate == 0) { - /* disable data in FIFO */ - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) - icm42607_config_fifo(s, 0); - /* disable sensor */ - ret = icm42607_enable_sensor(s, 0); - data->odr = 0; - return ret; - } - - /* normalize the rate */ - reg_val = ICM42607_ODR_TO_REG(rate); - normalized_rate = ICM42607_REG_TO_ODR(reg_val); - - /* round up the rate */ - if (rnd && (normalized_rate < rate)) { - reg_val = ICM42607_ODR_REG_UP(reg_val); - normalized_rate = ICM42607_REG_TO_ODR(reg_val); - } - - if (rate > 0) { - if ((normalized_rate < min_rate) || - (normalized_rate > max_rate)) - return EC_RES_INVALID_PARAM; - } - - reg2_val = ICM42607_ODR_TO_FILT_BW(reg_val); - - mutex_lock(s->mutex); - - /* update filter bandwidth */ - ret = icm_field_update8(s, reg2, ICM42607_UI_FILT_BW_MASK, - ICM42607_UI_FILT_BW_SET(reg2_val)); - if (ret != EC_SUCCESS) - goto out_unlock; - - /* update ODR */ - ret = icm_field_update8(s, reg, ICM42607_ODR_MASK, - ICM42607_ODR(reg_val)); - if (ret != EC_SUCCESS) - goto out_unlock; - - mutex_unlock(s->mutex); - - if (data->odr == 0) { - /* enable sensor */ - ret = icm42607_enable_sensor(s, 1); - if (ret) - return ret; - /* enable data in FIFO */ - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) - icm42607_config_fifo(s, 1); - } - - data->odr = normalized_rate; - - return EC_SUCCESS; - -out_unlock: - mutex_unlock(s->mutex); - return ret; -} - -static int icm42607_set_range(struct motion_sensor_t *s, int range, - int rnd) -{ - int reg, ret, reg_val; - int newrange; - - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - reg = ICM42607_REG_ACCEL_CONFIG0; - reg_val = ICM42607_ACCEL_FS_TO_REG(range); - newrange = ICM42607_ACCEL_REG_TO_FS(reg_val); - - if (rnd && (newrange < range) && (reg_val > 0)) { - reg_val--; - newrange = ICM42607_ACCEL_REG_TO_FS(reg_val); - } - - if (newrange > ICM42607_ACCEL_FS_MAX_VAL) { - newrange = ICM42607_ACCEL_FS_MAX_VAL; - reg_val = ICM42607_ACCEL_FS_TO_REG(range); - } - - break; - case MOTIONSENSE_TYPE_GYRO: - reg = ICM42607_REG_GYRO_CONFIG0; - reg_val = ICM42607_GYRO_FS_TO_REG(range); - newrange = ICM42607_GYRO_REG_TO_FS(reg_val); - - if (rnd && (newrange < range) && (reg_val > 0)) { - reg_val--; - newrange = ICM42607_GYRO_REG_TO_FS(reg_val); - } - - if (newrange > ICM42607_GYRO_FS_MAX_VAL) { - newrange = ICM42607_GYRO_FS_MAX_VAL; - reg_val = ICM42607_GYRO_FS_TO_REG(newrange); - } - - break; - default: - return EC_RES_INVALID_PARAM; - } - - mutex_lock(s->mutex); - - ret = icm_field_update8(s, reg, ICM42607_FS_MASK, - ICM42607_FS_SEL(reg_val)); - if (ret == EC_SUCCESS) - s->current_range = newrange; - - mutex_unlock(s->mutex); - - return ret; -} - -static int icm42607_get_hw_offset(const struct motion_sensor_t *s, - intv3_t offset) -{ - uint8_t raw[5]; - int i, reg, val, ret; - - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - reg = ICM42607_MREG_OFFSET_USER4; - break; - case MOTIONSENSE_TYPE_GYRO: - reg = ICM42607_MREG_OFFSET_USER0; - break; - default: - return EC_ERROR_INVAL; - } - - mutex_lock(s->mutex); - - ret = icm_switch_on_mclk(s); - if (ret != EC_SUCCESS) - goto out_unlock; - - for (i = 0; i < sizeof(raw); ++i) { - ret = icm_read_mclk_reg(s, reg + i, &val); - if (ret != EC_SUCCESS) - goto out_unlock; - raw[i] = val; - } - - ret = icm_switch_off_mclk(s); - if (ret != EC_SUCCESS) - goto out_unlock; - - mutex_unlock(s->mutex); - - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - /* - * raw[0]: Accel X[11:8] | gyro Z[11:8] - * raw[1]: Accel X[7:0] - * raw[2]: Accel Y[7:0] - * raw[3]: Accel Z[11:8] | Accel Y[11:8] - * raw[4]: Accel Z[7:0] - */ - offset[X] = (((int)raw[0] << 4) & ~GENMASK(7, 0)) | raw[1]; - offset[Y] = (((int)raw[3] << 8) & ~GENMASK(7, 0)) | raw[2]; - offset[Z] = (((int)raw[3] << 4) & ~GENMASK(7, 0)) | raw[4]; - break; - case MOTIONSENSE_TYPE_GYRO: - /* - * raw[0]: Gyro X[7:0] - * raw[1]: Gyro Y[11:8] | Gyro X[11:8] - * raw[2]: Gyro Y[7:0] - * raw[3]: Gyro Z[7:0] - * raw[4]: Accel X[11:8] | gyro Z[11:8] - */ - offset[X] = (((int)raw[1] << 8) & ~GENMASK(7, 0)) | raw[0]; - offset[Y] = (((int)raw[1] << 4) & ~GENMASK(7, 0)) | raw[2]; - offset[Z] = (((int)raw[4] << 8) & ~GENMASK(7, 0)) | raw[3]; - break; - default: - return EC_ERROR_INVAL; - } - - /* Extend sign-bit of 12 bits signed values */ - for (i = X; i <= Z; ++i) - offset[i] = sign_extend(offset[i], 11); - - return EC_SUCCESS; - -out_unlock: - mutex_unlock(s->mutex); - return ret; -} - -static int icm42607_set_hw_offset(const struct motion_sensor_t *s, - intv3_t offset) -{ - int i, val, ret; - - /* value is 12 bits signed maximum */ - for (i = X; i <= Z; ++i) { - if (offset[i] > 2047) - offset[i] = 2047; - else if (offset[i] < -2048) - offset[i] = -2048; - } - - mutex_lock(s->mutex); - - ret = icm_switch_on_mclk(s); - if (ret != EC_SUCCESS) - goto out_unlock; - - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - /* Accel X[11:8] | gyro Z[11:8] */ - val = (offset[X] >> 4) & GENMASK(7, 4); - ret = icm_field_update_mclk_reg(s, ICM42607_MREG_OFFSET_USER4, - GENMASK(7, 4), val); - if (ret != EC_SUCCESS) - goto out_unlock; - - /* Accel X[7:0] */ - val = offset[X] & GENMASK(7, 0); - ret = icm_write_mclk_reg(s, ICM42607_MREG_OFFSET_USER5, val); - if (ret != EC_SUCCESS) - goto out_unlock; - - /* Accel Y[7:0] */ - val = offset[Y] & GENMASK(7, 0); - ret = icm_write_mclk_reg(s, ICM42607_MREG_OFFSET_USER6, val); - if (ret != EC_SUCCESS) - goto out_unlock; - - /* Accel Z[11:8] | Accel Y[11:8] */ - val = ((offset[Z] >> 4) & GENMASK(7, 4)) | - ((offset[Y] >> 8) & GENMASK(3, 0)); - ret = icm_write_mclk_reg(s, ICM42607_MREG_OFFSET_USER7, val); - if (ret != EC_SUCCESS) - goto out_unlock; - - /* Accel Z[7:0] */ - val = offset[Z] & GENMASK(7, 0); - ret = icm_write_mclk_reg(s, ICM42607_MREG_OFFSET_USER8, val); - if (ret != EC_SUCCESS) - goto out_unlock; - break; - - case MOTIONSENSE_TYPE_GYRO: - /* Gyro X[7:0] */ - val = offset[X] & GENMASK(7, 0); - ret = icm_write_mclk_reg(s, ICM42607_MREG_OFFSET_USER0, val); - if (ret != EC_SUCCESS) - goto out_unlock; - - /* Gyro Y[11:8] | Gyro X[11:8] */ - val = ((offset[Y] >> 4) & GENMASK(7, 4)) | - ((offset[X] >> 8) & GENMASK(3, 0)); - ret = icm_write_mclk_reg(s, ICM42607_MREG_OFFSET_USER1, val); - if (ret != EC_SUCCESS) - goto out_unlock; - - /* Gyro Y[7:0] */ - val = offset[Y] & GENMASK(7, 0); - ret = icm_write_mclk_reg(s, ICM42607_MREG_OFFSET_USER2, val); - if (ret != EC_SUCCESS) - goto out_unlock; - - /* Gyro Z[7:0] */ - val = offset[Z] & GENMASK(7, 0); - ret = icm_write_mclk_reg(s, ICM42607_MREG_OFFSET_USER3, val); - if (ret != EC_SUCCESS) - goto out_unlock; - - /* Accel X[11:8] | gyro Z[11:8] */ - val = (offset[Z] >> 8) & GENMASK(3, 0); - ret = icm_field_update_mclk_reg(s, ICM42607_MREG_OFFSET_USER4, - GENMASK(3, 0), val); - if (ret != EC_SUCCESS) - goto out_unlock; - break; - - default: - ret = EC_ERROR_INVAL; - goto out_unlock; - } - - ret = icm_switch_off_mclk(s); - -out_unlock: - mutex_unlock(s->mutex); - return ret; -} - -static int icm42607_set_offset(const struct motion_sensor_t *s, - const int16_t *offset, int16_t temp) -{ - intv3_t v = { offset[X], offset[Y], offset[Z] }; - int div1, div2; - int i; - - /* rotate back to chip frame */ - rotate_inv(v, *s->rot_standard_ref, v); - - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - /* hardware offset is 1/2048g /LSB, EC offset 1/1024g /LSB. */ - div1 = 2; - div2 = 1; - break; - case MOTIONSENSE_TYPE_GYRO: - /* hardware offset is 1/32dps /LSB, EC offset 1/1024dps /LSB. */ - div1 = 1; - div2 = 32; - break; - default: - return EC_ERROR_INVAL; - } - for (i = X; i <= Z; ++i) - v[i] = round_divide(v[i] * div1, div2); - - return icm42607_set_hw_offset(s, v); -} - -static int icm42607_get_offset(const struct motion_sensor_t *s, int16_t *offset, - int16_t *temp) -{ - intv3_t v; - int div1, div2; - int i, ret; - - ret = icm42607_get_hw_offset(s, v); - if (ret != EC_SUCCESS) - return ret; - - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - /* hardware offset is 1/2048g /LSB, EC offset 1/1024g /LSB. */ - div1 = 1; - div2 = 2; - break; - case MOTIONSENSE_TYPE_GYRO: - /* hardware offset is 1/32dps /LSB, EC offset 1/1024dps /LSB. */ - div1 = 32; - div2 = 1; - break; - default: - return EC_ERROR_INVAL; - } - - for (i = X; i <= Z; ++i) - v[i] = round_divide(v[i] * div1, div2); - - rotate(v, *s->rot_standard_ref, v); - offset[X] = v[X]; - offset[Y] = v[Y]; - offset[Z] = v[Z]; - *temp = EC_MOTION_SENSE_INVALID_CALIB_TEMP; - - return EC_SUCCESS; -} - -static int icm42607_read(const struct motion_sensor_t *s, intv3_t v) -{ - uint8_t raw[6]; - int reg, ret; - - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - reg = ICM42607_REG_ACCEL_DATA_XYZ; - break; - case MOTIONSENSE_TYPE_GYRO: - reg = ICM42607_REG_GYRO_DATA_XYZ; - break; - default: - return EC_ERROR_INVAL; - } - - /* read data registers if sensor is stabilized */ - mutex_lock(s->mutex); - - ret = icm42607_check_sensor_stabilized(s, __hw_clock_source_read()); - if (ret == EC_SUCCESS) - ret = icm_read_n(s, reg, raw, sizeof(raw)); - - mutex_unlock(s->mutex); - if (ret != EC_SUCCESS) - return ret; - - ret = icm42607_normalize(s, v, raw); - /* if data is invalid return the previous read data */ - if (ret != EC_SUCCESS) { - if (v != s->raw_xyz) - memcpy(v, s->raw_xyz, sizeof(s->raw_xyz)); - } - - return EC_SUCCESS; -} - -static int icm42607_read_temp(const struct motion_sensor_t *s, int *temp_ptr) -{ - int val, ret; - - mutex_lock(s->mutex); - ret = icm_read16(s, ICM42607_REG_TEMP_DATA, &val); - mutex_unlock(s->mutex); - - if (ret != EC_SUCCESS) - return ret; - - /* ensure correct propagation of 16 bits sign bit */ - val = sign_extend(val, 15); - - if (val == ICM42607_INVALID_DATA) - return EC_ERROR_NOT_POWERED; - - *temp_ptr = C_TO_K((val / 128) + 25); - return EC_SUCCESS; -} - -static int icm42607_init_config(const struct motion_sensor_t *s) -{ - int mask, val, ret; - - ret = icm_switch_on_mclk(s); - if (ret) - return ret; - - /* Set otp_copy_mode register field */ - ret = icm_field_update_mclk_reg(s, ICM42607_MREG_OTP_CONFIG, - ICM42607_OTP_COPY_MODE_MASK, - ICM42607_OTP_COPY_TRIM); - if (ret) - return ret; - - /* Set otp_power_down register field to 0 */ - ret = icm_field_update_mclk_reg(s, ICM42607_MREG_OTP_CTRL7, - ICM42607_OTP_PWR_DOWN, 0); - if (ret) - return ret; - - /* Wait for 300us for the OTP to fully power up */ - usleep(300); - - /* Set otp_reload register field */ - ret = icm_field_update_mclk_reg(s, ICM42607_MREG_OTP_CTRL7, - ICM42607_OTP_RELOAD, - ICM42607_OTP_RELOAD); - if (ret) - return ret; - - /* Wait for 280 us for the OTP to load */ - usleep(280); - - ret = icm_switch_off_mclk(s); - if (ret) - return ret; - - /* disable i3c support */ - mask = ICM42607_I3C_SDR_EN | ICM42607_I3C_DDR_EN; - ret = icm_field_update8(s, ICM42607_REG_INTF_CONFIG1, mask, 0); - if (ret) - return ret; - - /* set averaging filter for accel, 8x is max for 400Hz */ - if (ICM42607_ACCEL_MAX_FREQ == 400000) - val = ICM42607_UI_AVG_SET(ICM42607_UI_AVG_8X); - else - val = ICM42607_UI_AVG_SET(ICM42607_UI_AVG_32X); - ret = icm_field_update8(s, ICM42607_REG_ACCEL_CONFIG1, - ICM42607_UI_AVG_MASK, val); - if (ret) - return ret; - - /* disable all interrupts */ - ret = icm_write8(s, ICM42607_REG_INT_SOURCE0, 0); - if (ret) - return ret; - - /* disable FIFO */ - return icm_write8(s, ICM42607_REG_FIFO_CONFIG1, ICM42607_FIFO_BYPASS); -} - -static int icm42607_init(struct motion_sensor_t *s) -{ - struct accelgyro_saved_data_t *saved_data = ICM_GET_SAVED_DATA(s); - int val; - int ret, i; - - mutex_lock(s->mutex); - - /* detect chip using whoami */ - ret = icm_read8(s, ICM42607_REG_WHO_AM_I, &val); - if (ret) - goto out_unlock; - - if (val != ICM42607_CHIP_ICM42607P) { - CPRINTS("Unknown WHO_AM_I: 0x%02x", val); - ret = EC_ERROR_ACCESS_DENIED; - goto out_unlock; - } - - /* first time init done only for 1st sensor (accel) */ - if (s->type == MOTIONSENSE_TYPE_ACCEL) { - /* clear status register */ - ret = icm_read8(s, ICM42607_REG_INT_STATUS, &val); - if (ret) - goto out_unlock; - - /* Reset to make sure previous state are not there */ - ret = icm_write8(s, ICM42607_REG_SIGNAL_PATH_RESET, - ICM42607_SOFT_RESET_DEV_CONFIG); - if (ret) - goto out_unlock; - - /* Check reset is done, 1ms max */ - for (i = 0; i < 5; ++i) { - usleep(200); - ret = icm_read8(s, ICM42607_REG_INT_STATUS, &val); - if (ret) - goto out_unlock; - if (val == ICM42607_RESET_DONE_INT) - break; - } - if (val != ICM42607_RESET_DONE_INT) { - ret = EC_ERROR_HW_INTERNAL; - goto out_unlock; - } - - /* configure sensor */ - ret = icm42607_init_config(s); - if (ret) - goto out_unlock; - - if (IS_ENABLED(CONFIG_ACCEL_INTERRUPTS)) { - ret = icm42607_config_interrupt(s); - if (ret) - goto out_unlock; - } - } - - for (i = X; i <= Z; i++) - saved_data->scale[i] = MOTION_SENSE_DEFAULT_SCALE; - - saved_data->odr = 0; - - mutex_unlock(s->mutex); - - return sensor_init_done(s); - -out_unlock: - mutex_unlock(s->mutex); - return ret; -} - -const struct accelgyro_drv icm42607_drv = { - .init = icm42607_init, - .read = icm42607_read, - .read_temp = icm42607_read_temp, - .set_range = icm42607_set_range, - .get_resolution = icm_get_resolution, - .set_data_rate = icm42607_set_data_rate, - .get_data_rate = icm_get_data_rate, - .set_offset = icm42607_set_offset, - .get_offset = icm42607_get_offset, - .set_scale = icm_set_scale, - .get_scale = icm_get_scale, -#ifdef CONFIG_ACCEL_INTERRUPTS - .irq_handler = icm42607_irq_handler, -#endif -}; diff --git a/driver/accelgyro_icm42607.h b/driver/accelgyro_icm42607.h deleted file mode 100644 index 41747fff7a..0000000000 --- a/driver/accelgyro_icm42607.h +++ /dev/null @@ -1,280 +0,0 @@ -/* Copyright 2021 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. - */ - -/* ICM-42607 accelerometer and gyroscope for Chrome EC */ - -#ifndef __CROS_EC_ACCELGYRO_ICM42607_H -#define __CROS_EC_ACCELGYRO_ICM42607_H - -#include "accelgyro.h" -#include "common.h" - -/* - * 7-bit address is 110100Xb. Where 'X' is determined - * by the logic level on pin AP_AD0. - */ -#define ICM42607_ADDR0_FLAGS 0x68 -#define ICM42607_ADDR1_FLAGS 0x69 - -/* Min and Max sampling frequency in mHz */ -#define ICM42607_ACCEL_MIN_FREQ 1562 -#define ICM42607_ACCEL_MAX_FREQ \ - MOTION_MAX_SENSOR_FREQUENCY(400000, 100000) -#define ICM42607_GYRO_MIN_FREQ 12500 -#define ICM42607_GYRO_MAX_FREQ \ - MOTION_MAX_SENSOR_FREQUENCY(1600000, 100000) - -/* Min and Max Accel FS in g */ -#define ICM42607_ACCEL_FS_MIN_VAL 2 -#define ICM42607_ACCEL_FS_MAX_VAL 16 - -/* Min and Max Gyro FS in dps */ -#define ICM42607_GYRO_FS_MIN_VAL 250 -#define ICM42607_GYRO_FS_MAX_VAL 2000 - -/* accel stabilization time in us */ -#define ICM42607_ACCEL_START_TIME 20000 -#define ICM42607_ACCEL_STOP_TIME 0 - -/* gyro stabilization time in us */ -#define ICM42607_GYRO_START_TIME 40000 -#define ICM42607_GYRO_STOP_TIME 20000 - -/* Reg value from Accel FS in G */ -#define ICM42607_ACCEL_FS_TO_REG(_fs) ((_fs) <= 2 ? 3 : \ - (_fs) >= 16 ? 0 : \ - 3 - __fls((_fs) / 2)) - -/* Accel FSR in G from Reg value */ -#define ICM42607_ACCEL_REG_TO_FS(_reg) ((1 << (3 - (_reg))) * 2) - -/* Reg value from Gyro FS in dps */ -#define ICM42607_GYRO_FS_TO_REG(_fs) ((_fs) <= 250 ? 3 : \ - (_fs) >= 2000 ? 0 : \ - 3 - __fls((_fs) / 250)) - -/* Gyro FSR in dps from Reg value */ -#define ICM42607_GYRO_REG_TO_FS(_reg) ((1 << (3 - (_reg))) * 250) - -/* Reg value from ODR in mHz */ -#define ICM42607_ODR_TO_REG(_odr) ((_odr) == 0 ? 0 : \ - (__fls(1600000 / (_odr)) + 5)) - -/* ODR in mHz from Reg value */ -#define ICM42607_REG_TO_ODR(_reg) ((_reg) <= 5 ? 1600000 : \ - (1600000 / (1 << ((_reg) - 5)))) - -/* Reg value for the next higher ODR */ -#define ICM42607_ODR_REG_UP(_reg) ((_reg) - 1) - -/* - * Filter bandwidth values from ODR reg - * >= 400Hz (7) -> 180Hz (1) - * 200Hz (8) -> 73Hz (3) - * 100Hz (9) -> 53Hz (4) - * 50Hz (10) -> 25Hz (6) - * <= 25Hz (11) -> 16Hz (7) - */ -#define ICM42607_ODR_TO_FILT_BW(_odr) ((_odr) <= 7 ? 1 : \ - (_odr) <= 9 ? (_odr) - 5 : \ - (_odr) == 10 ? 6 : \ - 7) - -/* - * Register addresses are virtual address on 16 bits. - * MSB is coding block selection value for MREG registers - * and LSB real register address. - * ex: MREG2 (block 0x28) register 03 => 0x2803 - */ -#define ICM42607_REG_MCLK_RDY 0x0000 -#define ICM42607_MCLK_RDY BIT(3) - -#define ICM426XX_REG_DEVICE_CONFIG 0x0001 -#define ICM426XX_SPI_MODE_1_2 BIT(0) -#define ICM426XX_SPI_AP_4WIRE BIT(2) - -#define ICM42607_REG_SIGNAL_PATH_RESET 0x0002 -#define ICM42607_SOFT_RESET_DEV_CONFIG BIT(4) -#define ICM42607_FIFO_FLUSH BIT(2) - -#define ICM42607_REG_DRIVE_CONFIG1 0x0003 - -#define ICM42607_REG_DRIVE_CONFIG2 0x0004 - -#define ICM42607_REG_DRIVE_CONFIG3 0x0005 - -/* default int configuration is pulsed mode, open drain, and active low */ -#define ICM42607_REG_INT_CONFIG 0x0006 -#define ICM42607_INT2_MASK GENMASK(5, 3) -#define ICM42607_INT2_LATCHED BIT(5) -#define ICM42607_INT2_PUSH_PULL BIT(4) -#define ICM42607_INT2_ACTIVE_HIGH BIT(3) -#define ICM42607_INT1_MASK GENMASK(2, 0) -#define ICM42607_INT1_LATCHED BIT(2) -#define ICM42607_INT1_PUSH_PULL BIT(1) -#define ICM42607_INT1_ACTIVE_HIGH BIT(0) - -/* data are 16 bits */ -#define ICM42607_REG_TEMP_DATA 0x0009 - -/* X + Y + Z: 3 * 16 bits */ -#define ICM42607_REG_ACCEL_DATA_XYZ 0x000B -#define ICM42607_REG_GYRO_DATA_XYZ 0x0011 - -#define ICM42607_INVALID_DATA -32768 - -/* data are 16 bits */ -#define ICM42607_REG_TMST_FSYNCH 0x0017 - -#define ICM42607_REG_PWR_MGMT0 0x001F -#define ICM42607_ACCEL_LP_CLK_SEL BIT(7) -#define ICM42607_IDLE BIT(4) -#define ICM42607_GYRO_MODE_MASK GENMASK(3, 2) -#define ICM42607_GYRO_MODE(_m) (((_m) & 0x03) << 2) -#define ICM42607_ACCEL_MODE_MASK GENMASK(1, 0) -#define ICM42607_ACCEL_MODE(_m) ((_m) & 0x03) - -enum icm42607_sensor_mode { - ICM42607_MODE_OFF, - ICM42607_MODE_STANDBY, - ICM42607_MODE_LOW_POWER, - ICM42607_MODE_LOW_NOISE, -}; - -#define ICM42607_REG_GYRO_CONFIG0 0x0020 -#define ICM42607_REG_ACCEL_CONFIG0 0x0021 -#define ICM42607_FS_MASK GENMASK(6, 5) -#define ICM42607_FS_SEL(_fs) (((_fs) & 0x03) << 5) -#define ICM42607_ODR_MASK GENMASK(3, 0) -#define ICM42607_ODR(_odr) ((_odr) & 0x0F) - -#define ICM42607_REG_TEMP_CONFIG0 0x0022 - -enum icm42607_ui_avg { - ICM42607_UI_AVG_2X, - ICM42607_UI_AVG_4X, - ICM42607_UI_AVG_8X, - ICM42607_UI_AVG_16X, - ICM42607_UI_AVG_32X, - ICM42607_UI_AVG_64X, -}; - -enum icm42607_ui_filt_bw { - ICM42607_UI_FILT_BW_DISABLED, - ICM42607_UI_FILT_BW_180HZ, - ICM42607_UI_FILT_BW_121HZ, - ICM42607_UI_FILT_BW_73HZ, - ICM42607_UI_FILT_BW_53HZ, - ICM42607_UI_FILT_BW_34HZ, - ICM42607_UI_FILT_BW_25HZ, - ICM42607_UI_FILT_BW_16HZ, -}; - -#define ICM42607_REG_GYRO_CONFIG1 0x0023 -#define ICM42607_REG_ACCEL_CONFIG1 0x0024 -#define ICM42607_UI_AVG_MASK GENMASK(6, 4) -#define ICM42607_UI_AVG_SET(_avg) (((_avg) & 0x07) << 4) -#define ICM42607_UI_FILT_BW_MASK GENMASK(2, 0) -#define ICM42607_UI_FILT_BW_SET(_filt) ((_filt) & 0x07) - -#define ICM42607_REG_FIFO_CONFIG1 0x0028 -#define ICM42607_FIFO_STOP_ON_FULL_MODE BIT(1) -#define ICM42607_FIFO_BYPASS BIT(0) -#define ICM42607_FIFO_MODE_STREAM 0x00 - -/* FIFO watermark value is 16 bits little endian */ -#define ICM42607_REG_FIFO_WM 0x0029 - -#define ICM42607_REG_INT_SOURCE0 0x002B -#define ICM42607_ST_INT1_EN BIT(7) -#define ICM42607_FSYNC_INT1_EN BIT(6) -#define ICM42607_PLL_RDY_INT1_EN BIT(5) -#define ICM42607_RESET_DONE_INT1_EN BIT(4) -#define ICM42607_DRDY_INT1_EN BIT(3) -#define ICM42607_FIFO_THS_INT1_EN BIT(2) -#define ICM42607_FIFO_FULL_INT1_EN BIT(1) -#define ICM42607_UI_AGC_RDY_INT1_EN BIT(0) - -#define ICM42607_REG_INTF_CONFIG0 0x0035 -#define ICM42607_FIFO_COUNT_FORMAT BIT(6) -#define ICM42607_FIFO_COUNT_ENDIAN BIT(5) -#define ICM42607_SENSOR_DATA_ENDIAN BIT(4) - -#define ICM42607_REG_INTF_CONFIG1 0x0036 -#define ICM42607_I3C_SDR_EN BIT(3) -#define ICM42607_I3C_DDR_EN BIT(2) -#define ICM42607_CLKSEL_MASK GENMASK(1, 0) -#define ICM42607_CLKSEL_PLL_ENABLE 0x01 - -#define ICM42607_REG_INT_STATUS_DRDY 0x0039 -#define ICM42607_DATA_RDY_INT BIT(0) - -#define ICM42607_REG_INT_STATUS 0x003A -#define ICM42607_ST_INT BIT(7) -#define ICM42607_FSYNC_INT BIT(6) -#define ICM42607_PLL_RDY_INT BIT(5) -#define ICM42607_RESET_DONE_INT BIT(4) -#define ICM42607_FIFO_THS_INT BIT(2) -#define ICM42607_FIFO_FULL_INT BIT(1) -#define ICM42607_AGC_RDY_INT BIT(0) - -/* FIFO count is 16 bits */ -#define ICM42607_REG_FIFO_COUNT 0x003D - -#define ICM42607_REG_FIFO_DATA 0x003F - -#define ICM42607_REG_APEX_CONFIG0 0x0025 -#define ICM42607_DMP_SRAM_RESET_APEX BIT(0) - -#define ICM42607_REG_APEX_CONFIG1 0x0026 -#define ICM42607_DMP_ODR_50HZ BIT(1) - -#define ICM42607_REG_WHO_AM_I 0x0075 -#define ICM42607_CHIP_ICM42607P 0x60 - -/* MREG read access registers */ -#define ICM42607_REG_BLK_SEL_W 0x0079 -#define ICM42607_REG_MADDR_W 0x007A -#define ICM42607_REG_M_W 0x007B - -/* MREG write access registers */ -#define ICM42607_REG_BLK_SEL_R 0x007C -#define ICM42607_REG_MADDR_R 0x007D -#define ICM42607_REG_M_R 0x007E - -/* USER BANK MREG1 */ -#define ICM42607_MREG_FIFO_CONFIG5 0x0001 -#define ICM42607_FIFO_WM_GT_TH BIT(5) -#define ICM42607_FIFO_RESUME_PARTIAL_RD BIT(4) -#define ICM42607_FIFO_HIRES_EN BIT(3) -#define ICM42607_FIFO_TMST_FSYNC_EN BIT(2) -#define ICM42607_FIFO_GYRO_EN BIT(1) -#define ICM42607_FIFO_ACCEL_EN BIT(0) - -#define ICM42607_MREG_OTP_CONFIG 0x002B -#define ICM42607_OTP_COPY_MODE_MASK GENMASK(3, 2) -#define ICM42607_OTP_COPY_TRIM (0x01 << 2) -#define ICM42607_OTP_COPY_ST_DATA (0x03 << 2) - -#define ICM42607_MREG_OFFSET_USER0 0x004E -#define ICM42607_MREG_OFFSET_USER1 0x004F -#define ICM42607_MREG_OFFSET_USER2 0x0050 -#define ICM42607_MREG_OFFSET_USER3 0x0051 -#define ICM42607_MREG_OFFSET_USER4 0x0052 -#define ICM42607_MREG_OFFSET_USER5 0x0053 -#define ICM42607_MREG_OFFSET_USER6 0x0054 -#define ICM42607_MREG_OFFSET_USER7 0x0055 -#define ICM42607_MREG_OFFSET_USER8 0x0056 - -/* USER BANK MREG2 */ -#define ICM42607_MREG_OTP_CTRL7 0x2806 -#define ICM42607_OTP_RELOAD BIT(3) -#define ICM42607_OTP_PWR_DOWN BIT(1) - -extern const struct accelgyro_drv icm42607_drv; - -void icm42607_interrupt(enum gpio_signal signal); - -#endif /* __CROS_EC_ACCELGYRO_ICM42607_H */ diff --git a/driver/accelgyro_icm426xx.c b/driver/accelgyro_icm426xx.c deleted file mode 100644 index 5d09c8e4ef..0000000000 --- a/driver/accelgyro_icm426xx.c +++ /dev/null @@ -1,981 +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. - */ - -/** - * ICM-426xx accelerometer and gyroscope module for Chrome EC - * 3D digital accelerometer & 3D digital gyroscope - */ - -#include "accelgyro.h" -#include "console.h" -#include "driver/accelgyro_icm_common.h" -#include "driver/accelgyro_icm426xx.h" -#include "hwtimer.h" -#include "i2c.h" -#include "math_util.h" -#include "motion_sense.h" -#include "motion_sense_fifo.h" -#include "spi.h" -#include "task.h" -#include "timer.h" -#include "util.h" - -#define CPUTS(outstr) cputs(CC_ACCEL, outstr) -#define CPRINTF(format, args...) cprintf(CC_ACCEL, format, ## args) -#define CPRINTS(format, args...) cprints(CC_ACCEL, format, ## args) - -STATIC_IF(CONFIG_ACCEL_FIFO) volatile uint32_t last_interrupt_timestamp; - -static int icm426xx_normalize(const struct motion_sensor_t *s, intv3_t v, - const uint8_t *raw) -{ - struct accelgyro_saved_data_t *data = ICM_GET_SAVED_DATA(s); - int i; - - /* sensor data is configured as little-endian */ - v[X] = (int16_t)UINT16_FROM_BYTE_ARRAY_LE(raw, 0); - v[Y] = (int16_t)UINT16_FROM_BYTE_ARRAY_LE(raw, 2); - v[Z] = (int16_t)UINT16_FROM_BYTE_ARRAY_LE(raw, 4); - - /* check if data is valid */ - if (v[X] == ICM426XX_INVALID_DATA && - v[Y] == ICM426XX_INVALID_DATA && - v[Z] == ICM426XX_INVALID_DATA) { - return EC_ERROR_INVAL; - } - - rotate(v, *s->rot_standard_ref, v); - - for (i = X; i <= Z; i++) - v[i] = SENSOR_APPLY_SCALE(v[i], data->scale[i]); - - return EC_SUCCESS; -} - -static int icm426xx_check_sensor_stabilized(const struct motion_sensor_t *s, - uint32_t ts) -{ - int32_t rem; - - rem = icm_get_sensor_stabilized(s, ts); - if (rem == 0) - return EC_SUCCESS; - if (rem > 0) - return EC_ERROR_BUSY; - - /* rem < 0: reset check since ts has passed stabilize_ts */ - icm_reset_stabilize_ts(s); - return EC_SUCCESS; -} - -/* use FIFO threshold interrupt on INT1 */ -#define ICM426XX_FIFO_INT_EN ICM426XX_FIFO_THS_INT1_EN -#define ICM426XX_FIFO_INT_STATUS ICM426XX_FIFO_THS_INT - -static int __maybe_unused icm426xx_enable_fifo(const struct motion_sensor_t *s, - int enable) -{ - int val, ret; - - if (enable) { - /* enable FIFO interrupts */ - ret = icm_field_update8(s, ICM426XX_REG_INT_SOURCE0, - ICM426XX_FIFO_INT_EN, - ICM426XX_FIFO_INT_EN); - if (ret != EC_SUCCESS) - return ret; - - /* flush FIFO data */ - ret = icm_write8(s, ICM426XX_REG_SIGNAL_PATH_RESET, - ICM426XX_FIFO_FLUSH); - if (ret != EC_SUCCESS) - return ret; - - /* set FIFO in streaming mode */ - ret = icm_write8(s, ICM426XX_REG_FIFO_CONFIG, - ICM426XX_FIFO_MODE_STREAM); - if (ret != EC_SUCCESS) - return ret; - - /* workaround: first read of FIFO count is always 0 */ - ret = icm_read16(s, ICM426XX_REG_FIFO_COUNT, &val); - if (ret != EC_SUCCESS) - return ret; - } else { - /* set FIFO in bypass mode */ - ret = icm_write8(s, ICM426XX_REG_FIFO_CONFIG, - ICM426XX_FIFO_MODE_BYPASS); - if (ret != EC_SUCCESS) - return ret; - - /* flush FIFO data */ - ret = icm_write8(s, ICM426XX_REG_SIGNAL_PATH_RESET, - ICM426XX_FIFO_FLUSH); - if (ret != EC_SUCCESS) - return ret; - - /* disable FIFO interrupts */ - ret = icm_field_update8(s, ICM426XX_REG_INT_SOURCE0, - ICM426XX_FIFO_INT_EN, 0); - if (ret != EC_SUCCESS) - return ret; - } - - return EC_SUCCESS; -} - -static int __maybe_unused icm426xx_config_fifo(const struct motion_sensor_t *s, - int enable) -{ - struct icm_drv_data_t *st = ICM_GET_DATA(s); - int mask, val; - uint8_t old_fifo_en; - int ret; - - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - mask = ICM426XX_FIFO_ACCEL_EN; - break; - case MOTIONSENSE_TYPE_GYRO: - mask = ICM426XX_FIFO_GYRO_EN; - break; - default: - return EC_ERROR_INVAL; - } - /* temperature data has to be always present in the FIFO */ - mask |= ICM426XX_FIFO_TEMP_EN; - - val = enable ? mask : 0; - - mutex_lock(s->mutex); - - ret = icm_field_update8(s, ICM426XX_REG_FIFO_CONFIG1, mask, val); - if (ret != EC_SUCCESS) - goto out_unlock; - - old_fifo_en = st->fifo_en; - if (enable) - st->fifo_en |= BIT(s->type); - else - st->fifo_en &= ~BIT(s->type); - - if (!old_fifo_en && st->fifo_en) { - /* 1st sensor enabled => turn FIFO on */ - ret = icm426xx_enable_fifo(s, 1); - if (ret != EC_SUCCESS) - goto out_unlock; - } else if (old_fifo_en && !st->fifo_en) { - /* last sensor disabled => turn FIFO off */ - ret = icm426xx_enable_fifo(s, 0); - if (ret != EC_SUCCESS) - goto out_unlock; - } - -out_unlock: - mutex_unlock(s->mutex); - return ret; -} - -static void __maybe_unused icm426xx_push_fifo_data(struct motion_sensor_t *s, - const uint8_t *raw, uint32_t ts) -{ - intv3_t v; - struct ec_response_motion_sensor_data vect; - int ret; - - if (s == NULL) - return; - - ret = icm426xx_normalize(s, v, raw); - if (ret == EC_SUCCESS) { - vect.data[X] = v[X]; - vect.data[Y] = v[Y]; - vect.data[Z] = v[Z]; - vect.flags = 0; - vect.sensor_num = s - motion_sensors; - motion_sense_fifo_stage_data(&vect, s, 3, ts); - } -} - -static int __maybe_unused icm426xx_load_fifo(struct motion_sensor_t *s, - uint32_t ts) -{ - struct icm_drv_data_t *st = ICM_GET_DATA(s); - int count, i, size; - const uint8_t *accel, *gyro; - int ret; - - ret = icm_read16(s, ICM426XX_REG_FIFO_COUNT, &count); - if (ret != EC_SUCCESS) - return ret; - - if (count <= 0) - return EC_ERROR_INVAL; - - /* flush FIFO if buffer is not large enough */ - if (count > ICM_FIFO_BUFFER) { - CPRINTS("It should not happen, the EC is too slow for the ODR"); - ret = icm_write8(s, ICM426XX_REG_SIGNAL_PATH_RESET, - ICM426XX_FIFO_FLUSH); - if (ret != EC_SUCCESS) - return ret; - return EC_ERROR_OVERFLOW; - } - - ret = icm_read_n(s, ICM426XX_REG_FIFO_DATA, st->fifo_buffer, count); - if (ret != EC_SUCCESS) - return ret; - - for (i = 0; i < count; i += size) { - size = icm_fifo_decode_packet(&st->fifo_buffer[i], - &accel, &gyro); - /* exit if error or FIFO is empty */ - if (size <= 0) - return -size; - if (accel != NULL) { - ret = icm426xx_check_sensor_stabilized(st->accel, ts); - if (ret == EC_SUCCESS) - icm426xx_push_fifo_data(st->accel, accel, ts); - } - if (gyro != NULL) { - ret = icm426xx_check_sensor_stabilized(st->gyro, ts); - if (ret == EC_SUCCESS) - icm426xx_push_fifo_data(st->gyro, gyro, ts); - } - } - - return EC_SUCCESS; -} - -#ifdef CONFIG_ACCEL_INTERRUPTS - -/** - * icm426xx_interrupt - called when the sensor activates the interrupt line. - * - * This is a "top half" interrupt handler, it just asks motion sense ask - * to schedule the "bottom half", ->icm426xx_irq_handler(). - */ -void icm426xx_interrupt(enum gpio_signal signal) -{ - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) - last_interrupt_timestamp = __hw_clock_source_read(); - - task_set_event(TASK_ID_MOTIONSENSE, - CONFIG_ACCELGYRO_ICM426XX_INT_EVENT); -} - -/** - * icm426xx_irq_handler - bottom half of the interrupt stack. - * Ran from the motion_sense task, finds the events that raised the interrupt. - */ -static int icm426xx_irq_handler(struct motion_sensor_t *s, uint32_t *event) -{ - int status; - int ret; - - if ((s->type != MOTIONSENSE_TYPE_ACCEL) || - (!(*event & CONFIG_ACCELGYRO_ICM426XX_INT_EVENT))) - return EC_ERROR_NOT_HANDLED; - - mutex_lock(s->mutex); - - /* read and clear interrupt status */ - ret = icm_read8(s, ICM426XX_REG_INT_STATUS, &status); - if (ret != EC_SUCCESS) - goto out_unlock; - - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) { - if (status & ICM426XX_FIFO_INT_STATUS) { - ret = icm426xx_load_fifo(s, last_interrupt_timestamp); - if (ret == EC_SUCCESS) - motion_sense_fifo_commit_data(); - } - } - -out_unlock: - mutex_unlock(s->mutex); - return ret; -} - -static int icm426xx_config_interrupt(const struct motion_sensor_t *s) -{ - struct icm_drv_data_t *st = ICM_GET_DATA(s); - int val, ret; - - /* configure INT1 pin */ - val = ICM426XX_INT1_PUSH_PULL; - if (s->flags & MOTIONSENSE_FLAG_INT_ACTIVE_HIGH) - val |= ICM426XX_INT1_ACTIVE_HIGH; - - ret = icm_write8(s, ICM426XX_REG_INT_CONFIG, val); - if (ret != EC_SUCCESS) - return ret; - - /* deassert async reset for proper INT pin operation */ - ret = icm_field_update8(s, ICM426XX_REG_INT_CONFIG1, - ICM426XX_INT_ASYNC_RESET, 0); - if (ret != EC_SUCCESS) - return ret; - - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) { - /* - * configure FIFO: - * - enable FIFO partial read - * - enable continuous watermark interrupt - * - disable all FIFO en bits - */ - val = ICM426XX_FIFO_PARTIAL_READ | ICM426XX_FIFO_WM_GT_TH; - ret = icm_field_update8(s, ICM426XX_REG_FIFO_CONFIG1, - GENMASK(6, 5) | ICM426XX_FIFO_EN_MASK, - val); - if (ret != EC_SUCCESS) - return ret; - - /* clear internal FIFO enable bits tracking */ - st->fifo_en = 0; - - /* set FIFO watermark to 1 data packet (8 bytes) */ - ret = icm_write16(s, ICM426XX_REG_FIFO_WATERMARK, 8); - if (ret != EC_SUCCESS) - return ret; - } - - return ret; -} - -#endif /* CONFIG_ACCEL_INTERRUPTS */ - -static int icm426xx_enable_sensor(const struct motion_sensor_t *s, int enable) -{ - uint32_t delay, stop_delay; - int32_t rem; - uint8_t mask, val; - int ret; - - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - mask = ICM426XX_ACCEL_MODE_MASK; - if (enable) { - delay = ICM426XX_ACCEL_START_TIME; - stop_delay = ICM426XX_ACCEL_STOP_TIME; - val = ICM426XX_ACCEL_MODE(ICM426XX_MODE_LOW_POWER); - } else { - delay = ICM426XX_ACCEL_STOP_TIME; - val = ICM426XX_ACCEL_MODE(ICM426XX_MODE_OFF); - } - break; - case MOTIONSENSE_TYPE_GYRO: - mask = ICM426XX_GYRO_MODE_MASK; - if (enable) { - delay = ICM426XX_GYRO_START_TIME; - stop_delay = ICM426XX_GYRO_STOP_TIME; - val = ICM426XX_GYRO_MODE(ICM426XX_MODE_LOW_NOISE); - } else { - delay = ICM426XX_GYRO_STOP_TIME; - val = ICM426XX_GYRO_MODE(ICM426XX_MODE_OFF); - } - break; - default: - return EC_ERROR_INVAL; - } - - /* check stop delay and sleep if required */ - if (enable) { - rem = icm_get_sensor_stabilized(s, __hw_clock_source_read()); - /* rem > stop_delay means counter rollover */ - if (rem > 0 && rem <= stop_delay) - usleep(rem); - } - - mutex_lock(s->mutex); - - ret = icm_field_update8(s, ICM426XX_REG_PWR_MGMT0, mask, val); - if (ret == EC_SUCCESS) { - icm_set_stabilize_ts(s, delay); - /* when turning sensor on block any register write for 200 us */ - if (enable) - usleep(200); - } - - mutex_unlock(s->mutex); - - return ret; -} - -static int icm426xx_set_data_rate(const struct motion_sensor_t *s, int rate, - int rnd) -{ - struct accelgyro_saved_data_t *data = ICM_GET_SAVED_DATA(s); - int reg, ret, reg_val; - int normalized_rate; - int max_rate, min_rate; - - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - reg = ICM426XX_REG_ACCEL_CONFIG0; - min_rate = ICM426XX_ACCEL_MIN_FREQ; - max_rate = ICM426XX_ACCEL_MAX_FREQ; - break; - case MOTIONSENSE_TYPE_GYRO: - reg = ICM426XX_REG_GYRO_CONFIG0; - min_rate = ICM426XX_GYRO_MIN_FREQ; - max_rate = ICM426XX_GYRO_MAX_FREQ; - break; - default: - return EC_RES_INVALID_PARAM; - } - - /* normalize the rate */ - reg_val = ICM426XX_ODR_TO_REG(rate); - normalized_rate = ICM426XX_REG_TO_ODR(reg_val); - - /* round up the rate */ - if (rnd && (normalized_rate < rate)) { - reg_val = ICM426XX_ODR_REG_UP(reg_val); - normalized_rate = ICM426XX_REG_TO_ODR(reg_val); - } - - if (rate > 0) { - if ((normalized_rate < min_rate) || - (normalized_rate > max_rate)) - return EC_RES_INVALID_PARAM; - } - - if (rate == 0) { - /* disable data in FIFO */ - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) - icm426xx_config_fifo(s, 0); - /* disable sensor */ - ret = icm426xx_enable_sensor(s, 0); - data->odr = 0; - return ret; - } - - mutex_lock(s->mutex); - - ret = icm_field_update8(s, reg, ICM426XX_ODR_MASK, - ICM426XX_ODR(reg_val)); - if (ret != EC_SUCCESS) - goto out_unlock; - - mutex_unlock(s->mutex); - - if (data->odr == 0) { - /* enable sensor */ - ret = icm426xx_enable_sensor(s, 1); - if (ret) - return ret; - /* enable data in FIFO */ - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) - icm426xx_config_fifo(s, 1); - } - - data->odr = normalized_rate; - return EC_SUCCESS; - -out_unlock: - mutex_unlock(s->mutex); - return ret; -} - -static int icm426xx_set_range(struct motion_sensor_t *s, int range, - int rnd) -{ - int reg, ret, reg_val; - int newrange; - - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - reg = ICM426XX_REG_ACCEL_CONFIG0; - - reg_val = ICM426XX_ACCEL_FS_TO_REG(range); - newrange = ICM426XX_ACCEL_REG_TO_FS(reg_val); - - if (rnd && (newrange < range) && (reg_val > 0)) { - reg_val--; - newrange = ICM426XX_ACCEL_REG_TO_FS(reg_val); - } - - if (newrange > ICM426XX_ACCEL_FS_MAX_VAL) { - newrange = ICM426XX_ACCEL_FS_MAX_VAL; - reg_val = ICM426XX_ACCEL_FS_TO_REG(range); - } - - break; - case MOTIONSENSE_TYPE_GYRO: - reg = ICM426XX_REG_GYRO_CONFIG0; - - reg_val = ICM426XX_GYRO_FS_TO_REG(range); - newrange = ICM426XX_GYRO_REG_TO_FS(reg_val); - - if (rnd && (newrange < range) && (reg_val > 0)) { - reg_val--; - newrange = ICM426XX_GYRO_REG_TO_FS(reg_val); - } - - if (newrange > ICM426XX_GYRO_FS_MAX_VAL) { - newrange = ICM426XX_GYRO_FS_MAX_VAL; - reg_val = ICM426XX_GYRO_FS_TO_REG(newrange); - } - - break; - default: - return EC_RES_INVALID_PARAM; - } - - mutex_lock(s->mutex); - - ret = icm_field_update8(s, reg, ICM426XX_FS_MASK, - ICM426XX_FS_SEL(reg_val)); - if (ret == EC_SUCCESS) - s->current_range = newrange; - - mutex_unlock(s->mutex); - - return ret; -} - -static int icm426xx_get_hw_offset(const struct motion_sensor_t *s, - intv3_t offset) -{ - uint8_t raw[5]; - int i, ret; - - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - mutex_lock(s->mutex); - ret = icm_read_n(s, ICM426XX_REG_OFFSET_USER4, - raw, sizeof(raw)); - mutex_unlock(s->mutex); - if (ret != EC_SUCCESS) - return ret; - /* - * raw[0]: Accel X[11:8] | gyro Z[11:8] - * raw[1]: Accel X[0:7] - * raw[2]: Accel Y[7:0] - * raw[3]: Accel Z[11:8] | Accel Y[11:8] - * raw[4]: Accel Z[7:0] - */ - offset[X] = (((int)raw[0] << 4) & ~GENMASK(7, 0)) | raw[1]; - offset[Y] = (((int)raw[3] << 8) & ~GENMASK(7, 0)) | raw[2]; - offset[Z] = (((int)raw[3] << 4) & ~GENMASK(7, 0)) | raw[4]; - break; - case MOTIONSENSE_TYPE_GYRO: - mutex_lock(s->mutex); - ret = icm_read_n(s, ICM426XX_REG_OFFSET_USER0, - raw, sizeof(raw)); - mutex_unlock(s->mutex); - if (ret != EC_SUCCESS) - return ret; - /* - * raw[0]: Gyro X[7:0] - * raw[1]: Gyro Y[11:8] | Gyro X[11:8] - * raw[2]: Gyro Y[7:0] - * raw[3]: Gyro Z[7:0] - * raw[4]: Accel X[11:8] | gyro Z[11:8] - */ - offset[X] = (((int)raw[1] << 8) & ~GENMASK(7, 0)) | raw[0]; - offset[Y] = (((int)raw[1] << 4) & ~GENMASK(7, 0)) | raw[2]; - offset[Z] = (((int)raw[4] << 8) & ~GENMASK(7, 0)) | raw[3]; - break; - default: - return EC_ERROR_INVAL; - } - - /* Extend sign-bit of 12 bits signed values */ - for (i = X; i <= Z; ++i) - offset[i] = sign_extend(offset[i], 11); - - return EC_SUCCESS; -} - -static int icm426xx_set_hw_offset(const struct motion_sensor_t *s, - intv3_t offset) -{ - int i, val, ret; - - /* value is 12 bits signed maximum */ - for (i = X; i <= Z; ++i) { - if (offset[i] > 2047) - offset[i] = 2047; - else if (offset[i] < -2048) - offset[i] = -2048; - } - - mutex_lock(s->mutex); - - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - /* Accel X[11:8] | gyro Z[11:8] */ - val = (offset[X] >> 4) & GENMASK(7, 4); - ret = icm_field_update8(s, ICM426XX_REG_OFFSET_USER4, - GENMASK(7, 4), val); - if (ret != EC_SUCCESS) - goto out_unlock; - - /* Accel X[7:0] */ - val = offset[X] & GENMASK(7, 0); - ret = icm_write8(s, ICM426XX_REG_OFFSET_USER5, val); - if (ret != EC_SUCCESS) - goto out_unlock; - - /* Accel Y[7:0] */ - val = offset[Y] & GENMASK(7, 0); - ret = icm_write8(s, ICM426XX_REG_OFFSET_USER6, val); - if (ret != EC_SUCCESS) - goto out_unlock; - - /* Accel Z[11:8] | Accel Y[11:8] */ - val = ((offset[Z] >> 4) & GENMASK(7, 4)) | - ((offset[Y] >> 8) & GENMASK(3, 0)); - ret = icm_write8(s, ICM426XX_REG_OFFSET_USER7, val); - if (ret != EC_SUCCESS) - goto out_unlock; - - /* Accel Z[7:0] */ - val = offset[Z] & GENMASK(7, 0); - ret = icm_write8(s, ICM426XX_REG_OFFSET_USER8, val); - if (ret != EC_SUCCESS) - goto out_unlock; - break; - - case MOTIONSENSE_TYPE_GYRO: - /* Gyro X[7:0] */ - val = offset[X] & GENMASK(7, 0); - ret = icm_write8(s, ICM426XX_REG_OFFSET_USER0, val); - if (ret != EC_SUCCESS) - goto out_unlock; - - /* Gyro Y[11:8] | Gyro X[11:8] */ - val = ((offset[Y] >> 4) & GENMASK(7, 4)) | - ((offset[X] >> 8) & GENMASK(3, 0)); - ret = icm_write8(s, ICM426XX_REG_OFFSET_USER1, val); - if (ret != EC_SUCCESS) - goto out_unlock; - - /* Gyro Y[7:0] */ - val = offset[Y] & GENMASK(7, 0); - ret = icm_write8(s, ICM426XX_REG_OFFSET_USER2, val); - if (ret != EC_SUCCESS) - goto out_unlock; - - /* Gyro Z[7:0] */ - val = offset[Z] & GENMASK(7, 0); - ret = icm_write8(s, ICM426XX_REG_OFFSET_USER3, val); - if (ret != EC_SUCCESS) - goto out_unlock; - - /* Accel X[11:8] | gyro Z[11:8] */ - val = (offset[Z] >> 8) & GENMASK(3, 0); - ret = icm_field_update8(s, ICM426XX_REG_OFFSET_USER4, - GENMASK(3, 0), val); - if (ret != EC_SUCCESS) - goto out_unlock; - break; - - default: - ret = EC_ERROR_INVAL; - break; - } - -out_unlock: - mutex_unlock(s->mutex); - return ret; -} - -static int icm426xx_set_offset(const struct motion_sensor_t *s, - const int16_t *offset, int16_t temp) -{ - intv3_t v = { offset[X], offset[Y], offset[Z] }; - int div1, div2; - int i; - - /* rotate back to chip frame */ - rotate_inv(v, *s->rot_standard_ref, v); - - /* convert raw data to hardware offset units */ - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - /* hardware offset is 1/2048g /LSB, EC offset 1/1024g /LSB. */ - div1 = 2; - div2 = 1; - break; - case MOTIONSENSE_TYPE_GYRO: - /* hardware offset is 1/32dps /LSB, EC offset 1/1024dps /LSB. */ - div1 = 1; - div2 = 32; - break; - default: - return EC_ERROR_INVAL; - } - for (i = X; i <= Z; ++i) - v[i] = round_divide(v[i] * div1, div2); - - return icm426xx_set_hw_offset(s, v); -} - -static int icm426xx_get_offset(const struct motion_sensor_t *s, int16_t *offset, - int16_t *temp) -{ - intv3_t v; - int div1, div2; - int i, ret; - - ret = icm426xx_get_hw_offset(s, v); - if (ret != EC_SUCCESS) - return ret; - - /* transform offset to raw data */ - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - /* hardware offset is 1/2048g /LSB, EC offset 1/1024g /LSB. */ - div1 = 1; - div2 = 2; - break; - case MOTIONSENSE_TYPE_GYRO: - /* hardware offset is 1/32dps /LSB, EC offset 1/1024dps /LSB. */ - div1 = 32; - div2 = 1; - break; - default: - return EC_ERROR_INVAL; - } - for (i = X; i <= Z; ++i) - v[i] = round_divide(v[i] * div1, div2); - - rotate(v, *s->rot_standard_ref, v); - offset[X] = v[X]; - offset[Y] = v[Y]; - offset[Z] = v[Z]; - *temp = EC_MOTION_SENSE_INVALID_CALIB_TEMP; - return EC_SUCCESS; -} - -static int icm426xx_read(const struct motion_sensor_t *s, intv3_t v) -{ - uint8_t raw[6]; - int reg, ret; - - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - reg = ICM426XX_REG_ACCEL_DATA_XYZ; - break; - case MOTIONSENSE_TYPE_GYRO: - reg = ICM426XX_REG_GYRO_DATA_XYZ; - break; - default: - return EC_ERROR_INVAL; - } - - /* read data registers if sensor is stabilized */ - mutex_lock(s->mutex); - - ret = icm426xx_check_sensor_stabilized(s, __hw_clock_source_read()); - if (ret == EC_SUCCESS) - ret = icm_read_n(s, reg, raw, sizeof(raw)); - - mutex_unlock(s->mutex); - if (ret != EC_SUCCESS) - return ret; - - ret = icm426xx_normalize(s, v, raw); - /* if data is invalid return the previous read data */ - if (ret != EC_SUCCESS) { - if (v != s->raw_xyz) - memcpy(v, s->raw_xyz, sizeof(s->raw_xyz)); - } - - return EC_SUCCESS; -} - -static int icm426xx_read_temp(const struct motion_sensor_t *s, int *temp_ptr) -{ - int val, ret; - - mutex_lock(s->mutex); - ret = icm_read16(s, ICM426XX_REG_TEMP_DATA, &val); - mutex_unlock(s->mutex); - if (ret != EC_SUCCESS) - return ret; - - /* ensure correct propagation of 16 bits sign bit */ - val = sign_extend(val, 15); - - if (val == ICM426XX_INVALID_DATA) - return EC_ERROR_NOT_POWERED; - - *temp_ptr = C_TO_K((val * 100) / 13248 + 25); - return EC_SUCCESS; -} - -static int icm426xx_init_config(const struct motion_sensor_t *s) -{ - uint8_t mask, val; - int ret; - - /* - * serial bus setup (i2c or spi) - * - * Do not check result for INTF_CONFIG6, since it can induce - * interferences on the bus. - */ - -#ifdef CONFIG_ACCELGYRO_ICM_COMM_SPI - icm_field_update8( - s, ICM426XX_REG_INTF_CONFIG6, ICM426XX_INTF_CONFIG6_MASK, - ICM426XX_I3C_EN | ICM426XX_I3C_SDR_EN | ICM426XX_I3C_DDR_EN); - ret = icm_field_update8(s, ICM426XX_REG_INTF_CONFIG4, - ICM426XX_I3C_BUS_MODE, ICM426XX_I3C_BUS_MODE); -#else - icm_field_update8(s, ICM426XX_REG_INTF_CONFIG6, - ICM426XX_INTF_CONFIG6_MASK, ICM426XX_I3C_EN); - ret = icm_field_update8(s, ICM426XX_REG_INTF_CONFIG4, - ICM426XX_I3C_BUS_MODE, 0); -#endif - if (ret) - return ret; - -#ifdef CONFIG_ACCELGYRO_ICM_COMM_SPI - ret = icm_field_update8( - s, ICM426XX_REG_DRIVE_CONFIG, ICM426XX_DRIVE_CONFIG_MASK, - ICM426XX_I2C_SLEW_RATE(ICM426XX_SLEW_RATE_20NS_60NS) | - ICM426XX_SPI_SLEW_RATE(ICM426XX_SLEW_RATE_INF_2NS)); -#else - ret = icm_field_update8( - s, ICM426XX_REG_DRIVE_CONFIG, ICM426XX_DRIVE_CONFIG_MASK, - ICM426XX_I2C_SLEW_RATE(ICM426XX_SLEW_RATE_12NS_36NS) | - ICM426XX_SPI_SLEW_RATE(ICM426XX_SLEW_RATE_12NS_36NS)); -#endif - if (ret) - return ret; - - /* - * Use invalid value in registers and FIFO. - * Data registers in little-endian format. - * Disable unused serial interface. - */ - mask = ICM426XX_DATA_CONF_MASK | ICM426XX_UI_SIFS_CFG_MASK; -#ifdef CONFIG_ACCELGYRO_ICM_COMM_SPI - val = ICM426XX_UI_SIFS_CFG_I2C_DIS; -#else - val = ICM426XX_UI_SIFS_CFG_SPI_DIS; -#endif - - ret = icm_field_update8(s, ICM426XX_REG_INTF_CONFIG0, mask, val); - if (ret) - return ret; - - /* set accel oscillator to RC clock to avoid bad transition with PLL */ - return icm_field_update8(s, ICM426XX_REG_INTF_CONFIG1, - ICM426XX_ACCEL_LP_CLK_SEL, - ICM426XX_ACCEL_LP_CLK_SEL); -} - -static int icm426xx_init(struct motion_sensor_t *s) -{ - struct icm_drv_data_t *st = ICM_GET_DATA(s); - struct accelgyro_saved_data_t *saved_data = ICM_GET_SAVED_DATA(s); - int mask, val; - int ret, i; - - mutex_lock(s->mutex); - - /* manually force register bank to 0 */ - st->bank = 0; - ret = icm_write8(s, ICM426XX_REG_BANK_SEL, ICM426XX_BANK_SEL(0)); - if (ret) - goto out_unlock; - - /* detect chip using whoami */ - ret = icm_read8(s, ICM426XX_REG_WHO_AM_I, &val); - if (ret) - goto out_unlock; - - if (val != ICM426XX_CHIP_ICM40608 && val != ICM426XX_CHIP_ICM42605) { - CPRINTS("Unknown WHO_AM_I: 0x%02x", val); - ret = EC_ERROR_ACCESS_DENIED; - goto out_unlock; - } - - /* first time init done only for 1st sensor (accel) */ - if (s->type == MOTIONSENSE_TYPE_ACCEL) { - /* reset the chip and verify it is ready */ - ret = icm_write8(s, ICM426XX_REG_DEVICE_CONFIG, - ICM426XX_SOFT_RESET_CONFIG); - if (ret) - goto out_unlock; - msleep(1); - - ret = icm_read8(s, ICM426XX_REG_INT_STATUS, &val); - if (ret) - goto out_unlock; - if (!(val & ICM426XX_RESET_DONE_INT)) { - ret = EC_ERROR_ACCESS_DENIED; - goto out_unlock; - } - - /* configure sensor */ - ret = icm426xx_init_config(s); - if (ret) - goto out_unlock; - - if (IS_ENABLED(CONFIG_ACCEL_INTERRUPTS)) - ret = icm426xx_config_interrupt(s); - if (ret) - goto out_unlock; - } - - for (i = X; i <= Z; i++) - saved_data->scale[i] = MOTION_SENSE_DEFAULT_SCALE; - - saved_data->odr = 0; - - /* set sensor filter */ - switch (s->type) { - case MOTIONSENSE_TYPE_ACCEL: - mask = ICM426XX_ACCEL_UI_FILT_MASK; - val = ICM426XX_ACCEL_UI_FILT_BW(ICM426XX_FILTER_BW_AVG_16X); - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) - st->accel = (struct motion_sensor_t *)s; - break; - case MOTIONSENSE_TYPE_GYRO: - mask = ICM426XX_GYRO_UI_FILT_MASK; - val = ICM426XX_GYRO_UI_FILT_BW(ICM426XX_FILTER_BW_ODR_DIV_2); - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) - st->gyro = (struct motion_sensor_t *)s; - break; - default: - ret = EC_ERROR_INVAL; - goto out_unlock; - } - ret = icm_field_update8(s, ICM426XX_REG_GYRO_ACCEL_CONFIG0, mask, val); - if (ret != EC_SUCCESS) - goto out_unlock; - - mutex_unlock(s->mutex); - - return sensor_init_done(s); - -out_unlock: - mutex_unlock(s->mutex); - return ret; -} - -const struct accelgyro_drv icm426xx_drv = { - .init = icm426xx_init, - .read = icm426xx_read, - .read_temp = icm426xx_read_temp, - .set_range = icm426xx_set_range, - .get_resolution = icm_get_resolution, - .set_data_rate = icm426xx_set_data_rate, - .get_data_rate = icm_get_data_rate, - .set_offset = icm426xx_set_offset, - .get_offset = icm426xx_get_offset, - .set_scale = icm_set_scale, - .get_scale = icm_get_scale, -#ifdef CONFIG_ACCEL_INTERRUPTS - .irq_handler = icm426xx_irq_handler, -#endif -}; diff --git a/driver/accelgyro_icm426xx.h b/driver/accelgyro_icm426xx.h deleted file mode 100644 index bcda1174b2..0000000000 --- a/driver/accelgyro_icm426xx.h +++ /dev/null @@ -1,267 +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. - */ - -/* ICM-426xx accelerometer and gyroscope for Chrome EC */ - -#ifndef __CROS_EC_ACCELGYRO_ICM426XX_H -#define __CROS_EC_ACCELGYRO_ICM426XX_H - -#include "accelgyro.h" -#include "common.h" - -/* - * 7-bit address is 110100Xb. Where 'X' is determined - * by the logic level on pin AP_AD0. - */ -#define ICM426XX_ADDR0_FLAGS 0x68 -#define ICM426XX_ADDR1_FLAGS 0x69 - -/* Min and Max sampling frequency in mHz */ -#define ICM426XX_ACCEL_MIN_FREQ 3125 -#define ICM426XX_ACCEL_MAX_FREQ MOTION_MAX_SENSOR_FREQUENCY(500000, 100000) -#define ICM426XX_GYRO_MIN_FREQ 12500 -#define ICM426XX_GYRO_MAX_FREQ MOTION_MAX_SENSOR_FREQUENCY(4000000, 100000) - -/* Min and Max Accel FS in G */ -#define ICM426XX_ACCEL_FS_MIN_VAL 2 -#define ICM426XX_ACCEL_FS_MAX_VAL 16 - -/* Min and Max Gyro FS in dps */ -#define ICM426XX_GYRO_FS_MIN_VAL 125 -#define ICM426XX_GYRO_FS_MAX_VAL 2000 - -/* accel stabilization time in us */ -#define ICM426XX_ACCEL_START_TIME 20000 -#define ICM426XX_ACCEL_STOP_TIME 0 - -/* gyro stabilization time in us */ -#define ICM426XX_GYRO_START_TIME 60000 -#define ICM426XX_GYRO_STOP_TIME 150000 - -/* Reg value from Accel FS in G */ -#define ICM426XX_ACCEL_FS_TO_REG(_fs) ((_fs) < 2 ? 3 : \ - (_fs) > 16 ? 0 : \ - 3 - __fls((_fs) / 2)) - -/* Accel FSR in G from Reg value */ -#define ICM426XX_ACCEL_REG_TO_FS(_reg) ((1 << (3 - (_reg))) * 2) - -/* Reg value from Gyro FS in dps */ -#define ICM426XX_GYRO_FS_TO_REG(_fs) ((_fs) < 125 ? 4 : \ - (_fs) > 2000 ? 0 : \ - 4 - __fls((_fs) / 125)) - -/* Gyro FSR in dps from Reg value */ -#define ICM426XX_GYRO_REG_TO_FS(_reg) ((1 << (4 - (_reg))) * 125) - -/* Reg value from ODR in mHz */ -#define ICM426XX_ODR_TO_REG(_odr) ((_odr) <= 200000 ? \ - 13 - __fls((_odr) / 3125) : \ - (_odr) < 500000 ? 7 : \ - (_odr) < 1000000 ? 15 : \ - 6 - __fls((_odr) / 1000000)) - -/* ODR in mHz from Reg value */ -#define ICM426XX_REG_TO_ODR(_reg) ((_reg) == 15 ? 500000 : \ - (_reg) >= 7 ? \ - (1 << (13 - (_reg))) * 3125 : \ - (1 << (6 - (_reg))) * 1000000) - -/* Reg value for the next higher ODR */ -#define ICM426XX_ODR_REG_UP(_reg) ((_reg) == 15 ? 6 : \ - (_reg) == 7 ? 15 : \ - (_reg) - 1) - -/* - * Register addresses are virtual address on 16 bits. - * MSB is coding register bank and LSB real register address. - * ex: bank 4, register 1F => 0x041F - */ -#define ICM426XX_REG_DEVICE_CONFIG 0x0011 -#define ICM426XX_SOFT_RESET_CONFIG BIT(0) - -enum icm426xx_slew_rate { - ICM426XX_SLEW_RATE_20NS_60NS, - ICM426XX_SLEW_RATE_12NS_36NS, - ICM426XX_SLEW_RATE_6NS_18NS, - ICM426XX_SLEW_RATE_4NS_12NS, - ICM426XX_SLEW_RATE_2NS_6NS, - ICM426XX_SLEW_RATE_INF_2NS, -}; -#define ICM426XX_REG_DRIVE_CONFIG 0x0013 -#define ICM426XX_DRIVE_CONFIG_MASK GENMASK(5, 0) -#define ICM426XX_I2C_SLEW_RATE(_s) (((_s) & 0x07) << 3) -#define ICM426XX_SPI_SLEW_RATE(_s) ((_s) & 0x07) - -/* default int configuration is pulsed mode, open drain, and active low */ -#define ICM426XX_REG_INT_CONFIG 0x0014 -#define ICM426XX_INT2_LATCHED BIT(5) -#define ICM426XX_INT2_PUSH_PULL BIT(4) -#define ICM426XX_INT2_ACTIVE_HIGH BIT(3) -#define ICM426XX_INT1_LATCHED BIT(2) -#define ICM426XX_INT1_PUSH_PULL BIT(1) -#define ICM426XX_INT1_ACTIVE_HIGH BIT(0) - -#define ICM426XX_REG_FIFO_CONFIG 0x0016 -#define ICM426XX_FIFO_MODE_BYPASS (0x00 << 6) -#define ICM426XX_FIFO_MODE_STREAM (0x01 << 6) -#define ICM426XX_FIFO_MODE_STOP_FULL (0x02 << 6) - -/* data are 16 bits */ -#define ICM426XX_REG_TEMP_DATA 0x001D -/* X + Y + Z: 3 * 16 bits */ -#define ICM426XX_REG_ACCEL_DATA_XYZ 0x001F -#define ICM426XX_REG_GYRO_DATA_XYZ 0x0025 - -#define ICM426XX_INVALID_DATA -32768 - -#define ICM426XX_REG_INT_STATUS 0x002D -#define ICM426XX_UI_FSYNC_INT BIT(6) -#define ICM426XX_PLL_RDY_INT BIT(5) -#define ICM426XX_RESET_DONE_INT BIT(4) -#define ICM426XX_DATA_RDY_INT BIT(3) -#define ICM426XX_FIFO_THS_INT BIT(2) -#define ICM426XX_FIFO_FULL_INT BIT(1) -#define ICM426XX_AGC_RDY_INT BIT(0) - -/* FIFO count is 16 bits */ -#define ICM426XX_REG_FIFO_COUNT 0x002E -#define ICM426XX_REG_FIFO_DATA 0x0030 - -#define ICM426XX_REG_SIGNAL_PATH_RESET 0x004B -#define ICM426XX_ABORT_AND_RESET BIT(3) -#define ICM426XX_TMST_STROBE BIT(2) -#define ICM426XX_FIFO_FLUSH BIT(1) - -#define ICM426XX_REG_INTF_CONFIG0 0x004C -#define ICM426XX_DATA_CONF_MASK GENMASK(7, 4) -#define ICM426XX_FIFO_HOLD_LAST_DATA BIT(7) -#define ICM426XX_FIFO_COUNT_REC BIT(6) -#define ICM426XX_FIFO_COUNT_BE BIT(5) -#define ICM426XX_SENSOR_DATA_BE BIT(4) -#define ICM426XX_UI_SIFS_CFG_MASK GENMASK(1, 0) -#define ICM426XX_UI_SIFS_CFG_SPI_DIS 0x02 -#define ICM426XX_UI_SIFS_CFG_I2C_DIS 0x03 - -#define ICM426XX_REG_INTF_CONFIG1 0x004D -#define ICM426XX_ACCEL_LP_CLK_SEL BIT(3) - -enum icm426xx_sensor_mode { - ICM426XX_MODE_OFF, - ICM426XX_MODE_STANDBY, - ICM426XX_MODE_LOW_POWER, - ICM426XX_MODE_LOW_NOISE, -}; -#define ICM426XX_REG_PWR_MGMT0 0x004E -#define ICM426XX_TEMP_DIS BIT(5) -#define ICM426XX_IDLE BIT(4) -#define ICM426XX_GYRO_MODE_MASK GENMASK(3, 2) -#define ICM426XX_GYRO_MODE(_m) (((_m) & 0x03) << 2) -#define ICM426XX_ACCEL_MODE_MASK GENMASK(1, 0) -#define ICM426XX_ACCEL_MODE(_m) ((_m) & 0x03) - -#define ICM426XX_REG_GYRO_CONFIG0 0x004F -#define ICM426XX_REG_ACCEL_CONFIG0 0x0050 -#define ICM426XX_FS_MASK GENMASK(7, 5) -#define ICM426XX_FS_SEL(_fs) (((_fs) & 0x07) << 5) -#define ICM426XX_ODR_MASK GENMASK(3, 0) -#define ICM426XX_ODR(_odr) ((_odr) & 0x0F) - -enum icm426xx_filter_bw { - /* low noise mode */ - ICM426XX_FILTER_BW_ODR_DIV_2 = 0, - - /* low power mode */ - ICM426XX_FILTER_BW_AVG_1X = 1, - ICM426XX_FILTER_BW_AVG_16X = 6, -}; - -#define ICM426XX_REG_GYRO_ACCEL_CONFIG0 0x0052 -#define ICM426XX_ACCEL_UI_FILT_MASK GENMASK(7, 4) -#define ICM426XX_ACCEL_UI_FILT_BW(_f) (((_f) & 0x0F) << 4) -#define ICM426XX_GYRO_UI_FILT_MASK GENMASK(3, 0) -#define ICM426XX_GYRO_UI_FILT_BW(_f) ((_f) & 0x0F) - -#define ICM426XX_REG_FIFO_CONFIG1 0x005F -#define ICM426XX_FIFO_PARTIAL_READ BIT(6) -#define ICM426XX_FIFO_WM_GT_TH BIT(5) -#define ICM426XX_FIFO_EN_MASK GENMASK(3, 0) -#define ICM426XX_FIFO_TMST_FSYNC_EN BIT(3) -#define ICM426XX_FIFO_TEMP_EN BIT(2) -#define ICM426XX_FIFO_GYRO_EN BIT(1) -#define ICM426XX_FIFO_ACCEL_EN BIT(0) - -/* FIFO watermark value is 16 bits little endian */ -#define ICM426XX_REG_FIFO_WATERMARK 0x0060 - -#define ICM426XX_REG_INT_CONFIG1 0x0064 -#define ICM426XX_INT_PULSE_DURATION BIT(6) -#define ICM426XX_INT_TDEASSERT_DIS BIT(5) -#define ICM426XX_INT_ASYNC_RESET BIT(4) - -#define ICM426XX_REG_INT_SOURCE0 0x0065 -#define ICM426XX_UI_FSYNC_INT1_EN BIT(6) -#define ICM426XX_PLL_RDY_INT1_EN BIT(5) -#define ICM426XX_RESET_DONE_INT1_EN BIT(4) -#define ICM426XX_UI_DRDY_INT1_EN BIT(3) -#define ICM426XX_FIFO_THS_INT1_EN BIT(2) -#define ICM426XX_FIFO_FULL_INT1_EN BIT(1) -#define ICM426XX_UI_AGC_RDY_INT1_EN BIT(0) - -#define ICM426XX_REG_INT_SOURCE3 0x0068 -#define ICM426XX_UI_FSYNC_INT2_EN BIT(6) -#define ICM426XX_PLL_RDY_INT2_EN BIT(5) -#define ICM426XX_RESET_DONE_INT2_EN BIT(4) -#define ICM426XX_UI_DRDY_INT2_EN BIT(3) -#define ICM426XX_FIFO_THS_INT2_EN BIT(2) -#define ICM426XX_FIFO_FULL_INT2_EN BIT(1) -#define ICM426XX_UI_AGC_RDY_INT2_EN BIT(0) - -#define ICM426XX_REG_WHO_AM_I 0x0075 -#define ICM426XX_CHIP_ICM40608 0x39 -#define ICM426XX_CHIP_ICM42605 0x42 - -#define ICM426XX_REG_BANK_SEL 0x0076 -#define ICM426XX_BANK_SEL(_b) ((_b) & 0x07) - -#define ICM426XX_REG_INTF_CONFIG4 0x017A -#define ICM426XX_I3C_BUS_MODE BIT(6) -#define ICM426XX_SPI_AP_4WIRE BIT(1) - -#define ICM426XX_REG_INTF_CONFIG5 0x017B -#define ICM426XX_PIN9_FUNC_INT2 (0x00 << 1) -#define ICM426XX_PIN9_FUNC_FSYNC (0x01 << 1) - -#define ICM426XX_REG_INTF_CONFIG6 0x017C -#define ICM426XX_INTF_CONFIG6_MASK GENMASK(4, 0) -#define ICM426XX_I3C_EN BIT(4) -#define ICM426XX_I3C_IBI_BYTE_EN BIT(3) -#define ICM426XX_I3C_IBI_EN BIT(2) -#define ICM426XX_I3C_DDR_EN BIT(1) -#define ICM426XX_I3C_SDR_EN BIT(0) - -#define ICM426XX_REG_INT_SOURCE8 0x044F -#define ICM426XX_FSYNC_IBI_EN BIT(5) -#define ICM426XX_PLL_RDY_IBI_EN BIT(4) -#define ICM426XX_UI_DRDY_IBI_EN BIT(3) -#define ICM426XX_FIFO_THS_IBI_EN BIT(2) -#define ICM426XX_FIFO_FULL_IBI_EN BIT(1) -#define ICM426XX_AGC_RDY_IBI_EN BIT(0) - -#define ICM426XX_REG_OFFSET_USER0 0x0477 -#define ICM426XX_REG_OFFSET_USER1 0x0478 -#define ICM426XX_REG_OFFSET_USER2 0x0479 -#define ICM426XX_REG_OFFSET_USER3 0x047A -#define ICM426XX_REG_OFFSET_USER4 0x047B -#define ICM426XX_REG_OFFSET_USER5 0x047C -#define ICM426XX_REG_OFFSET_USER6 0x047D -#define ICM426XX_REG_OFFSET_USER7 0x047E -#define ICM426XX_REG_OFFSET_USER8 0x047F - -extern const struct accelgyro_drv icm426xx_drv; - -void icm426xx_interrupt(enum gpio_signal signal); - -#endif /* __CROS_EC_ACCELGYRO_ICM426XX_H */ diff --git a/driver/accelgyro_icm_common.c b/driver/accelgyro_icm_common.c deleted file mode 100644 index 94db99407d..0000000000 --- a/driver/accelgyro_icm_common.c +++ /dev/null @@ -1,366 +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. - */ - -/** - * ICM accelerometer and gyroscope module for Chrome EC - * 3D digital accelerometer & 3D digital gyroscope - */ - -#include "accelgyro.h" -#include "console.h" -#include "i2c.h" -#include "spi.h" -#include "driver/accelgyro_icm_common.h" -#include "driver/accelgyro_icm426xx.h" - -#define CPUTS(outstr) cputs(CC_ACCEL, outstr) -#define CPRINTF(format, args...) cprintf(CC_ACCEL, format, ## args) -#define CPRINTS(format, args...) cprints(CC_ACCEL, format, ## args) - -#ifdef CONFIG_ACCELGYRO_ICM_COMM_SPI -static int icm_spi_raw_read(const int addr, const uint8_t reg, - uint8_t *data, const int len) -{ - uint8_t cmd = 0x80 | reg; - - return spi_transaction(&spi_devices[addr], &cmd, 1, data, len); -} - -static int icm_spi_raw_write(const int addr, const uint8_t reg, - const uint8_t *data, const int len) -{ - uint8_t cmd[3]; - int i; - - if (len > 2) - return EC_ERROR_UNIMPLEMENTED; - - cmd[0] = reg; - for (i = 0; i < len; ++i) - cmd[i + 1] = data[i]; - - return spi_transaction(&spi_devices[addr], cmd, len + 1, NULL, 0); -} -#endif - -static int icm_bank_sel(const struct motion_sensor_t *s, const int reg) -{ - struct icm_drv_data_t *st = ICM_GET_DATA(s); - uint8_t bank = ICM426XX_REG_GET_BANK(reg); - int ret; - - if (bank == st->bank) - return EC_SUCCESS; - -#ifdef CONFIG_ACCELGYRO_ICM_COMM_SPI - ret = icm_spi_raw_write(ACCEL_GET_SPI_ADDR(s->i2c_spi_addr_flags), - ICM426XX_REG_BANK_SEL, &bank, 1); -#else - ret = i2c_write8(s->port, s->i2c_spi_addr_flags, ICM426XX_REG_BANK_SEL, - bank); -#endif - - if (ret == EC_SUCCESS) - st->bank = bank; - - return ret; -} - -/** - * Read 8 bits register - */ -int icm_read8(const struct motion_sensor_t *s, const int reg, int *data_ptr) -{ - const uint8_t addr = ICM426XX_REG_GET_ADDR(reg); - int ret; - - ret = icm_bank_sel(s, reg); - if (ret != EC_SUCCESS) - return ret; - -#ifdef CONFIG_ACCELGYRO_ICM_COMM_SPI - { - uint8_t val; - - ret = icm_spi_raw_read( - ACCEL_GET_SPI_ADDR(s->i2c_spi_addr_flags), addr, &val, - sizeof(val)); - if (ret == EC_SUCCESS) - *data_ptr = val; - } -#else - ret = i2c_read8(s->port, s->i2c_spi_addr_flags, addr, data_ptr); -#endif - - return ret; -} - -/** - * Write 8 bits register - */ -int icm_write8(const struct motion_sensor_t *s, const int reg, int data) -{ - const uint8_t addr = ICM426XX_REG_GET_ADDR(reg); - int ret; - - ret = icm_bank_sel(s, reg); - if (ret != EC_SUCCESS) - return ret; - -#ifdef CONFIG_ACCELGYRO_ICM_COMM_SPI - { - uint8_t val = data; - - ret = icm_spi_raw_write( - ACCEL_GET_SPI_ADDR(s->i2c_spi_addr_flags), addr, &val, - sizeof(val)); - } -#else - ret = i2c_write8(s->port, s->i2c_spi_addr_flags, addr, data); -#endif - - return ret; -} - -/** - * Read 16 bits register - */ -int icm_read16(const struct motion_sensor_t *s, const int reg, int *data_ptr) -{ - const uint8_t addr = ICM426XX_REG_GET_ADDR(reg); - int ret; - - ret = icm_bank_sel(s, reg); - if (ret != EC_SUCCESS) - return ret; - -#ifdef CONFIG_ACCELGYRO_ICM_COMM_SPI - { - uint8_t val[2]; - - ret = icm_spi_raw_read( - ACCEL_GET_SPI_ADDR(s->i2c_spi_addr_flags), addr, val, - sizeof(val)); - if (ret == EC_SUCCESS) { - if (I2C_IS_BIG_ENDIAN(s->i2c_spi_addr_flags)) - *data_ptr = ((int)val[0] << 8) | val[1]; - else - *data_ptr = ((int)val[1] << 8) | val[0]; - } - } -#else - ret = i2c_read16(s->port, s->i2c_spi_addr_flags, - addr, data_ptr); -#endif - - return ret; -} - -/** - * Write 16 bits register - */ -int icm_write16(const struct motion_sensor_t *s, const int reg, int data) -{ - const uint8_t addr = ICM426XX_REG_GET_ADDR(reg); - int ret; - - ret = icm_bank_sel(s, reg); - if (ret != EC_SUCCESS) - return ret; - -#ifdef CONFIG_ACCELGYRO_ICM_COMM_SPI - { - uint8_t val[2]; - - if (I2C_IS_BIG_ENDIAN(s->i2c_spi_addr_flags)) { - val[0] = (data >> 8) & 0xFF; - val[1] = data & 0xFF; - } else { - val[0] = data & 0xFF; - val[1] = (data >> 8) & 0xFF; - } - ret = icm_spi_raw_write( - ACCEL_GET_SPI_ADDR(s->i2c_spi_addr_flags), addr, val, - sizeof(val)); - } -#else - ret = i2c_write16(s->port, s->i2c_spi_addr_flags, addr, data); -#endif - - return ret; -} - -/** - * Read n bytes - */ -int icm_read_n(const struct motion_sensor_t *s, const int reg, - uint8_t *data_ptr, const int len) -{ - const uint8_t addr = ICM426XX_REG_GET_ADDR(reg); - int ret; - - ret = icm_bank_sel(s, reg); - if (ret != EC_SUCCESS) - return ret; - -#ifdef CONFIG_ACCELGYRO_ICM_COMM_SPI - ret = icm_spi_raw_read(ACCEL_GET_SPI_ADDR(s->i2c_spi_addr_flags), addr, - data_ptr, len); -#else - ret = i2c_read_block(s->port, s->i2c_spi_addr_flags, addr, data_ptr, - len); -#endif - - return ret; -} - -int icm_field_update8(const struct motion_sensor_t *s, const int reg, - const uint8_t field_mask, const uint8_t set_value) -{ - const uint8_t addr = ICM426XX_REG_GET_ADDR(reg); - int ret; - - ret = icm_bank_sel(s, reg); - if (ret != EC_SUCCESS) - return ret; - - ret = EC_ERROR_UNIMPLEMENTED; -#ifdef CONFIG_ACCELGYRO_ICM_COMM_SPI - { - uint8_t val; - - ret = icm_spi_raw_read( - ACCEL_GET_SPI_ADDR(s->i2c_spi_addr_flags), addr, &val, - sizeof(val)); - if (ret != EC_SUCCESS) - return ret; - - val = (val & (~field_mask)) | set_value; - - ret = icm_spi_raw_write( - ACCEL_GET_SPI_ADDR(s->i2c_spi_addr_flags), addr, &val, - sizeof(val)); - } -#else - ret = i2c_field_update8(s->port, s->i2c_spi_addr_flags, addr, - field_mask, set_value); -#endif - - return ret; -} - -int icm_get_resolution(const struct motion_sensor_t *s) -{ - return ICM_RESOLUTION; -} - -int icm_get_data_rate(const struct motion_sensor_t *s) -{ - struct accelgyro_saved_data_t *data = ICM_GET_SAVED_DATA(s); - - return data->odr; -} - -int icm_set_scale(const struct motion_sensor_t *s, const uint16_t *scale, - int16_t temp) -{ - struct accelgyro_saved_data_t *data = ICM_GET_SAVED_DATA(s); - - data->scale[X] = scale[X]; - data->scale[Y] = scale[Y]; - data->scale[Z] = scale[Z]; - return EC_SUCCESS; -} - -int icm_get_scale(const struct motion_sensor_t *s, uint16_t *scale, - int16_t *temp) -{ - struct accelgyro_saved_data_t *data = ICM_GET_SAVED_DATA(s); - - scale[X] = data->scale[X]; - scale[Y] = data->scale[Y]; - scale[Z] = data->scale[Z]; - *temp = EC_MOTION_SENSE_INVALID_CALIB_TEMP; - return EC_SUCCESS; -} - -/* FIFO header: 1 byte */ -#define ICM_FIFO_HEADER_MSG BIT(7) -#define ICM_FIFO_HEADER_ACCEL BIT(6) -#define ICM_FIFO_HEADER_GYRO BIT(5) -#define ICM_FIFO_HEADER_TMST_FSYNC GENMASK(3, 2) -#define ICM_FIFO_HEADER_ODR_ACCEL BIT(1) -#define ICM_FIFO_HEADER_ODR_GYRO BIT(0) - -/* FIFO data packet */ -struct icm_fifo_sensor_data { - int16_t x; - int16_t y; - int16_t z; -} __packed; - -struct icm_fifo_1sensor_packet { - uint8_t header; - struct icm_fifo_sensor_data data; - int8_t temp; -} __packed; -#define ICM_FIFO_1SENSOR_PACKET_SIZE 8 - -struct icm_fifo_2sensors_packet { - uint8_t header; - struct icm_fifo_sensor_data accel; - struct icm_fifo_sensor_data gyro; - int8_t temp; - uint16_t timestamp; -} __packed; -#define ICM_FIFO_2SENSORS_PACKET_SIZE 16 - -ssize_t icm_fifo_decode_packet(const void *packet, const uint8_t **accel, - const uint8_t **gyro) -{ - const struct icm_fifo_1sensor_packet *pack1 = packet; - const struct icm_fifo_2sensors_packet *pack2 = packet; - uint8_t header = *((const uint8_t *)packet); - - /* FIFO empty */ - if (header & ICM_FIFO_HEADER_MSG) { - if (accel != NULL) - *accel = NULL; - if (gyro != NULL) - *gyro = NULL; - return 0; - } - - /* accel + gyro */ - if ((header & ICM_FIFO_HEADER_ACCEL) && - (header & ICM_FIFO_HEADER_GYRO)) { - if (accel != NULL) - *accel = (uint8_t *)&pack2->accel; - if (gyro != NULL) - *gyro = (uint8_t *)&pack2->gyro; - return ICM_FIFO_2SENSORS_PACKET_SIZE; - } - - /* accel only */ - if (header & ICM_FIFO_HEADER_ACCEL) { - if (accel != NULL) - *accel = (uint8_t *)&pack1->data; - if (gyro != NULL) - *gyro = NULL; - return ICM_FIFO_1SENSOR_PACKET_SIZE; - } - - /* gyro only */ - if (header & ICM_FIFO_HEADER_GYRO) { - if (accel != NULL) - *accel = NULL; - if (gyro != NULL) - *gyro = (uint8_t *)&pack1->data; - return ICM_FIFO_1SENSOR_PACKET_SIZE; - } - - /* invalid packet if here */ - return -EC_ERROR_INVAL; -} diff --git a/driver/accelgyro_icm_common.h b/driver/accelgyro_icm_common.h deleted file mode 100644 index 8cf3b1e41d..0000000000 --- a/driver/accelgyro_icm_common.h +++ /dev/null @@ -1,140 +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. - */ - -/* ICM accelerometer and gyroscope common definitions for Chrome EC */ - -#ifndef __CROS_EC_ACCELGYRO_ICM_COMMON_H -#define __CROS_EC_ACCELGYRO_ICM_COMMON_H - -#include "accelgyro.h" -#include "hwtimer.h" -#include "timer.h" - -#if !defined(CONFIG_ACCELGYRO_ICM_COMM_SPI) && \ - !defined(CONFIG_ACCELGYRO_ICM_COMM_I2C) -#error "ICM must use either SPI or I2C communication" -#endif - -#ifdef CONFIG_ACCEL_FIFO -/* reserve maximum 4 samples of 16 bytes */ -#define ICM_FIFO_BUFFER 64 -#else -#define ICM_FIFO_BUFFER 0 -#endif - -struct icm_drv_data_t { - struct accelgyro_saved_data_t saved_data[2]; - struct motion_sensor_t *accel; - struct motion_sensor_t *gyro; - uint32_t stabilize_ts[2]; - uint8_t bank; - uint8_t fifo_en; - uint8_t fifo_buffer[ICM_FIFO_BUFFER] __aligned(sizeof(long)); -}; - -#define ICM_GET_DATA(_s) \ - ((struct icm_drv_data_t *)(_s)->drv_data) -#define ICM_GET_SAVED_DATA(_s) \ - (&ICM_GET_DATA(_s)->saved_data[(_s)->type]) - -/* - * Virtual register address is 16 bits: - * - 8 bits MSB coding bank number - * - 8 bits LSB coding physical address - */ -#define ICM426XX_REG_GET_BANK(_r) (((_r) & 0xFF00) >> 8) -#define ICM426XX_REG_GET_ADDR(_r) ((_r) & 0x00FF) - -/* Sensor resolution in number of bits */ -#define ICM_RESOLUTION 16 - -/** - * sign_extend - sign extend a standard int value using the given sign-bit - * @value: value to sign extend - * @index: 0 based bit index to sign bit - */ -static inline int sign_extend(int value, int index) -{ - int shift = (sizeof(int) * 8) - index - 1; - - return (int)(value << shift) >> shift; -} - -/** - * Read 8 bits register - */ -int icm_read8(const struct motion_sensor_t *s, const int reg, int *data_ptr); - -/** - * Write 8 bits register - */ -int icm_write8(const struct motion_sensor_t *s, const int reg, int data); - -/** - * Read 16 bits register - */ -int icm_read16(const struct motion_sensor_t *s, const int reg, int *data_ptr); - -/** - * Write 16 bits register - */ -int icm_write16(const struct motion_sensor_t *s, const int reg, int data); - -/** - * Read n bytes - */ -int icm_read_n(const struct motion_sensor_t *s, const int reg, - uint8_t *data_ptr, const int len); - -int icm_field_update8(const struct motion_sensor_t *s, const int reg, - const uint8_t field_mask, const uint8_t set_value); - -int icm_get_resolution(const struct motion_sensor_t *s); - -int icm_get_range(const struct motion_sensor_t *s); - -int icm_get_data_rate(const struct motion_sensor_t *s); - -int icm_set_scale(const struct motion_sensor_t *s, const uint16_t *scale, - int16_t temp); - -int icm_get_scale(const struct motion_sensor_t *s, uint16_t *scale, - int16_t *temp); - -ssize_t icm_fifo_decode_packet(const void *packet, const uint8_t **accel, - const uint8_t **gyro); - -static inline void icm_set_stabilize_ts(const struct motion_sensor_t *s, - uint32_t delay) -{ - struct icm_drv_data_t *st = ICM_GET_DATA(s); - uint32_t stabilize_ts; - - stabilize_ts = __hw_clock_source_read() + delay; - /* prevent 0 value used for disabling time checking */ - st->stabilize_ts[s->type] = stabilize_ts | 1; -} - -static inline void icm_reset_stabilize_ts(const struct motion_sensor_t *s) -{ - struct icm_drv_data_t *st = ICM_GET_DATA(s); - - st->stabilize_ts[s->type] = 0; -} - -static inline -int32_t icm_get_sensor_stabilized(const struct motion_sensor_t *s, - uint32_t ts) -{ - struct icm_drv_data_t *st = ICM_GET_DATA(s); - uint32_t stabilize_ts = st->stabilize_ts[s->type]; - - if (stabilize_ts == 0) - return 0; - - return time_until(ts, stabilize_ts); -} - -#endif /* __CROS_EC_ACCELGYRO_ICM_COMMON_H */ diff --git a/driver/accelgyro_lsm6ds0.c b/driver/accelgyro_lsm6ds0.c deleted file mode 100644 index beee41b815..0000000000 --- a/driver/accelgyro_lsm6ds0.c +++ /dev/null @@ -1,424 +0,0 @@ -/* Copyright 2014 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. - */ - -/** - * LSM6DS0 accelerometer and gyro module for Chrome EC - * 3D digital accelerometer & 3D digital gyroscope - */ - -#include "accelgyro.h" -#include "common.h" -#include "console.h" -#include "driver/accelgyro_lsm6ds0.h" -#include "hooks.h" -#include "i2c.h" -#include "math_util.h" -#include "task.h" -#include "util.h" - -#define CPUTS(outstr) cputs(CC_ACCEL, outstr) -#define CPRINTS(format, args...) cprints(CC_ACCEL, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_ACCEL, format, ## args) - -/* - * Struct for pairing an engineering value with the register value for a - * parameter. - */ -struct accel_param_pair { - int val; /* Value in engineering units. */ - int reg_val; /* Corresponding register value. */ -}; - -/* List of range values in +/-G's and their associated register values. */ -static const struct accel_param_pair g_ranges[] = { - {2, LSM6DS0_GSEL_2G}, - {4, LSM6DS0_GSEL_4G}, - {8, LSM6DS0_GSEL_8G} -}; - -/* - * List of angular rate range values in +/-dps's - * and their associated register values. - */ -const struct accel_param_pair dps_ranges[] = { - {245, LSM6DS0_DPS_SEL_245}, - {500, LSM6DS0_DPS_SEL_500}, - {1000, LSM6DS0_DPS_SEL_1000}, - {2000, LSM6DS0_DPS_SEL_2000} -}; - -static inline const struct accel_param_pair *get_range_table( - enum motionsensor_type type, int *psize) -{ - if (MOTIONSENSE_TYPE_ACCEL == type) { - if (psize) - *psize = ARRAY_SIZE(g_ranges); - return g_ranges; - } else { - if (psize) - *psize = ARRAY_SIZE(dps_ranges); - return dps_ranges; - } -} - -/* List of ODR (gyro off) values in mHz and their associated register values.*/ -const struct accel_param_pair gyro_on_odr[] = { - {0, LSM6DS0_ODR_PD}, - {15000, LSM6DS0_ODR_15HZ}, - {59000, LSM6DS0_ODR_59HZ}, - {119000, LSM6DS0_ODR_119HZ}, - {238000, LSM6DS0_ODR_238HZ}, - {476000, LSM6DS0_ODR_476HZ}, - {952000, LSM6DS0_ODR_952HZ} -}; - -/* List of ODR (gyro on) values in mHz and their associated register values. */ -const struct accel_param_pair gyro_off_odr[] = { - {0, LSM6DS0_ODR_PD}, - {10000, LSM6DS0_ODR_10HZ}, - {50000, LSM6DS0_ODR_50HZ}, - {119000, LSM6DS0_ODR_119HZ}, - {238000, LSM6DS0_ODR_238HZ}, - {476000, LSM6DS0_ODR_476HZ}, - {952000, LSM6DS0_ODR_952HZ} -}; - -static inline const struct accel_param_pair *get_odr_table( - enum motionsensor_type type, int *psize) -{ - if (MOTIONSENSE_TYPE_ACCEL == type) { - if (psize) - *psize = ARRAY_SIZE(gyro_off_odr); - return gyro_off_odr; - } else { - if (psize) - *psize = ARRAY_SIZE(gyro_on_odr); - return gyro_on_odr; - } -} - -static inline int get_ctrl_reg(enum motionsensor_type type) -{ - return (MOTIONSENSE_TYPE_ACCEL == type) ? - LSM6DS0_CTRL_REG6_XL : LSM6DS0_CTRL_REG1_G; -} - -static inline int get_xyz_reg(enum motionsensor_type type) -{ - return (MOTIONSENSE_TYPE_ACCEL == type) ? - LSM6DS0_OUT_X_L_XL : LSM6DS0_OUT_X_L_G; -} - -/** - * @return reg value that matches the given engineering value passed in. - * The round_up flag is used to specify whether to round up or down. - * Note, this function always returns a valid reg value. If the request is - * outside the range of values, it returns the closest valid reg value. - */ -static int get_reg_val(const int eng_val, const int round_up, - const struct accel_param_pair *pairs, const int size) -{ - int i; - for (i = 0; i < size - 1; i++) { - if (eng_val <= pairs[i].val) - break; - - if (eng_val < pairs[i+1].val) { - if (round_up) - i += 1; - break; - } - } - return pairs[i].reg_val; -} - -/** - * @return engineering value that matches the given reg val - */ -static int get_engineering_val(const int reg_val, - const struct accel_param_pair *pairs, const int size) -{ - int i; - for (i = 0; i < size; i++) { - if (reg_val == pairs[i].reg_val) - break; - } - return pairs[i].val; -} - -/** - * Read register from accelerometer. - */ -static inline int raw_read8(const int port, const uint16_t i2c_addr_flags, - const int reg, int *data_ptr) -{ - return i2c_read8(port, i2c_addr_flags, reg, data_ptr); -} - -/** - * Write register from accelerometer. - */ -static inline int raw_write8(const int port, const uint16_t i2c_addr_flags, - const int reg, int data) -{ - return i2c_write8(port, i2c_addr_flags, reg, data); -} - -static int set_range(struct motion_sensor_t *s, - int range, - int rnd) -{ - int ret, ctrl_val, range_tbl_size; - uint8_t ctrl_reg, reg_val; - const struct accel_param_pair *ranges; - - ctrl_reg = get_ctrl_reg(s->type); - ranges = get_range_table(s->type, &range_tbl_size); - - reg_val = get_reg_val(range, rnd, ranges, range_tbl_size); - - /* - * Lock accel resource to prevent another task from attempting - * to write accel parameters until we are done. - */ - mutex_lock(s->mutex); - - ret = raw_read8(s->port, s->i2c_spi_addr_flags, - ctrl_reg, &ctrl_val); - if (ret != EC_SUCCESS) - goto accel_cleanup; - - ctrl_val = (ctrl_val & ~LSM6DS0_RANGE_MASK) | reg_val; - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - ctrl_reg, ctrl_val); - - /* Now that we have set the range, update the driver's value. */ - if (ret == EC_SUCCESS) - s->current_range = get_engineering_val(reg_val, ranges, - range_tbl_size); - -accel_cleanup: - mutex_unlock(s->mutex); - return ret; -} - -static int get_resolution(const struct motion_sensor_t *s) -{ - return LSM6DS0_RESOLUTION; -} - -static int set_data_rate(const struct motion_sensor_t *s, - int rate, - int rnd) -{ - int ret, val, odr_tbl_size; - uint8_t ctrl_reg, reg_val; - const struct accel_param_pair *data_rates; - struct lsm6ds0_data *data = s->drv_data; - - ctrl_reg = get_ctrl_reg(s->type); - data_rates = get_odr_table(s->type, &odr_tbl_size); - reg_val = get_reg_val(rate, rnd, data_rates, odr_tbl_size); - - /* - * Lock accel resource to prevent another task from attempting - * to write accel parameters until we are done. - */ - mutex_lock(s->mutex); - - ret = raw_read8(s->port, s->i2c_spi_addr_flags, ctrl_reg, &val); - if (ret != EC_SUCCESS) - goto accel_cleanup; - - val = (val & ~LSM6DS0_ODR_MASK) | reg_val; - ret = raw_write8(s->port, s->i2c_spi_addr_flags, ctrl_reg, val); - - /* Now that we have set the odr, update the driver's value. */ - if (ret == EC_SUCCESS) - data->base.odr = get_engineering_val(reg_val, data_rates, - odr_tbl_size); - - /* CTRL_REG3_G 12h - * [7] low-power mode = 0; - * [6] high pass filter disabled; - * [5:4] 0 keep const 0 - * [3:0] HPCF_G - * Table 48 Gyroscope high-pass filter cutoff frequency - */ - if (MOTIONSENSE_TYPE_GYRO == s->type) { - ret = raw_read8(s->port, s->i2c_spi_addr_flags, - LSM6DS0_CTRL_REG3_G, &val); - if (ret != EC_SUCCESS) - goto accel_cleanup; - val &= ~(0x3 << 4); /* clear bit [5:4] */ - val = (rate > 119000) ? - (val | (1<<7)) /* set high-power mode */ : - (val & ~(1<<7)); /* set low-power mode */ - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - LSM6DS0_CTRL_REG3_G, val); - } - -accel_cleanup: - mutex_unlock(s->mutex); - return ret; -} - -static int get_data_rate(const struct motion_sensor_t *s) -{ - struct lsm6ds0_data *data = s->drv_data; - - return data->base.odr; -} - -static int set_offset(const struct motion_sensor_t *s, - const int16_t *offset, - int16_t temp) -{ - /* temperature is ignored */ - struct lsm6ds0_data *data = s->drv_data; - data->offset[X] = offset[X]; - data->offset[Y] = offset[Y]; - data->offset[Z] = offset[Z]; - return EC_SUCCESS; -} - -static int get_offset(const struct motion_sensor_t *s, - int16_t *offset, - int16_t *temp) -{ - struct lsm6ds0_data *data = s->drv_data; - offset[X] = data->offset[X]; - offset[Y] = data->offset[Y]; - offset[Z] = data->offset[Z]; - *temp = EC_MOTION_SENSE_INVALID_CALIB_TEMP; - return EC_SUCCESS; -} - -static int is_data_ready(const struct motion_sensor_t *s, int *ready) -{ - int ret, tmp; - - ret = raw_read8(s->port, s->i2c_spi_addr_flags, - LSM6DS0_STATUS_REG, &tmp); - - if (ret != EC_SUCCESS) { - CPRINTS("%s type:0x%X RS Error", s->name, s->type); - return ret; - } - - if (MOTIONSENSE_TYPE_ACCEL == s->type) - *ready = (LSM6DS0_STS_XLDA_UP == (tmp & LSM6DS0_STS_XLDA_MASK)); - else - *ready = (LSM6DS0_STS_GDA_UP == (tmp & LSM6DS0_STS_GDA_MASK)); - - return EC_SUCCESS; -} - -static int read(const struct motion_sensor_t *s, intv3_t v) -{ - uint8_t raw[6]; - uint8_t xyz_reg; - int ret, i, tmp = 0; - struct lsm6ds0_data *data = s->drv_data; - - ret = is_data_ready(s, &tmp); - if (ret != EC_SUCCESS) - return ret; - - /* - * If sensor data is not ready, return the previous read data. - * Note: return success so that motion senor task can read again - * to get the latest updated sensor data quickly. - */ - if (!tmp) { - if (v != s->raw_xyz) - memcpy(v, s->raw_xyz, sizeof(s->raw_xyz)); - return EC_SUCCESS; - } - - xyz_reg = get_xyz_reg(s->type); - - /* Read 6 bytes starting at xyz_reg */ - ret = i2c_read_block(s->port, s->i2c_spi_addr_flags, - xyz_reg, raw, 6); - - if (ret != EC_SUCCESS) { - CPRINTS("%s type:0x%X RD XYZ Error", - s->name, s->type); - return ret; - } - - for (i = X; i <= Z; i++) - v[i] = (int16_t)((raw[i * 2 + 1] << 8) | raw[i * 2]); - - rotate(v, *s->rot_standard_ref, v); - - /* apply offset in the device coordinates */ - for (i = X; i <= Z; i++) - v[i] += (data->offset[i] << 5) / s->current_range; - - return EC_SUCCESS; -} - -static int init(struct motion_sensor_t *s) -{ - int ret = 0, tmp; - - ret = raw_read8(s->port, s->i2c_spi_addr_flags, - LSM6DS0_WHO_AM_I_REG, &tmp); - if (ret) - return EC_ERROR_UNKNOWN; - - if (tmp != LSM6DS0_WHO_AM_I) - return EC_ERROR_ACCESS_DENIED; - - /* - * This sensor can be powered through an EC reboot, so the state of - * the sensor is unknown here. Initiate software reset to restore - * sensor to default. - * [6] BDU Enable Block Data Update. - * [0] SW_RESET software reset - * - * lsm6ds0 supports both accel & gyro features - * Board will see two virtual sensor devices: accel & gyro. - * Requirement: Accel need be init before gyro. - * SW_RESET is down for accel only! - */ - if (MOTIONSENSE_TYPE_ACCEL == s->type) { - - mutex_lock(s->mutex); - ret = raw_read8(s->port, s->i2c_spi_addr_flags, - LSM6DS0_CTRL_REG8, &tmp); - if (ret) { - mutex_unlock(s->mutex); - return EC_ERROR_UNKNOWN; - } - tmp |= (1 | LSM6DS0_BDU_ENABLE); - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - LSM6DS0_CTRL_REG8, tmp); - mutex_unlock(s->mutex); - - if (ret) - return ret; - - /* Power Down Gyro */ - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - LSM6DS0_CTRL_REG1_G, 0x0); - if (ret) - return ret; - } - return sensor_init_done(s); -} - -const struct accelgyro_drv lsm6ds0_drv = { - .init = init, - .read = read, - .set_range = set_range, - .get_resolution = get_resolution, - .set_data_rate = set_data_rate, - .get_data_rate = get_data_rate, - .set_offset = set_offset, - .get_offset = get_offset, -}; diff --git a/driver/accelgyro_lsm6ds0.h b/driver/accelgyro_lsm6ds0.h deleted file mode 100644 index c6b0789c08..0000000000 --- a/driver/accelgyro_lsm6ds0.h +++ /dev/null @@ -1,133 +0,0 @@ -/* Copyright 2014 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. - */ - -/* LSM6DS0 accelerometer and gyro module for Chrome EC */ - -#ifndef __CROS_EC_ACCELGYRO_LSM6DS0_H -#define __CROS_EC_ACCELGYRO_LSM6DS0_H - -#include "accelgyro.h" -#include "task.h" - -/* - * 7-bit address is 110101Xb. Where 'X' is determined - * by the voltage on the ADDR pin. - */ -#define LSM6DS0_ADDR0_FLAGS 0x6a -#define LSM6DS0_ADDR1_FLAGS 0x6b - -/* who am I */ -#define LSM6DS0_WHO_AM_I 0x68 - -/* Chip specific registers. */ -#define LSM6DS0_ACT_THS 0x04 -#define LSM6DS0_ACT_DUR 0x05 -#define LSM6DS0_INT_GEN_CFG_XL 0x06 -#define LSM6DS0_INT_GEN_THS_X_XL 0x07 -#define LSM6DS0_INT_GEN_THS_Y_XL 0x08 -#define LSM6DS0_INT_GEN_THS_Z_XL 0x09 -#define LSM6DS0_INT_GEN_DUR_XL 0x0a -#define LSM6DS0_REFERENCE_G 0x0b -#define LSM6DS0_INT_CTRL 0x0c -#define LSM6DS0_WHO_AM_I_REG 0x0f -#define LSM6DS0_CTRL_REG1_G 0x10 -#define LSM6DS0_CTRL_REG2_G 0x11 -#define LSM6DS0_CTRL_REG3_G 0x12 -#define LSM6DS0_ORIENT_CFG_G 0x13 -#define LSM6DS0_INT_GEN_SRC_G 0x14 -#define LSM6DS0_OUT_TEMP_L 0x15 -#define LSM6DS0_OUT_TEMP_H 0x16 -#define LSM6DS0_OUT_X_L_G 0x18 -#define LSM6DS0_OUT_X_H_G 0x19 -#define LSM6DS0_OUT_Y_L_G 0x1a -#define LSM6DS0_OUT_Y_H_G 0x1b -#define LSM6DS0_OUT_Z_L_G 0x1c -#define LSM6DS0_OUT_Z_H_G 0x1d -#define LSM6DS0_CTRL_REG4 0x1e -#define LSM6DS0_CTRL_REG5_XL 0x1f -#define LSM6DS0_CTRL_REG6_XL 0x20 -#define LSM6DS0_CTRL_REG7_XL 0x21 -#define LSM6DS0_CTRL_REG8 0x22 -#define LSM6DS0_CTRL_REG9 0x23 -#define LSM6DS0_CTRL_REG10 0x24 -#define LSM6DS0_INT_GEN_SRC_XL 0x26 -#define LSM6DS0_STATUS_REG 0x27 -#define LSM6DS0_OUT_X_L_XL 0x28 -#define LSM6DS0_OUT_X_H_XL 0x29 -#define LSM6DS0_OUT_Y_L_XL 0x2a -#define LSM6DS0_OUT_Y_H_XL 0x2b -#define LSM6DS0_OUT_Z_L_XL 0x2c -#define LSM6DS0_OUT_Z_H_XL 0x2d -#define LSM6DS0_FIFO_CTRL 0x2e -#define LSM6DS0_FIFO_SRC 0x2f -#define LSM6DS0_INT_GEN_CFG_G 0x30 -#define LSM6DS0_INT_GEN_THS_XH_G 0x31 -#define LSM6DS0_INT_GEN_THS_XL_G 0x32 -#define LSM6DS0_INT_GEN_THS_YH_G 0x33 -#define LSM6DS0_INT_GEN_THS_YL_G 0x34 -#define LSM6DS0_INT_GEN_THS_ZH_G 0x35 -#define LSM6DS0_INT_GEN_THS_ZL_G 0x36 -#define LSM6DS0_INT_GEN_DUR_G 0x37 - -#define LSM6DS0_DPS_SEL_245 (0 << 3) -#define LSM6DS0_DPS_SEL_500 BIT(3) -#define LSM6DS0_DPS_SEL_1000 (2 << 3) -#define LSM6DS0_DPS_SEL_2000 (3 << 3) -#define LSM6DS0_GSEL_2G (0 << 3) -#define LSM6DS0_GSEL_4G (2 << 3) -#define LSM6DS0_GSEL_8G (3 << 3) - -#define LSM6DS0_RANGE_MASK (3 << 3) - -#define LSM6DS0_ODR_PD (0 << 5) -#define LSM6DS0_ODR_10HZ BIT(5) -#define LSM6DS0_ODR_15HZ BIT(5) -#define LSM6DS0_ODR_50HZ (2 << 5) -#define LSM6DS0_ODR_59HZ (2 << 5) -#define LSM6DS0_ODR_119HZ (3 << 5) -#define LSM6DS0_ODR_238HZ (4 << 5) -#define LSM6DS0_ODR_476HZ (5 << 5) -#define LSM6DS0_ODR_952HZ (6 << 5) - -#define LSM6DS0_ODR_MASK (7 << 5) - -/* - * Register : STATUS_REG - * Address : 0X27 - */ -enum lsm6ds0_status { - LSM6DS0_STS_DOWN = 0x00, - LSM6DS0_STS_XLDA_UP = 0x01, - LSM6DS0_STS_GDA_UP = 0x02, -}; -#define LSM6DS0_STS_XLDA_MASK 0x01 -#define LSM6DS0_STS_GDA_MASK 0x02 - -/* - * Register : CTRL_REG8 - * Address : 0X22 - * Bit Group Name: BDU - */ -enum lsm6ds0_bdu { - LSM6DS0_BDU_DISABLE = 0x00, - LSM6DS0_BDU_ENABLE = 0x40, -}; -/* Sensor resolution in number of bits. This sensor has fixed resolution. */ -#define LSM6DS0_RESOLUTION 16 - -/* Min and Max sampling frequency in mHz */ -#define LSM6DS0_ACCEL_MIN_FREQ 14900 -#define LSM6DS0_ACCEL_MAX_FREQ MOTION_MAX_SENSOR_FREQUENCY(952000, 119000) - -#define LSM6DS0_GYRO_MIN_FREQ 14900 -#define LSM6DS0_GYRO_MAX_FREQ MOTION_MAX_SENSOR_FREQUENCY(952000, 119000) - -extern const struct accelgyro_drv lsm6ds0_drv; -struct lsm6ds0_data { - struct accelgyro_saved_data_t base; - int16_t offset[3]; -}; - -#endif /* __CROS_EC_ACCELGYRO_LSM6DS0_H */ diff --git a/driver/accelgyro_lsm6dso.c b/driver/accelgyro_lsm6dso.c deleted file mode 100644 index fbce687f2c..0000000000 --- a/driver/accelgyro_lsm6dso.c +++ /dev/null @@ -1,490 +0,0 @@ -/* Copyright 2019 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. - */ - -/** - * LSM6DSO Accel and Gyro module for Chrome EC - * 3D digital accelerometer & 3D digital gyroscope - * - * For any details on driver implementation please - * Refer to AN5192 Application Note on www.st.com - */ - -#include "driver/accelgyro_lsm6dso.h" -#include "hooks.h" -#include "hwtimer.h" -#include "math_util.h" -#include "motion_sense_fifo.h" -#include "task.h" -#include "timer.h" - -#define CPRINTS(format, args...) cprints(CC_ACCEL, format, ## args) - -STATIC_IF(CONFIG_ACCEL_FIFO) volatile uint32_t last_interrupt_timestamp; -STATIC_IF(CONFIG_ACCEL_INTERRUPTS) int config_interrupt( - const struct motion_sensor_t *s); - -/* - * When ODR change, the sensor filters need settling time; - * Add a counter to discard a well known number of data with - * incorrect values. - */ -static uint32_t samples_to_discard[LSM6DSO_FIFO_DEV_NUM]; - -/** - * @return output data base register for sensor - */ -static inline int get_xyz_reg(enum motionsensor_type type) -{ - return LSM6DSO_ACCEL_OUT_X_L_ADDR - - (LSM6DSO_ACCEL_OUT_X_L_ADDR - LSM6DSO_GYRO_OUT_X_L_ADDR) * type; -} - -#ifdef CONFIG_ACCEL_INTERRUPTS -/** - * Configure interrupt int 1 to fire handler for: - * - * FIFO threshold on watermark (1 sample) - * - * @s: Motion sensor pointer - */ -static int config_interrupt(const struct motion_sensor_t *s) -{ - int ret = EC_SUCCESS; - int int1_ctrl_val; - - if (!IS_ENABLED(CONFIG_ACCEL_FIFO)) - return ret; - - ret = st_raw_read8(s->port, s->i2c_spi_addr_flags, LSM6DSO_INT1_CTRL, - &int1_ctrl_val); - if (ret != EC_SUCCESS) - return ret; - - /* - * Configure FIFO threshold to 1 sample: interrupt on watermark - * will be generated every time a new data sample will be stored - * in FIFO. The interrupr on watermark is cleared only when the - * number or samples still present in FIFO exceeds the - * configured threshold. - */ - ret = st_raw_write8(s->port, s->i2c_spi_addr_flags, - LSM6DSO_FIFO_CTRL1_ADDR, 1); - if (ret != EC_SUCCESS) - return ret; - - int1_ctrl_val |= LSM6DSO_INT_FIFO_TH | LSM6DSO_INT_FIFO_OVR | - LSM6DSO_INT_FIFO_FULL; - - ret = st_raw_write8(s->port, s->i2c_spi_addr_flags, LSM6DSO_INT1_CTRL, - int1_ctrl_val); - - return ret; -} - -/** - * fifo_disable - set fifo mode to LSM6DSO_FIFO_MODE_BYPASS_VAL - * @s: Motion sensor pointer: must be MOTIONSENSE_TYPE_ACCEL. - */ -static int fifo_disable(const struct motion_sensor_t *s) -{ - return st_raw_write8(s->port, s->i2c_spi_addr_flags, - LSM6DSO_FIFO_CTRL4_ADDR, - LSM6DSO_FIFO_MODE_BYPASS_VAL); -} - -/** - * set_fifo_params - Configure internal FIFO parameters - * - * Configure FIFO decimator to have every time the right pattern - * with acc/gyro - */ -static int fifo_enable(const struct motion_sensor_t *s) -{ - return st_raw_write8(s->port, s->i2c_spi_addr_flags, - LSM6DSO_FIFO_CTRL4_ADDR, - LSM6DSO_FIFO_MODE_CONTINUOUS_VAL); -} - -/** - * push_fifo_data - Scan data pattern and push upside - */ -static void push_fifo_data(struct motion_sensor_t *main_s, uint8_t *fifo, - uint32_t saved_ts) -{ - struct ec_response_motion_sensor_data vect; - struct motion_sensor_t *sensor; - uint8_t tag; - int id; - int *axis; - uint8_t *ptr; - uint8_t ag_maps[] = { - MOTIONSENSE_TYPE_GYRO, - MOTIONSENSE_TYPE_ACCEL, - }; - - /* - * FIFO pattern is as follow (i.e. Acc/Gyro @ same ODR) - * ________ ____________ _______ ____________ - * | TAG_XL | Acc[x,y,z] | TAG_G | Gyr[x,y,z] | - * |________|____________|_______|____________| - * |<-------- 1 -------->|<-------- 2 ------->| (FIFO Threshold) - * - * First byte is tag, next data. - * Data pattern len is fixed for each sample. - * FIFO threshold is related to sample data (7 byte). - */ - ptr = fifo + LSM6DSO_TAG_SIZE; - tag = (*fifo >> 3) - LSM6DSO_GYRO_TAG; - id = ag_maps[tag]; - - /* Discard samples every ODR changes. */ - if (samples_to_discard[id] > 0) { - samples_to_discard[id]--; - return; - } - - sensor = main_s + id; - axis = sensor->raw_xyz; - - /* Apply precision, sensitivity and rotation. */ - st_normalize(sensor, axis, ptr); - vect.data[X] = axis[X]; - vect.data[Y] = axis[Y]; - vect.data[Z] = axis[Z]; - - vect.flags = 0; - vect.sensor_num = sensor - motion_sensors; - motion_sense_fifo_stage_data(&vect, sensor, 3, saved_ts); -} - -static inline int load_fifo(struct motion_sensor_t *main_s, - const uint16_t fifo_len, - uint32_t saved_ts) -{ - uint8_t fifo[LSM6DSO_FIFO_SAMPLE_SIZE]; - int i, err; - - for (i = 0; i < fifo_len; i++) { - err = st_raw_read_n_noinc(main_s->port, - main_s->i2c_spi_addr_flags, - LSM6DSO_FIFO_DATA_ADDR_TAG, - fifo, LSM6DSO_FIFO_SAMPLE_SIZE); - if (err != EC_SUCCESS) - return err; - - push_fifo_data(main_s, fifo, saved_ts); - } - - return EC_SUCCESS; -} - -/** - * accelgyro_config_fifo - update mode and ODR for FIFO decimator - */ -static int accelgyro_config_fifo(const struct motion_sensor_t *s) -{ - int err; - struct stprivate_data *data = LSM6DSO_GET_DATA(s); - uint8_t reg_val; - uint8_t fifo_odr_mask; - - /* Changing in ODR must stop FIFO. */ - err = fifo_disable(s); - if (err != EC_SUCCESS) - return err; - - /* - * If ODR changes restore to default discard samples number - * the counter related to this sensor. - */ - samples_to_discard[s->type] = LSM6DSO_DISCARD_SAMPLES; - - fifo_odr_mask = LSM6DSO_FIFO_ODR_MASK(s); - reg_val = LSM6DSO_ODR_TO_REG(data->base.odr); - err = st_write_data_with_mask(s, LSM6DSO_FIFO_CTRL3_ADDR, - fifo_odr_mask, reg_val); - if (err != EC_SUCCESS) - return err; - - return fifo_enable(s); -} - -/** - * lsm6dso_interrupt - interrupt from int1 pin of sensor - */ -void lsm6dso_interrupt(enum gpio_signal signal) -{ - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) - last_interrupt_timestamp = __hw_clock_source_read(); - - task_set_event(TASK_ID_MOTIONSENSE, CONFIG_ACCEL_LSM6DSO_INT_EVENT); -} - -/** - * irq_handler - bottom half of the interrupt task sheduled by consumer - */ -static int irq_handler(struct motion_sensor_t *s, uint32_t *event) -{ - int ret = EC_SUCCESS, fifo_len = 0; - struct lsm6dso_fstatus fsts; - bool has_read_fifo = false; - - if ((s->type != MOTIONSENSE_TYPE_ACCEL) || - (!(*event & CONFIG_ACCEL_LSM6DSO_INT_EVENT))) - return EC_ERROR_NOT_HANDLED; - - if (!IS_ENABLED(CONFIG_ACCEL_FIFO)) - return EC_SUCCESS; - - do { - /* Read how many data patterns on FIFO to read. */ - ret = st_raw_read_n_noinc(s->port, s->i2c_spi_addr_flags, - LSM6DSO_FIFO_STS1_ADDR, - (uint8_t *)&fsts, sizeof(fsts)); - if (ret != EC_SUCCESS) - break; - - if (fsts.len & (LSM6DSO_FIFO_DATA_OVR | LSM6DSO_FIFO_FULL)) - CPRINTS("%s FIFO Overrun: %04x", s->name, fsts.len); - - fifo_len = fsts.len & LSM6DSO_FIFO_DIFF_MASK; - if (fifo_len) { - ret = load_fifo(s, fifo_len, last_interrupt_timestamp); - has_read_fifo = true; - } - } while (fifo_len != 0 && ret == EC_SUCCESS); - - if (ret == EC_SUCCESS && has_read_fifo) - motion_sense_fifo_commit_data(); - - return ret; -} -#endif /* CONFIG_ACCEL_INTERRUPTS */ - -/** - * set_range - set full scale range - * @s: Motion sensor pointer - * @range: Range - * @rnd: Round up/down flag - * Note: Range is sensitivity/gain for speed purpose - */ -static int set_range(struct motion_sensor_t *s, int range, int rnd) -{ - int err; - uint8_t ctrl_reg, reg_val; - int newrange = range; - - ctrl_reg = LSM6DSO_RANGE_REG(s->type); - if (s->type == MOTIONSENSE_TYPE_ACCEL) { - /* Adjust and check rounded value for Acc. */ - if (rnd && (newrange < LSM6DSO_ACCEL_NORMALIZE_FS(newrange))) - newrange *= 2; - - if (newrange > LSM6DSO_ACCEL_FS_MAX_VAL) - newrange = LSM6DSO_ACCEL_FS_MAX_VAL; - - reg_val = lsm6dso_accel_fs_reg(newrange); - } else { - /* Adjust and check rounded value for Gyro. */ - reg_val = LSM6DSO_GYRO_FS_REG(range); - if (rnd && (range > LSM6DSO_GYRO_NORMALIZE_FS(reg_val))) - reg_val++; - - if (reg_val > LSM6DSO_GYRO_FS_MAX_REG_VAL) - reg_val = LSM6DSO_GYRO_FS_MAX_REG_VAL; - - newrange = LSM6DSO_GYRO_NORMALIZE_FS(reg_val); - } - - mutex_lock(s->mutex); - err = st_write_data_with_mask(s, ctrl_reg, LSM6DSO_RANGE_MASK, - reg_val); - if (err == EC_SUCCESS) - s->current_range = newrange; - - mutex_unlock(s->mutex); - - return EC_SUCCESS; -} - -/** - * set_data_rate set sensor data rate - * @s: Motion sensor pointer - * @range: Rate (mHz) - * @rnd: Round up/down flag - */ -static int set_data_rate(const struct motion_sensor_t *s, int rate, int rnd) -{ - int ret, normalized_rate = 0; - struct stprivate_data *data = LSM6DSO_GET_DATA(s); - uint8_t ctrl_reg, reg_val = 0; - - ctrl_reg = LSM6DSO_ODR_REG(s->type); - if (rate > 0) { - reg_val = LSM6DSO_ODR_TO_REG(rate); - normalized_rate = LSM6DSO_REG_TO_ODR(reg_val); - - if (rnd && (normalized_rate < rate)) { - reg_val++; - normalized_rate = LSM6DSO_REG_TO_ODR(reg_val); - } - - if (normalized_rate < LSM6DSO_ODR_MIN_VAL || - normalized_rate > LSM6DSO_ODR_MAX_VAL) - return EC_RES_INVALID_PARAM; - } - - mutex_lock(s->mutex); - ret = st_write_data_with_mask(s, ctrl_reg, LSM6DSO_ODR_MASK, reg_val); - if (ret == EC_SUCCESS) { - data->base.odr = normalized_rate; - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) - accelgyro_config_fifo(s); - } - - mutex_unlock(s->mutex); - - return ret; -} - -static int is_data_ready(const struct motion_sensor_t *s, int *ready) -{ - int ret, tmp; - - ret = st_raw_read8(s->port, s->i2c_spi_addr_flags, - LSM6DSO_STATUS_REG, &tmp); - if (ret != EC_SUCCESS) { - CPRINTS("%s type:0x%X RS Error", s->name, s->type); - - return ret; - } - - if (MOTIONSENSE_TYPE_ACCEL == s->type) - *ready = (LSM6DSO_STS_XLDA_UP == (tmp & LSM6DSO_STS_XLDA_MASK)); - else - *ready = (LSM6DSO_STS_GDA_UP == (tmp & LSM6DSO_STS_GDA_MASK)); - - return EC_SUCCESS; -} - -/* - * Is not very efficient to collect the data in read: better have an interrupt - * and collect in FIFO, even if it has one item: we don't have to check if the - * sensor is ready (minimize I2C access). - */ -static int read(const struct motion_sensor_t *s, intv3_t v) -{ - uint8_t raw[OUT_XYZ_SIZE]; - uint8_t xyz_reg; - int ret, tmp = 0; - - ret = is_data_ready(s, &tmp); - if (ret != EC_SUCCESS) - return ret; - - /* - * If sensor data is not ready, return the previous read data. - * Note: return success so that motion senor task can read again - * to get the latest updated sensor data quickly. - */ - if (!tmp) { - if (v != s->raw_xyz) - memcpy(v, s->raw_xyz, sizeof(s->raw_xyz)); - - return EC_SUCCESS; - } - - xyz_reg = get_xyz_reg(s->type); - - /* Read data bytes starting at xyz_reg. */ - ret = st_raw_read_n_noinc(s->port, s->i2c_spi_addr_flags, - xyz_reg, raw, OUT_XYZ_SIZE); - if (ret != EC_SUCCESS) - return ret; - - /* Apply precision, sensitivity and rotation vector. */ - st_normalize(s, v, raw); - - return EC_SUCCESS; -} - -static int init(struct motion_sensor_t *s) -{ - int ret = 0, tmp; - struct stprivate_data *data = LSM6DSO_GET_DATA(s); - - ret = st_raw_read8(s->port, s->i2c_spi_addr_flags, - LSM6DSO_WHO_AM_I_REG, &tmp); - if (ret != EC_SUCCESS) - return EC_ERROR_UNKNOWN; - - if (tmp != LSM6DSO_WHO_AM_I) - return EC_ERROR_ACCESS_DENIED; - - /* - * This sensor can be powered through an EC reboot, so the state of the - * sensor is unknown here so reset it - * LSM6DSO supports both Acc & Gyro features - * Board will see two virtual sensor devices: Acc & Gyro - * Requirement: Acc need be init before Gyro - */ - if (s->type == MOTIONSENSE_TYPE_ACCEL) { - mutex_lock(s->mutex); - - /* Software reset. */ - ret = st_raw_write8(s->port, s->i2c_spi_addr_flags, - LSM6DSO_CTRL3_ADDR, LSM6DSO_SW_RESET); - if (ret != EC_SUCCESS) - goto err_unlock; - - /* - * Output data not updated until have been read. - * Require interrupt to be active low. - */ - ret = st_raw_write8(s->port, s->i2c_spi_addr_flags, - LSM6DSO_CTRL3_ADDR, - LSM6DSO_BDU | LSM6DSO_IF_INC - | LSM6DSO_H_L_ACTIVE); - if (ret != EC_SUCCESS) - goto err_unlock; - - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) { - ret = fifo_disable(s); - if (ret != EC_SUCCESS) - goto err_unlock; - } - - if (IS_ENABLED(CONFIG_ACCEL_INTERRUPTS)) - ret = config_interrupt(s); - if (ret != EC_SUCCESS) - goto err_unlock; - - mutex_unlock(s->mutex); - } - - /* Set default resolution common to Acc and Gyro. */ - data->resol = LSM6DSO_RESOLUTION; - return sensor_init_done(s); - -err_unlock: - mutex_unlock(s->mutex); - CPRINTS("%s: MS Init type:0x%X Error", s->name, s->type); - - return ret; -} - -const struct accelgyro_drv lsm6dso_drv = { - .init = init, - .read = read, - .set_range = set_range, - .get_resolution = st_get_resolution, - .set_data_rate = set_data_rate, - .get_data_rate = st_get_data_rate, - .set_offset = st_set_offset, - .get_offset = st_get_offset, -#ifdef CONFIG_ACCEL_INTERRUPTS - .irq_handler = irq_handler, -#endif /* CONFIG_ACCEL_INTERRUPTS */ -}; diff --git a/driver/accelgyro_lsm6dso.h b/driver/accelgyro_lsm6dso.h deleted file mode 100644 index 9a58fe7d36..0000000000 --- a/driver/accelgyro_lsm6dso.h +++ /dev/null @@ -1,223 +0,0 @@ -/* Copyright 2019 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. - */ - -/* LSM6DSO Accel and Gyro driver for Chrome EC */ - -#ifndef __CROS_EC_ACCELGYRO_LSM6DSO_H -#define __CROS_EC_ACCELGYRO_LSM6DSO_H - -#include "stm_mems_common.h" - -/* - * 7-bit address is 110101xb. Where 'x' is determined - * by the voltage on the ADDR pin - */ -#define LSM6DSO_ADDR0_FLAGS 0x6a -#define LSM6DSO_ADDR1_FLAGS 0x6b - -/* Access to embedded sensor hub register bank */ -#define LSM6DSO_FUNC_CFG_ACC_ADDR 0x01 -#define LSM6DSO_FUNC_CFG_EN 0x80 - -/* Who Am I */ -#define LSM6DSO_WHO_AM_I_REG 0x0f -#define LSM6DSO_WHO_AM_I 0x6c - -/* Common defines for Acc and Gyro sensors */ -#define LSM6DSO_EN_BIT 0x01 -#define LSM6DSO_DIS_BIT 0x00 - -#define LSM6DSO_GYRO_OUT_X_L_ADDR 0x22 -#define LSM6DSO_ACCEL_OUT_X_L_ADDR 0x28 - -#define LSM6DSO_CTRL1_ADDR 0x10 -#define LSM6DSO_CTRL2_ADDR 0x11 -#define LSM6DSO_CTRL3_ADDR 0x12 -#define LSM6DSO_SW_RESET 0x01 -#define LSM6DSO_IF_INC 0x04 -#define LSM6DSO_PP_OD 0x10 -#define LSM6DSO_H_L_ACTIVE 0x20 -#define LSM6DSO_BDU 0x40 - -#define LSM6DSO_CTRL4_ADDR 0x13 -#define LSM6DSO_INT2_ON_INT1_MASK 0x20 - -#define LSM6DSO_CTRL5_ADDR 0x14 -#define LSM6DSO_CTRL6_ADDR 0x15 -#define LSM6DSO_CTRL7_ADDR 0x16 -#define LSM6DSO_CTRL8_ADDR 0x17 -#define LSM6DSO_CTRL9_ADDR 0x18 - -#define LSM6DSO_CTRL10_ADDR 0x19 -#define LSM6DSO_TIMESTAMP_EN 0x20 - -#define LSM6DSO_STATUS_REG 0x1e - -/* Output data rate registers and masks */ -#define LSM6DSO_ODR_REG(_sensor) \ - (LSM6DSO_CTRL1_ADDR + (_sensor)) -#define LSM6DSO_ODR_MASK 0xf0 - -/* FIFO decimator registers and bitmask */ -#define LSM6DSO_FIFO_CTRL1_ADDR 0x07 -#define LSM6DSO_FIFO_CTRL2_ADDR 0x08 - -#define LSM6DSO_FIFO_CTRL3_ADDR 0x09 -#define LSM6DSO_FIFO_ODR_XL_MASK 0x0f -#define LSM6DSO_FIFO_ODR_G_MASK 0xf0 - -#define LSM6DSO_FIFO_CTRL4_ADDR 0x0a -#define LSM6DSO_FIFO_MODE_MASK 0x07 - -#define LSM6DSO_INT1_CTRL 0x0d -#define LSM6DSO_INT2_CTRL 0x0e -#define LSM6DSO_INT_FIFO_TH 0x08 -#define LSM6DSO_INT_FIFO_OVR 0x10 -#define LSM6DSO_INT_FIFO_FULL 0x20 - -#define LSM6DSO_FIFO_STS1_ADDR 0x3a -#define LSM6DSO_FIFO_STS2_ADDR 0x3b -#define LSM6DSO_FIFO_DIFF_MASK 0x07ff -#define LSM6DSO_FIFO_FULL 0x2000 -#define LSM6DSO_FIFO_DATA_OVR 0x4000 -#define LSM6DSO_FIFO_WATERMARK 0x8000 - -/* Out FIFO data register */ -#define LSM6DSO_FIFO_DATA_ADDR_TAG 0x78 - -/* Registers value for supported FIFO mode */ -#define LSM6DSO_FIFO_MODE_BYPASS_VAL 0x00 -#define LSM6DSO_FIFO_MODE_CONTINUOUS_VAL 0x06 - -/* Define device available in FIFO pattern */ -enum lsm6dso_dev_fifo { - LSM6DSO_FIFO_DEV_INVALID = -1, - LSM6DSO_FIFO_DEV_GYRO = 0, - LSM6DSO_FIFO_DEV_ACCEL, - LSM6DSO_FIFO_DEV_NUM, -}; - -/* Define FIFO data pattern, tag and len */ -#define LSM6DSO_TAG_SIZE 1 -#define LSM6DSO_FIFO_SAMPLE_SIZE (OUT_XYZ_SIZE + LSM6DSO_TAG_SIZE) - -enum lsm6dso_tag_fifo { - LSM6DSO_GYRO_TAG = 0x01, - LSM6DSO_ACC_TAG = 0x02, -}; - -struct lsm6dso_fstatus { - uint16_t len; - uint16_t pattern; -}; - -/* Absolute maximum rate for Acc and Gyro sensors */ -#define LSM6DSO_ODR_MIN_VAL 13000 -#define LSM6DSO_ODR_MAX_VAL \ - MOTION_MAX_SENSOR_FREQUENCY(416000, 13000) - -/* ODR reg value from selected data rate in mHz */ -#define LSM6DSO_ODR_TO_REG(_odr) (__fls(_odr / LSM6DSO_ODR_MIN_VAL) + 1) - -#define LSM6DSO_FIFO_ODR_MASK(_s) \ - (_s->type == MOTIONSENSE_TYPE_ACCEL ? LSM6DSO_FIFO_ODR_XL_MASK : \ - LSM6DSO_FIFO_ODR_G_MASK) - -/* Normalized ODR values from selected data rate in mHz */ -#define LSM6DSO_REG_TO_ODR(_reg) (LSM6DSO_ODR_MIN_VAL << (_reg - 1)) - -/* Full Scale ranges value and gain for Acc */ -#define LSM6DSO_FS_LIST_NUM 4 - -#define LSM6DSO_ACCEL_FS_ADDR 0x10 -#define LSM6DSO_ACCEL_FS_MASK 0x0c - -#define LSM6DSO_ACCEL_FS_2G_VAL 0x00 -#define LSM6DSO_ACCEL_FS_4G_VAL 0x02 -#define LSM6DSO_ACCEL_FS_8G_VAL 0x03 -#define LSM6DSO_ACCEL_FS_16G_VAL 0x01 - -#define LSM6DSO_ACCEL_FS_MAX_VAL 16 - -/* Accel reg value from Full Scale range */ -static inline uint8_t lsm6dso_accel_fs_reg(int fs) -{ - uint8_t ret; - - switch(fs) { - case 2: - ret = LSM6DSO_ACCEL_FS_2G_VAL; - break; - case 16: - ret = LSM6DSO_ACCEL_FS_16G_VAL; - break; - default: - ret = __fls(fs); - break; - } - - return ret; -} - -/* Accel normalized FS value from Full Scale */ -#define LSM6DSO_ACCEL_NORMALIZE_FS(_fs) (1 << __fls(_fs)) - -/* Full Scale range value and gain for Gyro */ -#define LSM6DSO_GYRO_FS_ADDR 0x11 -#define LSM6DSO_GYRO_FS_MASK 0x0c - -/* Minimal Gyro range in mDPS */ -#define LSM6DSO_GYRO_FS_MIN_VAL_MDPS ((8750 << 15) / 1000) -#define LSM6DSO_GYRO_FS_MAX_REG_VAL 3 - -/* Gyro reg value for Full Scale selection in DPS */ -#define LSM6DSO_GYRO_FS_REG(_fs) \ - __fls(MAX(1, (_fs * 1000) / LSM6DSO_GYRO_FS_MIN_VAL_MDPS)) - -/* Gyro normalized FS value (in DPS) from Full Scale register */ -#define LSM6DSO_GYRO_NORMALIZE_FS(_reg) \ - ((LSM6DSO_GYRO_FS_MIN_VAL_MDPS << (_reg)) / 1000) - -/* FS register address/mask for Acc/Gyro sensors */ -#define LSM6DSO_RANGE_REG(_sensor) (LSM6DSO_ACCEL_FS_ADDR + (_sensor)) -#define LSM6DSO_RANGE_MASK 0x0c - -/* Status register bit for Acc/Gyro data ready */ -enum lsm6dso_status { - LSM6DSO_STS_DOWN = 0x00, - LSM6DSO_STS_XLDA_UP = 0x01, - LSM6DSO_STS_GDA_UP = 0x02 -}; - -/* Status register bitmask for Acc/Gyro data ready */ -#define LSM6DSO_STS_XLDA_MASK 0x01 -#define LSM6DSO_STS_GDA_MASK 0x02 - -/* Sensor resolution in number of bits: fixed 16 bit */ -#define LSM6DSO_RESOLUTION 16 - -/* Aggregate private data for all supported sensor (Acc, Gyro) */ -struct lsm6dso_data { - struct stprivate_data st_data[LSM6DSO_FIFO_DEV_NUM]; -}; - -/* - * Note: The specific number of samples to discard depends on the filters - * configured for the chip, as well as the ODR being set. For most of our - * allowed ODRs, 3 should suffice. - * See: ST's LSM6DSO application notes (AN5192) Tables 12 and 18 for details - */ -#define LSM6DSO_DISCARD_SAMPLES 3 - -#define LSM6DSO_GET_DATA(_s) ((struct stprivate_data *)((_s)->drv_data)) - -/* Macro to initialize motion_sensors structure */ -#define LSM6DSO_ST_DATA(g, type) (&((g).st_data[type])) - -extern const struct accelgyro_drv lsm6dso_drv; - -void lsm6dso_interrupt(enum gpio_signal signal); - -#endif /* __CROS_EC_ACCELGYRO_LSM6DSO_H */ diff --git a/driver/als_al3010.c b/driver/als_al3010.c deleted file mode 100644 index b129dc2f57..0000000000 --- a/driver/als_al3010.c +++ /dev/null @@ -1,49 +0,0 @@ -/* 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. - * - * Dyna-Image AL3010 light sensor driver - */ - -#include "driver/als_al3010.h" -#include "i2c.h" - -/** - * Initialise AL3010 light sensor. - */ -int al3010_init(void) -{ - int ret; - - ret = i2c_write8(I2C_PORT_ALS, AL3010_I2C_ADDR, - AL3010_REG_CONFIG, AL3010_GAIN << 4); - if (ret) - return ret; - - return i2c_write8(I2C_PORT_ALS, AL3010_I2C_ADDR, - AL3010_REG_SYSTEM, AL3010_ENABLE); -} - -/** - * Read AL3010 light sensor data. - */ -int al3010_read_lux(int *lux, int af) -{ - int ret; - int val; - long long val64; - - ret = i2c_read16(I2C_PORT_ALS, AL3010_I2C_ADDR, - AL3010_REG_DATA_LOW, &val); - - if (ret) - return ret; - - val64 = val; - val64 = (val64 * AL3010_GAIN_SCALE) / 10000; - val = val64 * af / 100; - - *lux = val; - - return EC_SUCCESS; -} diff --git a/driver/als_al3010.h b/driver/als_al3010.h deleted file mode 100644 index 288e255990..0000000000 --- a/driver/als_al3010.h +++ /dev/null @@ -1,40 +0,0 @@ -/* 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. - * - * Dyna-Image AL3010 light sensor driver - */ - -#ifndef __CROS_EC_ALS_AL3010_H -#define __CROS_EC_ALS_AL3010_H - -/* I2C interface */ -#define AL3010_I2C_ADDR1_FLAGS 0x1C -#define AL3010_I2C_ADDR2_FLAGS 0x1D -#define AL3010_I2C_ADDR3_FLAGS 0x1E - -/* AL3010 registers */ -#define AL3010_REG_SYSTEM 0x00 -#define AL3010_REG_INT_STATUS 0x01 -#define AL3010_REG_CONFIG 0x10 -#define AL3010_REG_DATA_LOW 0x0C - -#define AL3010_ENABLE 0x01 -#define AL3010_GAIN_SELECT 3 - -#define AL3010_GAIN_1 0 /* 77806 lx */ -#define AL3010_GAIN_2 1 /* 19452 lx */ -#define AL3010_GAIN_3 2 /* 4863 lx */ -#define AL3010_GAIN_4 3 /* 1216 lx */ -#define AL3010_GAIN CONCAT2(AL3010_GAIN_, AL3010_GAIN_SELECT) - -#define AL3010_GAIN_SCALE_1 11872 /* 1.1872 lux/count */ -#define AL3010_GAIN_SCALE_2 2968 /* 0.2968 lux/count */ -#define AL3010_GAIN_SCALE_3 742 /* 0.0742 lux/count */ -#define AL3010_GAIN_SCALE_4 186 /* 0.0186 lux/count */ -#define AL3010_GAIN_SCALE CONCAT2(AL3010_GAIN_SCALE_, AL3010_GAIN_SELECT) - -int al3010_init(void); -int al3010_read_lux(int *lux, int af); - -#endif /* __CROS_EC_ALS_AL3010_H */ diff --git a/driver/als_bh1730.c b/driver/als_bh1730.c deleted file mode 100644 index 56afb86e0b..0000000000 --- a/driver/als_bh1730.c +++ /dev/null @@ -1,180 +0,0 @@ -/* Copyright 2017 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. - * - * Rohm BH1730 Ambient light sensor driver - */ - -#include "accelgyro.h" -#include "config.h" -#include "console.h" -#include "driver/als_bh1730.h" -#include "i2c.h" - -#define CPRINTS(format, args...) cprints(CC_MOTION_SENSE, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_MOTION_SENSE, format, ## args) - -/** - * Convert BH1730 data0, data1 to lux - */ -static int bh1730_convert_to_lux(uint32_t data0_1) -{ - int lux; - uint16_t data0 = 0x0000ffff & data0_1; - uint16_t data1 = data0_1 >> 16; - uint32_t d0_1k = data0 * 1000; - uint32_t d1_1k = data1 * 1000; - uint32_t d_temp; - uint32_t d_lux; - - if (data0 == 0) - return 0; - else - d_temp = d1_1k / data0; - - if(d_temp < BH1730_LUXTH1_1K) { - d0_1k = BH1730_LUXTH1_D0_1K * data0; - d1_1k = BH1730_LUXTH1_D1_1K * data1; - } else if(d_temp < BH1730_LUXTH2_1K) { - d0_1k = BH1730_LUXTH2_D0_1K * data0; - d1_1k = BH1730_LUXTH2_D1_1K * data1; - } else if(d_temp < BH1730_LUXTH3_1K) { - d0_1k = BH1730_LUXTH3_D0_1K * data0; - d1_1k = BH1730_LUXTH3_D1_1K * data1; - } else if(d_temp < BH1730_LUXTH4_1K) { - d0_1k = BH1730_LUXTH4_D0_1K * data0; - d1_1k = BH1730_LUXTH4_D1_1K * data1; - } else - return 0; - - d_lux = (d0_1k - d1_1k) / BH1730_GAIN_DIV; - d_lux *= 100; - lux = d_lux / ITIME_MS_X_1K; - - return lux; -} - -/** - * Read BH1730 light sensor data. - */ -static int bh1730_read_lux(const struct motion_sensor_t *s, intv3_t v) -{ - struct bh1730_drv_data_t *drv_data = BH1730_GET_DATA(s); - int ret; - int data0_1; - - /* read data0 and data1 from sensor */ - ret = i2c_read32(s->port, s->i2c_spi_addr_flags, - BH1730_DATA0LOW, &data0_1); - if (ret != EC_SUCCESS) { - CPRINTF("bh1730_read_lux - fail %d\n", ret); - return ret; - } - - /* convert sensor data0 and data1 to lux */ - v[0] = bh1730_convert_to_lux(data0_1); - v[1] = 0; - v[2] = 0; - - /* - * Return an error when nothing change to prevent filling the - * fifo with useless data. - */ - if (v[0] == drv_data->last_value) - return EC_ERROR_UNCHANGED; - else - return EC_SUCCESS; -} - -static int bh1730_set_range(struct motion_sensor_t *s, int range, - int rnd) -{ - /* Range is fixed by hardware */ - if (range != s->default_range) - return EC_ERROR_INVAL; - - s->current_range = range; - return EC_SUCCESS; -} - -static int bh1730_set_data_rate(const struct motion_sensor_t *s, - int rate, int roundup) -{ - struct bh1730_drv_data_t *drv_data = BH1730_GET_DATA(s); - - /* now only one rate supported */ - drv_data->rate = BH1730_10000_MHZ; - - return EC_SUCCESS; -} - -static int bh1730_get_data_rate(const struct motion_sensor_t *s) -{ - struct bh1730_drv_data_t *drv_data = BH1730_GET_DATA(s); - - return drv_data->rate; -} - -static int bh1730_set_offset(const struct motion_sensor_t *s, - const int16_t *offset, - int16_t temp) -{ - return EC_SUCCESS; -} - -static int bh1730_get_offset(const struct motion_sensor_t *s, - int16_t *offset, - int16_t *temp) -{ - *offset = 0; - - return EC_SUCCESS; -} - -/** - * Initialise BH1730 Ambient light sensor. - */ -static int bh1730_init(struct motion_sensor_t *s) -{ - int ret; - - /* power and measurement bit high */ - ret = i2c_write8(s->port, s->i2c_spi_addr_flags, - BH1730_CONTROL, - BH1730_CONTROL_POWER_ENABLE - | BH1730_CONTROL_ADC_EN_ENABLE); - - if (ret != EC_SUCCESS) { - CPRINTF("bh1730_init_sensor - enable fail %d\n", ret); - return ret; - } - - /* set timing */ - ret = i2c_write8(s->port, s->i2c_spi_addr_flags, - BH1730_TIMING, BH1730_CONF_ITIME); - if (ret != EC_SUCCESS) { - CPRINTF("bh1730_init_sensor - time fail %d\n", ret); - return ret; - } - /* set ADC gain */ - ret = i2c_write8(s->port, s->i2c_spi_addr_flags, - BH1730_GAIN, BH1730_CONF_GAIN); - - if (ret != EC_SUCCESS) { - CPRINTF("bh1730_init_sensor - gain fail %d\n", ret); - return ret; - } - - return sensor_init_done(s); -} - -const struct accelgyro_drv bh1730_drv = { - .init = bh1730_init, - .read = bh1730_read_lux, - .set_range = bh1730_set_range, - .set_offset = bh1730_set_offset, - .get_offset = bh1730_get_offset, - .set_data_rate = bh1730_set_data_rate, - .get_data_rate = bh1730_get_data_rate, -}; - diff --git a/driver/als_bh1730.h b/driver/als_bh1730.h deleted file mode 100644 index f49afac76f..0000000000 --- a/driver/als_bh1730.h +++ /dev/null @@ -1,97 +0,0 @@ -/* Copyright 2017 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. - * - * Rohm BH1730 Ambient light sensor driver - */ - -#ifndef __CROS_EC_ALS_BH1730_H -#define __CROS_EC_ALS_BH1730_H - -/* I2C interface */ -#define BH1730_I2C_ADDR_FLAGS 0x29 - -/* BH1730 registers */ -#define BH1730_CONTROL 0x80 -#define BH1730_TIMING 0x81 -#define BH1730_INTERRUPT 0x82 -#define BH1730_THLLOW 0x83 -#define BH1730_THLHIGH 0x84 -#define BH1730_THHLOW 0x85 -#define BH1730_THHHIGH 0x86 -#define BH1730_GAIN 0x87 -#define BH1730_OPART_ID 0x92 -#define BH1730_DATA0LOW 0x94 -#define BH1730_DATA0HIGH 0x95 -#define BH1730_DATA1LOW 0x96 -#define BH1730_DATA1HIGH 0x97 -/* Software reset */ -#define BH1730_RESET 0xE4 - -/* Registers bits */ -#define BH1730_CONTROL_ADC_INTR_INACTIVE (0x00 << 5) -#define BH1730_CONTROL_ADC_INTR_ACTIVE (0x01 << 5) -#define BH1730_CONTROL_ADC_VALID (0x01 << 4) -#define BH1730_CONTROL_ONE_TIME_CONTINOUS (0x00 << 3) -#define BH1730_CONTROL_ONE_TIME_ONETIME (0x01 << 3) -#define BH1730_CONTROL_DATA_SEL_TYPE0_AND_1 (0x00 << 2) -#define BH1730_CONTROL_DATA_SEL_TYPE0 (0x01 << 2) -#define BH1730_CONTROL_ADC_EN_DISABLE (0x00 << 1) -#define BH1730_CONTROL_ADC_EN_ENABLE (0x01 << 1) -#define BH1730_CONTROL_POWER_DISABLE (0x00 << 0) -#define BH1730_CONTROL_POWER_ENABLE (0x01 << 0) - -#define BH1730_GAIN_GAIN_X1_GAIN (0x00 << 0) -#define BH1730_GAIN_GAIN_X2_GAIN (0x01 << 0) -#define BH1730_GAIN_GAIN_X64_GAIN (0x02 << 0) -#define BH1730_GAIN_GAIN_X128_GAIN (0x03 << 0) - -/* Sensor configuration */ -/* Select Gain */ -#define BH1730_CONF_GAIN BH1730_GAIN_GAIN_X64_GAIN -#define BH1730_GAIN_DIV 64 - -/* Select Itime, 0xDA is 102.6ms = 38*2.7ms */ -#define BH1730_CONF_ITIME 0xDA -#define ITIME_MS_X_10 ((256 - BH1730_CONF_ITIME) * 27) -#define ITIME_MS_X_1K (ITIME_MS_X_10*100) - -/* default Itime is about 10Hz */ -#define BH1730_10000_MHZ (10*1000) -#define BH1730_MAX_FREQ BH1730_10000_MHZ -/* - * 10Hz is too fast for the AP: allow the AP query data less often, the EC will - * downsample. - */ -#define BH1730_MIN_FREQ (BH1730_MAX_FREQ / 100) - -/* - * Use default lux calculation formula parameters if board specific - * parameters are not defined. - */ -#ifndef CONFIG_ALS_BH1730_LUXTH_PARAMS -#define BH1730_LUXTH1_1K 260 -#define BH1730_LUXTH1_D0_1K 1290 -#define BH1730_LUXTH1_D1_1K 2733 -#define BH1730_LUXTH2_1K 550 -#define BH1730_LUXTH2_D0_1K 797 -#define BH1730_LUXTH2_D1_1K 859 -#define BH1730_LUXTH3_1K 1090 -#define BH1730_LUXTH3_D0_1K 510 -#define BH1730_LUXTH3_D1_1K 345 -#define BH1730_LUXTH4_1K 2130 -#define BH1730_LUXTH4_D0_1K 276 -#define BH1730_LUXTH4_D1_1K 130 -#endif - -#define BH1730_GET_DATA(_s) ((struct bh1730_drv_data_t *)(_s)->drv_data) - -struct bh1730_drv_data_t { - int rate; - int last_value; -}; - -extern const struct accelgyro_drv bh1730_drv; - -#endif /* __CROS_EC_ALS_BH1730_H */ - diff --git a/driver/als_isl29035.c b/driver/als_isl29035.c deleted file mode 100644 index db77a19f09..0000000000 --- a/driver/als_isl29035.c +++ /dev/null @@ -1,73 +0,0 @@ -/* Copyright 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. - * - * Intersil ILS29035 light sensor driver - */ - -#include "driver/als_isl29035.h" -#include "i2c.h" - -/* I2C interface */ -#define ILS29035_I2C_ADDR_FLAGS 0x44 -#define ILS29035_REG_COMMAND_I 0 -#define ILS29035_REG_COMMAND_II 1 -#define ILS29035_REG_DATA_LSB 2 -#define ILS29035_REG_DATA_MSB 3 -#define ILS29035_REG_INT_LT_LSB 4 -#define ILS29035_REG_INT_LT_MSB 5 -#define ILS29035_REG_INT_HT_LSB 6 -#define ILS29035_REG_INT_HT_MSB 7 -#define ILS29035_REG_ID 15 - -int isl29035_init(void) -{ - /* - * Tell it to read continually. This uses 70uA, as opposed to nearly - * zero, but it makes the hook/update code cleaner (we don't want to - * wait 90ms to read on demand while processing hook callbacks). - */ - return i2c_write8(I2C_PORT_ALS, ILS29035_I2C_ADDR_FLAGS, - ILS29035_REG_COMMAND_I, 0xa0); -} - -int isl29035_read_lux(int *lux, int af) -{ - int rv, lsb, msb, data; - - /* - * NOTE: It is necessary to read the LSB first, then the MSB. If you do - * it in the opposite order, the results are not correct. This is - * apparently an undocumented "feature". It's especially noticeable in - * one-shot mode. - */ - - /* Read lsb */ - rv = i2c_read8(I2C_PORT_ALS, ILS29035_I2C_ADDR_FLAGS, - ILS29035_REG_DATA_LSB, &lsb); - if (rv) - return rv; - - /* Read msb */ - rv = i2c_read8(I2C_PORT_ALS, ILS29035_I2C_ADDR_FLAGS, - ILS29035_REG_DATA_MSB, &msb); - if (rv) - return rv; - - data = (msb << 8) | lsb; - - /* - * The default power-on values will give 16 bits of precision: - * 0x0000-0xffff indicates 0-1000 lux. We multiply the sensor value by - * a scaling factor to account for attentuation by glass, tinting, etc. - * - * Caution: Don't go nuts with the attentuation factor. If it's - * greater than 32, the signed int math will roll over and you'll get - * very wrong results. Of course, if you have that much attenuation and - * are still getting useful readings, you probably have your sensor - * pointed directly into the sun. - */ - *lux = data * af * 1000 / 0xffff; - - return EC_SUCCESS; -} diff --git a/driver/als_isl29035.h b/driver/als_isl29035.h deleted file mode 100644 index 153ba148f9..0000000000 --- a/driver/als_isl29035.h +++ /dev/null @@ -1,14 +0,0 @@ -/* Copyright 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. - * - * Intersil ILS29035 light sensor driver - */ - -#ifndef __CROS_EC_ALS_ISL29035_H -#define __CROS_EC_ALS_ISL29035_H - -int isl29035_init(void); -int isl29035_read_lux(int *lux, int af); - -#endif /* __CROS_EC_ALS_ISL29035_H */ diff --git a/driver/als_opt3001.c b/driver/als_opt3001.c deleted file mode 100644 index 53f2b7df89..0000000000 --- a/driver/als_opt3001.c +++ /dev/null @@ -1,315 +0,0 @@ -/* 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. - * - * TI OPT3001 light sensor driver - */ - -#include "common.h" -#include "driver/als_opt3001.h" -#include "i2c.h" - -#ifdef HAS_TASK_ALS -/** - * Read register from OPT3001 light sensor. - */ -static int opt3001_i2c_read(const int reg, int *data_ptr) -{ - int ret; - - ret = i2c_read16(I2C_PORT_ALS, OPT3001_I2C_ADDR_FLAGS, - reg, data_ptr); - if (!ret) - *data_ptr = ((*data_ptr << 8) & 0xFF00) | - ((*data_ptr >> 8) & 0x00FF); - - return ret; -} - -/** - * Write register to OPT3001 light sensor. - */ -static int opt3001_i2c_write(const int reg, int data) -{ - data = ((data << 8) & 0xFF00) | ((data >> 8) & 0x00FF); - return i2c_write16(I2C_PORT_ALS, OPT3001_I2C_ADDR_FLAGS, - reg, data); -} - -/** - * Initialise OPT3001 light sensor. - */ -int opt3001_init(void) -{ - int data; - int ret; - - ret = opt3001_i2c_read(OPT3001_REG_MAN_ID, &data); - if (ret) - return ret; - if (data != OPT3001_MANUFACTURER_ID) - return EC_ERROR_UNKNOWN; - - ret = opt3001_i2c_read(OPT3001_REG_DEV_ID, &data); - if (ret) - return ret; - if (data != OPT3001_DEVICE_ID) - return EC_ERROR_UNKNOWN; - - /* - * [15:12]: 0101b Automatic full scale (1310.40lux, 0.32lux/lsb) - * [11] : 1b Conversion time 800ms - * [10:9] : 10b Continuous Mode of conversion operation - * [4] : 1b Latched window-style comparison operation - */ - return opt3001_i2c_write(OPT3001_REG_CONFIGURE, 0x5C10); -} - -/** - * Read OPT3001 light sensor data. - */ -int opt3001_read_lux(int *lux, int af) -{ - int ret; - int data; - - ret = opt3001_i2c_read(OPT3001_REG_RESULT, &data); - if (ret) - return ret; - - /* - * The default power-on values will give 12 bits of precision: - * 0x0000-0x0fff indicates 0 to 1310.40 lux. We multiply the sensor - * value by a scaling factor to account for attenuation by glass, - * tinting, etc. - */ - - /* - * lux = 2EXP[3:0] × R[11:0] / 100 - */ - *lux = (1 << ((data & 0xF000) >> 12)) * (data & 0x0FFF) * af / 100; - - return EC_SUCCESS; -} - -#ifdef CONFIG_CMD_I2C_STRESS_TEST_ALS -struct i2c_stress_test_dev opt3001_i2c_stress_test_dev = { - .reg_info = { - .read_reg = OPT3001_REG_DEV_ID, - .read_val = OPT3001_DEVICE_ID, - .write_reg = OPT3001_REG_INT_LIMIT_LSB, - }, - .i2c_read_dev = &opt3001_i2c_read, - .i2c_write_dev = &opt3001_i2c_write, -}; -#endif /* CONFIG_CMD_I2C_STRESS_TEST_ALS */ -#else /* HAS_TASK_ALS */ -#include "accelgyro.h" -#include "math_util.h" - -/** - * Read register from OPT3001 light sensor. - */ -static int opt3001_i2c_read(const int port, - const uint16_t i2c_addr_flags, - const int reg, int *data_ptr) -{ - int ret; - - ret = i2c_read16(port, i2c_addr_flags, - reg, data_ptr); - if (!ret) - *data_ptr = ((*data_ptr << 8) & 0xFF00) | - ((*data_ptr >> 8) & 0x00FF); - - return ret; -} - -/** - * Write register to OPT3001 light sensor. - */ -static int opt3001_i2c_write(const int port, - const uint16_t i2c_addr_flags, - const int reg, int data) -{ - data = ((data << 8) & 0xFF00) | ((data >> 8) & 0x00FF); - return i2c_write16(port, i2c_addr_flags, reg, data); -} - -/** - * Read OPT3001 light sensor data. - */ -int opt3001_read_lux(const struct motion_sensor_t *s, intv3_t v) -{ - struct opt3001_drv_data_t *drv_data = OPT3001_GET_DATA(s); - int ret; - int data; - - ret = opt3001_i2c_read(s->port, s->i2c_spi_addr_flags, - OPT3001_REG_RESULT, &data); - if (ret) - return ret; - - /* - * lux = 2EXP[3:0] × R[11:0] / 100 - */ - data = (1 << (data >> 12)) * (data & 0x0FFF); - data += drv_data->offset * 100; - data = data * drv_data->scale + data * drv_data->uscale / 10000; - data /= 100; - - if (data < 0) - data = 1; - - v[0] = data; - v[1] = 0; - v[2] = 0; - - /* - * Return an error when nothing change to prevent filling the - * fifo with useless data. - */ - if (v[0] == drv_data->last_value) - return EC_ERROR_UNCHANGED; - else { - drv_data->last_value = v[0]; - return EC_SUCCESS; - } -} - -static int opt3001_set_range(struct motion_sensor_t *s, int range, - int rnd) -{ - struct opt3001_drv_data_t *drv_data = OPT3001_GET_DATA(s); - - drv_data->scale = range >> 16; - drv_data->uscale = range & 0xffff; - s->current_range = range; - return EC_SUCCESS; -} - -static int opt3001_set_data_rate(const struct motion_sensor_t *s, - int rate, int roundup) -{ - struct opt3001_drv_data_t *drv_data = OPT3001_GET_DATA(s); - int rv; - int reg; - enum opt3001_mode mode; - - if (rate == 0) { - /* - * Suspend driver: - */ - mode = OPT3001_MODE_SUSPEND; - } else { - mode = OPT3001_MODE_CONTINUOUS; - /* - * We set the sensor for continuous mode, - * integrating over 800ms. - * Do not allow range higher than 1Hz. - */ - if (rate > OPT3001_LIGHT_MAX_FREQ) - rate = OPT3001_LIGHT_MAX_FREQ; - } - rv = opt3001_i2c_read(s->port, s->i2c_spi_addr_flags, - OPT3001_REG_CONFIGURE, ®); - if (rv) - return rv; - - rv = opt3001_i2c_write(s->port, s->i2c_spi_addr_flags, - OPT3001_REG_CONFIGURE, - (reg & OPT3001_MODE_MASK) | - (mode << OPT3001_MODE_OFFSET)); - if (rv) - return rv; - - drv_data->rate = rate; - return EC_SUCCESS; -} - -static int opt3001_get_data_rate(const struct motion_sensor_t *s) -{ - struct opt3001_drv_data_t *drv_data = OPT3001_GET_DATA(s); - - return drv_data->rate; -} - -static int opt3001_set_offset(const struct motion_sensor_t *s, - const int16_t *offset, - int16_t temp) -{ - struct opt3001_drv_data_t *drv_data = OPT3001_GET_DATA(s); - - drv_data->offset = offset[X]; - return EC_SUCCESS; -} - -static int opt3001_get_offset(const struct motion_sensor_t *s, - int16_t *offset, - int16_t *temp) -{ - struct opt3001_drv_data_t *drv_data = OPT3001_GET_DATA(s); - - offset[X] = drv_data->offset; - offset[Y] = 0; - offset[Z] = 0; - *temp = EC_MOTION_SENSE_INVALID_CALIB_TEMP; - return EC_SUCCESS; -} -/** - * Initialise OPT3001 light sensor. - */ -static int opt3001_init(struct motion_sensor_t *s) -{ - int data; - int ret; - - ret = opt3001_i2c_read(s->port, s->i2c_spi_addr_flags, - OPT3001_REG_MAN_ID, &data); - if (ret) - return ret; - if (data != OPT3001_MANUFACTURER_ID) - return EC_ERROR_ACCESS_DENIED; - - ret = opt3001_i2c_read(s->port, s->i2c_spi_addr_flags, - OPT3001_REG_DEV_ID, &data); - if (ret) - return ret; - if (data != OPT3001_DEVICE_ID) - return EC_ERROR_ACCESS_DENIED; - - /* - * [15-12]: 1100b Automatic full-scale setting mode - * [11] : 1b Conversion time 800ms - * [4] : 1b Latched window-style comparison operation - */ - opt3001_i2c_write(s->port, s->i2c_spi_addr_flags, - OPT3001_REG_CONFIGURE, 0xC810); - - opt3001_set_range(s, s->default_range, 0); - - return EC_SUCCESS; -} - -const struct accelgyro_drv opt3001_drv = { - .init = opt3001_init, - .read = opt3001_read_lux, - .set_range = opt3001_set_range, - .set_offset = opt3001_set_offset, - .get_offset = opt3001_get_offset, - .set_data_rate = opt3001_set_data_rate, - .get_data_rate = opt3001_get_data_rate, -}; - -#ifdef CONFIG_CMD_I2C_STRESS_TEST_ALS -struct i2c_stress_test_dev opt3001_i2c_stress_test_dev = { - .reg_info = { - .read_reg = OPT3001_REG_DEV_ID, - .read_val = OPT3001_DEVICE_ID, - .write_reg = OPT3001_REG_INT_LIMIT_LSB, - }, - .i2c_read = &opt3001_i2c_read, - .i2c_write = &opt3001_i2c_write, -}; -#endif /* CONFIG_CMD_I2C_STRESS_TEST_ALS */ -#endif /* HAS_TASK_ALS */ diff --git a/driver/als_opt3001.h b/driver/als_opt3001.h deleted file mode 100644 index 96b47232d1..0000000000 --- a/driver/als_opt3001.h +++ /dev/null @@ -1,71 +0,0 @@ -/* 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. - * - * TI OPT3001 light sensor driver - */ - -#ifndef __CROS_EC_ALS_OPT3001_H -#define __CROS_EC_ALS_OPT3001_H - -/* I2C interface */ -#define OPT3001_I2C_ADDR1_FLAGS 0x44 -#define OPT3001_I2C_ADDR2_FLAGS 0x45 -#define OPT3001_I2C_ADDR3_FLAGS 0x46 -#define OPT3001_I2C_ADDR4_FLAGS 0x47 - -/* OPT3001 registers */ -#define OPT3001_REG_RESULT 0x00 -#define OPT3001_REG_CONFIGURE 0x01 -#define OPT3001_RANGE_OFFSET 12 -#define OPT3001_RANGE_MASK 0x0fff -#define OPT3001_MODE_OFFSET 9 -#define OPT3001_MODE_MASK 0xf9ff -enum opt3001_mode { - OPT3001_MODE_SUSPEND, - OPT3001_MODE_FORCED, - OPT3001_MODE_CONTINUOUS, -}; - -#define OPT3001_REG_INT_LIMIT_LSB 0x02 -#define OPT3001_REG_INT_LIMIT_MSB 0x03 -#define OPT3001_REG_MAN_ID 0x7e -#define OPT3001_REG_DEV_ID 0x7f - -/* OPT3001 register values */ -#define OPT3001_MANUFACTURER_ID 0x5449 -#define OPT3001_DEVICE_ID 0x3001 - -/* - * Min and Max sampling frequency in mHz. - * Due to integration set at 800ms, we limit max frequency to 1Hz. - */ -#define OPT3001_LIGHT_MIN_FREQ 100 -#define OPT3001_LIGHT_MAX_FREQ 1000 -#if (CONFIG_EC_MAX_SENSOR_FREQ_MILLIHZ <= OPT3001_LIGHT_MAX_FREQ) -#error "EC too slow for light sensor" -#endif - -#ifdef HAS_TASK_ALS -int opt3001_init(void); -int opt3001_read_lux(int *lux, int af); -#else -#define OPT3001_GET_DATA(_s) ((struct opt3001_drv_data_t *)(_s)->drv_data) - -struct opt3001_drv_data_t { - int rate; - int last_value; - /* the coef is scale.uscale */ - int16_t scale; - uint16_t uscale; - int16_t offset; -}; - -extern const struct accelgyro_drv opt3001_drv; -#endif - -#ifdef CONFIG_CMD_I2C_STRESS_TEST_ALS -extern struct i2c_stress_test_dev opt3001_i2c_stress_test_dev; -#endif - -#endif /* __CROS_EC_ALS_OPT3001_H */ diff --git a/driver/als_si114x.c b/driver/als_si114x.c deleted file mode 100644 index 262f3f076b..0000000000 --- a/driver/als_si114x.c +++ /dev/null @@ -1,596 +0,0 @@ -/* 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. - * - * Silicon Image SI1141/SI1142 light sensor driver - * - * Started from linux si114x driver. - */ -#include "accelgyro.h" -#include "common.h" -#include "console.h" -#include "driver/als_si114x.h" -#include "hooks.h" -#include "hwtimer.h" -#include "i2c.h" -#include "math_util.h" -#include "motion_sense_fifo.h" -#include "task.h" -#include "timer.h" -#include "util.h" - -#define CPUTS(outstr) cputs(CC_ACCEL, outstr) -#define CPRINTF(format, args...) cprintf(CC_ACCEL, format, ## args) -#define CPRINTS(format, args...) cprints(CC_ACCEL, format, ## args) - -static int init(struct motion_sensor_t *s); - -/** - * Read 8bit register from device. - */ -static inline int raw_read8(const int port, const uint16_t i2c_addr_flags, - const int reg, int *data_ptr) -{ - return i2c_read8(port, i2c_addr_flags, reg, data_ptr); -} - -/** - * Write 8bit register from device. - */ -static inline int raw_write8(const int port, const uint16_t i2c_addr_flags, - const int reg, int data) -{ - return i2c_write8(port, i2c_addr_flags, reg, data); -} - -/** - * Read 16bit register from device. - */ -static inline int raw_read16(const int port, const uint16_t i2c_addr_flags, - const int reg, int *data_ptr) -{ - return i2c_read16(port, i2c_addr_flags, reg, data_ptr); -} - -/* helper function to operate on parameter values: op can be query/set/or/and */ -static int si114x_param_op(const struct motion_sensor_t *s, - uint8_t op, - uint8_t param, - int *value) -{ - int ret; - - mutex_lock(s->mutex); - - if (op != SI114X_COMMAND_PARAM_QUERY) { - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - SI114X_PARAM_WR, *value); - if (ret != EC_SUCCESS) - goto error; - } - - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - SI114X_COMMAND, op | (param & 0x1F)); - if (ret != EC_SUCCESS) - goto error; - - ret = raw_read8(s->port, s->i2c_spi_addr_flags, - SI114X_PARAM_RD, value); - if (ret != EC_SUCCESS) - goto error; - - mutex_unlock(s->mutex); - - *value &= 0xff; - return EC_SUCCESS; -error: - mutex_unlock(s->mutex); - return ret; -} - -static int si114x_read_results(struct motion_sensor_t *s, int nb) -{ - int i, ret, val; - struct si114x_drv_data_t *data = SI114X_GET_DATA(s); - struct si114x_typed_data_t *type_data = SI114X_GET_TYPED_DATA(s); - - /* Read ALX result */ - for (i = 0; i < nb; i++) { - ret = raw_read16(s->port, s->i2c_spi_addr_flags, - type_data->base_data_reg + i * 2, - &val); - if (ret) - break; - if (val == SI114X_OVERFLOW) { - /* overflowing, try next time. */ - return EC_SUCCESS; - } else if (val + type_data->offset <= 0) { - /* No light */ - val = 1; - } else { - /* Add offset, calibration */ - val += type_data->offset; - } - /* - * Proximity sensor data is inverse of the distance. - * Return back something proportional to distance, - * we correct later with the scale parameter. - */ - if (s->type == MOTIONSENSE_TYPE_PROX) - val = BIT(16) / val; - val = val * type_data->scale + - val * type_data->uscale / 10000; - s->raw_xyz[i] = val; - } - - if (ret != EC_SUCCESS) - return ret; - - if (s->type == MOTIONSENSE_TYPE_PROX) - data->covered = (s->raw_xyz[0] < SI114X_COVERED_THRESHOLD); - else if (data->covered) - /* - * The sensor (proximity & light) is covered. The light data - * will most likely be incorrect (darker than expected), so - * ignore the measurement. - */ - return EC_SUCCESS; - - /* Add in fifo if changed only */ - for (i = 0; i < nb; i++) { - if (s->raw_xyz[i] != s->xyz[i]) - break; - } - if (i == nb) - return EC_ERROR_UNCHANGED; - - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) { - struct ec_response_motion_sensor_data vector; - - vector.flags = 0; - for (i = 0; i < nb; i++) - vector.data[i] = s->raw_xyz[i]; - for (i = nb; i < 3; i++) - vector.data[i] = 0; - vector.sensor_num = s - motion_sensors; - motion_sense_fifo_stage_data(&vector, s, nb, - __hw_clock_source_read()); - motion_sense_fifo_commit_data(); - /* - * TODO: get time at a more accurate spot. - * Like in si114x_interrupt - */ - } - /* Otherwise, we need to copy raw_xyz into xyz with mutex */ - return EC_SUCCESS; -} - -void si114x_interrupt(enum gpio_signal signal) -{ - task_set_event(TASK_ID_MOTIONSENSE, CONFIG_ALS_SI114X_INT_EVENT); -} - -#ifdef CONFIG_ALS_SI114X_POLLING -static void si114x_read_deferred(void) -{ - task_set_event(TASK_ID_MOTIONSENSE, CONFIG_ALS_SI114X_INT_EVENT); -} -DECLARE_DEFERRED(si114x_read_deferred); -#endif - -/** - * irq_handler - bottom half of the interrupt stack. - * Ran from the motion_sense task, finds the events that raised the interrupt. - * - * For now, we just print out. We should set a bitmask motion sense code will - * act upon. - */ -static int irq_handler(struct motion_sensor_t *s, uint32_t *event) -{ - int ret = EC_SUCCESS, val; - struct si114x_drv_data_t *data = SI114X_GET_DATA(s); - struct si114x_typed_data_t *type_data = SI114X_GET_TYPED_DATA(s); - - if (!(*event & CONFIG_ALS_SI114X_INT_EVENT)) - return EC_ERROR_NOT_HANDLED; - - ret = raw_read8(s->port, s->i2c_spi_addr_flags, - SI114X_IRQ_STATUS, &val); - if (ret) - return ret; - - if (!(val & type_data->irq_flags)) - return EC_ERROR_INVAL; - - /* clearing IRQ */ - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - SI114X_IRQ_STATUS, - val & type_data->irq_flags); - if (ret != EC_SUCCESS) - CPRINTS("clearing irq failed"); - - switch (data->state) { - case SI114X_ALS_IN_PROGRESS: - case SI114X_ALS_IN_PROGRESS_PS_PENDING: - /* We are only reading the visible light sensor */ - ret = si114x_read_results(s, 1); - /* Fire pending requests */ - if (data->state == SI114X_ALS_IN_PROGRESS_PS_PENDING) { - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - SI114X_COMMAND, - SI114X_COMMAND_PS_FORCE); - data->state = SI114X_PS_IN_PROGRESS; - } else { - data->state = SI114X_IDLE; - } - break; - case SI114X_PS_IN_PROGRESS: - case SI114X_PS_IN_PROGRESS_ALS_PENDING: - /* Read PS results */ - ret = si114x_read_results(s, SI114X_NUM_LEDS); - if (data->state == SI114X_PS_IN_PROGRESS_ALS_PENDING) { - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - SI114X_COMMAND, - SI114X_COMMAND_ALS_FORCE); - data->state = SI114X_ALS_IN_PROGRESS; - } else { - data->state = SI114X_IDLE; - } - break; - case SI114X_IDLE: - default: - CPRINTS("Invalid state"); - } - return ret; -} - -/* Just trigger a measurement */ -static int read(const struct motion_sensor_t *s, intv3_t v) -{ - int ret = 0; - uint8_t cmd; - struct si114x_drv_data_t *data = SI114X_GET_DATA(s); - - switch (data->state) { - case SI114X_ALS_IN_PROGRESS: - if (s->type == MOTIONSENSE_TYPE_PROX) - data->state = SI114X_ALS_IN_PROGRESS_PS_PENDING; -#if 0 - else - CPRINTS("Invalid state"); -#endif - ret = EC_ERROR_BUSY; - break; - case SI114X_PS_IN_PROGRESS: - if (s->type == MOTIONSENSE_TYPE_LIGHT) - data->state = SI114X_PS_IN_PROGRESS_ALS_PENDING; -#if 0 - else - CPRINTS("Invalid state"); -#endif - ret = EC_ERROR_BUSY; - break; - case SI114X_IDLE: - switch (s->type) { - case MOTIONSENSE_TYPE_LIGHT: - cmd = SI114X_COMMAND_ALS_FORCE; - data->state = SI114X_ALS_IN_PROGRESS; - break; - case MOTIONSENSE_TYPE_PROX: - cmd = SI114X_COMMAND_PS_FORCE; - data->state = SI114X_PS_IN_PROGRESS; - break; - default: - CPRINTS("Invalid sensor type"); - return EC_ERROR_INVAL; - } - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - SI114X_COMMAND, cmd); -#ifdef CONFIG_ALS_SI114X_POLLING - hook_call_deferred(&si114x_read_deferred_data, - SI114x_POLLING_DELAY); -#endif - ret = EC_RES_IN_PROGRESS; - break; - case SI114X_ALS_IN_PROGRESS_PS_PENDING: - case SI114X_PS_IN_PROGRESS_ALS_PENDING: - ret = EC_ERROR_ACCESS_DENIED; - break; - case SI114X_NOT_READY: - ret = EC_ERROR_NOT_POWERED; - } -#if 0 /* This code is incorrect https://crbug.com/956569 */ - if (ret == EC_ERROR_ACCESS_DENIED && - s->type == MOTIONSENSE_TYPE_LIGHT) { - timestamp_t ts_now = get_time(); - - /* - * We were unable to access the sensor for THRES time. - * We should reset the sensor to clear the interrupt register - * and the state machine. - */ - if (time_after(ts_now.le.lo, - s->last_collection + SI114X_DENIED_THRESHOLD)) { - int ret, val; - - ret = raw_read8(s->port, s->addr, - SI114X_IRQ_STATUS, &val); - CPRINTS("%d stuck IRQ_STATUS 0x%02x - ret %d", - s->name, val, ret); - init(s); - } - } -#endif - return ret; -} - -static int si114x_set_chlist(const struct motion_sensor_t *s) -{ - int reg = 0; - - /* Not interested in temperature (AUX nor IR) */ - reg = SI114X_PARAM_CHLIST_EN_ALS_VIS; - switch (SI114X_NUM_LEDS) { - case 3: - reg |= SI114X_PARAM_CHLIST_EN_PS3; - case 2: - reg |= SI114X_PARAM_CHLIST_EN_PS3; - case 1: - reg |= SI114X_PARAM_CHLIST_EN_PS3; - break; - } - - return si114x_param_op(s, SI114X_COMMAND_PARAM_SET, - SI114X_PARAM_CHLIST, ®); -} - -#ifdef CONFIG_ALS_SI114X_CHECK_REVISION -static int si114x_revisions(const struct motion_sensor_t *s) -{ - int val; - int ret = raw_read8(s->port, s->addr, SI114X_PART_ID, &val); - if (ret != EC_SUCCESS) - return ret; - - if (val != CONFIG_ALS_SI114X) { - CPRINTS("invalid part"); - return EC_ERROR_ACCESS_DENIED; - } - - ret = raw_read8(s->port, s->port, s->addr, SI114X_SEQ_ID, &val); - if (ret != EC_SUCCESS) - return ret; - - if (val < SI114X_SEQ_REV_A03) - CPRINTS("WARNING: old sequencer revision"); - - return 0; -} -#endif - -static int si114x_initialize(const struct motion_sensor_t *s) -{ - int ret, val; - - /* send reset command */ - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - SI114X_COMMAND, SI114X_COMMAND_RESET); - if (ret != EC_SUCCESS) - return ret; - msleep(20); - - /* hardware key, magic value */ - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - SI114X_HW_KEY, SI114X_HW_KEY_VALUE); - if (ret != EC_SUCCESS) - return ret; - msleep(20); - - /* interrupt configuration, interrupt output enable */ - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - SI114X_INT_CFG, SI114X_INT_CFG_INT_OE); - if (ret != EC_SUCCESS) - return ret; - - /* enable interrupt for certain activities */ - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - SI114X_IRQ_ENABLE, - SI114X_IRQ_ENABLE_PS3_IE | - SI114X_IRQ_ENABLE_PS2_IE | - SI114X_IRQ_ENABLE_PS1_IE | - SI114X_IRQ_ENABLE_ALS_IE_INT0); - if (ret != EC_SUCCESS) - return ret; - - /* Only forced mode */ - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - SI114X_MEAS_RATE, 0); - if (ret != EC_SUCCESS) - return ret; - - /* measure ALS every time device wakes up */ - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - SI114X_ALS_RATE, 0); - if (ret != EC_SUCCESS) - return ret; - - /* measure proximity every time device wakes up */ - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - SI114X_PS_RATE, 0); - if (ret != EC_SUCCESS) - return ret; - - /* set LED currents to maximum */ - switch (SI114X_NUM_LEDS) { - case 3: - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - SI114X_PS_LED3, 0x0f); - if (ret != EC_SUCCESS) - return ret; - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - SI114X_PS_LED21, 0xff); - break; - case 2: - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - SI114X_PS_LED21, 0xff); - break; - case 1: - ret = raw_write8(s->port, s->i2c_spi_addr_flags, - SI114X_PS_LED21, 0x0f); - break; - } - if (ret != EC_SUCCESS) - return ret; - - ret = si114x_set_chlist(s); - if (ret != EC_SUCCESS) - return ret; - - /* set normal proximity measurement mode, set high signal range - * PS measurement */ - val = SI114X_PARAM_PS_ADC_MISC_MODE_NORMAL_PROXIMITY; - ret = si114x_param_op(s, SI114X_COMMAND_PARAM_SET, - SI114X_PARAM_PS_ADC_MISC, &val); - return ret; -} - -static int set_resolution(const struct motion_sensor_t *s, - int res, - int rnd) -{ - int ret, reg1, reg2, val; - /* override on resolution: set the gain. between 0 to 7 */ - if (s->type == MOTIONSENSE_TYPE_PROX) { - if (res < 0 || res > 5) - return EC_ERROR_PARAM2; - reg1 = SI114X_PARAM_PS_ADC_GAIN; - reg2 = SI114X_PARAM_PS_ADC_COUNTER; - } else { - if (res < 0 || res > 7) - return EC_ERROR_PARAM2; - reg1 = SI114X_PARAM_ALS_VIS_ADC_GAIN; - reg2 = SI114X_PARAM_ALS_VIS_ADC_COUNTER; - } - - val = res; - ret = si114x_param_op(s, SI114X_COMMAND_PARAM_SET, reg1, &val); - if (ret != EC_SUCCESS) - return ret; - /* set recovery period to one's complement of gain */ - val = (~res & 0x07) << 4; - ret = si114x_param_op(s, SI114X_COMMAND_PARAM_SET, reg2, &val); - return ret; -} - -static int get_resolution(const struct motion_sensor_t *s) -{ - int ret, reg, val; - if (s->type == MOTIONSENSE_TYPE_PROX) - reg = SI114X_PARAM_PS_ADC_GAIN; - else - /* ignore IR led */ - reg = SI114X_PARAM_ALS_VIS_ADC_GAIN; - - val = 0; - ret = si114x_param_op(s, SI114X_COMMAND_PARAM_QUERY, reg, &val); - if (ret != EC_SUCCESS) - return -1; - - return val & 0x07; -} - -static int set_range(struct motion_sensor_t *s, - int range, - int rnd) -{ - struct si114x_typed_data_t *data = SI114X_GET_TYPED_DATA(s); - data->scale = range >> 16; - data->uscale = range & 0xffff; - s->current_range = range; - return EC_SUCCESS; -} - -static int get_data_rate(const struct motion_sensor_t *s) -{ - /* Sensor in forced mode, rate is used by motion_sense */ - struct si114x_typed_data_t *data = SI114X_GET_TYPED_DATA(s); - return data->rate; -} - -static int set_data_rate(const struct motion_sensor_t *s, - int rate, - int rnd) -{ - struct si114x_typed_data_t *data = SI114X_GET_TYPED_DATA(s); - data->rate = rate; - return EC_SUCCESS; -} - -static int set_offset(const struct motion_sensor_t *s, - const int16_t *offset, - int16_t temp) -{ - struct si114x_typed_data_t *data = SI114X_GET_TYPED_DATA(s); - data->offset = offset[X]; - return EC_SUCCESS; -} - -static int get_offset(const struct motion_sensor_t *s, - int16_t *offset, - int16_t *temp) -{ - struct si114x_typed_data_t *data = SI114X_GET_TYPED_DATA(s); - offset[X] = data->offset; - offset[Y] = 0; - offset[Z] = 0; - *temp = EC_MOTION_SENSE_INVALID_CALIB_TEMP; - return EC_SUCCESS; -} - -static int init(struct motion_sensor_t *s) -{ - int ret, resol; - struct si114x_drv_data_t *data = SI114X_GET_DATA(s); - - /* initialize only once: light must be declared first. */ - if (s->type == MOTIONSENSE_TYPE_LIGHT) { -#ifdef CONFIG_ALS_SI114X_CHECK_REVISION - ret = si114x_revisions(s); - if (ret != EC_SUCCESS) - return ret; -#endif - ret = si114x_initialize(s); - if (ret != EC_SUCCESS) - return ret; - - data->state = SI114X_IDLE; - resol = 7; - } else { - if (data->state == SI114X_NOT_READY) - return EC_ERROR_ACCESS_DENIED; - resol = 5; - } - - /* - * Sensor is most likely behind a glass. - * Max out the gain to get correct measurement - */ - set_resolution(s, resol, 0); - - return sensor_init_done(s); -} - -const struct accelgyro_drv si114x_drv = { - .init = init, - .read = read, - .set_range = set_range, - .set_resolution = set_resolution, - .get_resolution = get_resolution, - .set_data_rate = set_data_rate, - .get_data_rate = get_data_rate, - .set_offset = set_offset, - .get_offset = get_offset, -#ifdef CONFIG_ACCEL_INTERRUPTS - .irq_handler = irq_handler, -#endif -}; diff --git a/driver/als_si114x.h b/driver/als_si114x.h deleted file mode 100644 index 2084c55f09..0000000000 --- a/driver/als_si114x.h +++ /dev/null @@ -1,120 +0,0 @@ -/* 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. - * - * Silicon Image SI1141/SI1142 light sensor driver - */ - -#ifndef __CROS_EC_ALS_SI114X_H -#define __CROS_EC_ALS_SI114X_H - -#define SI114X_ADDR_FLAGS 0x5a - -#define SI114X_PART_ID 0x00 -#define SI114X_SEQ_ID 0x02 - -#define SI114X_INT_CFG 0x03 -#define SI114X_INT_CFG_INT_OE BIT(0) - -#define SI114X_IRQ_ENABLE 0x04 -#define SI114X_IRQ_ENABLE_PS3_IE BIT(4) -#define SI114X_IRQ_ENABLE_PS2_IE BIT(3) -#define SI114X_IRQ_ENABLE_PS1_IE BIT(2) -#define SI114X_IRQ_ENABLE_ALS_IE_INT1 BIT(1) -#define SI114X_IRQ_ENABLE_ALS_IE_INT0 BIT(0) - -#define SI114X_HW_KEY 0x07 -#define SI114X_HW_KEY_VALUE 0x17 - -#define SI114X_MEAS_RATE 0x08 -#define SI114X_ALS_RATE 0x09 -#define SI114X_PS_RATE 0x0A - -#define SI114X_PS_LED21 0x0F -#define SI114X_PS_LED3 0x10 -#define SI114X_NUM_LEDS (CONFIG_ALS_SI114X - 0x40) - -#define SI114X_PARAM_WR 0x17 -#define SI114X_COMMAND 0x18 - -#define SI114X_COMMAND_PARAM_QUERY 0x80 -#define SI114X_COMMAND_PARAM_SET 0xA0 -#define SI114X_PARAM_CHLIST 0x01 -#define SI114X_PARAM_CHLIST_EN_ALS_VIS BIT(4) -#define SI114X_PARAM_CHLIST_EN_PS3 BIT(2) -#define SI114X_PARAM_CHLIST_EN_PS2 BIT(1) -#define SI114X_PARAM_CHLIST_EN_PS1 BIT(0) -#define SI114X_PARAM_PS_ADC_COUNTER 0x0A -#define SI114X_PARAM_PS_ADC_GAIN 0x0B -#define SI114X_PARAM_PS_ADC_MISC 0x0C -#define SI114X_PARAM_PS_ADC_MISC_MODE BIT(2) -#define SI114X_PARAM_PS_ADC_MISC_MODE_NORMAL_PROXIMITY BIT(2) -#define SI114X_PARAM_ALS_VIS_ADC_COUNTER 0x10 -#define SI114X_PARAM_ALS_VIS_ADC_GAIN 0x11 -#define SI114X_PARAM_ALS_VIS_ADC_MISC 0x12 - -#define SI114X_COMMAND_RESET 0x01 -#define SI114X_COMMAND_PS_FORCE 0x05 -#define SI114X_COMMAND_ALS_FORCE 0x06 - -#define SI114X_IRQ_STATUS 0x21 -#define SI114X_ALS_VIS_DATA0 0x22 - -#define SI114X_PARAM_RD 0x2E - -/* Proximity sensor finds an object within 5 cm, disable light sensor */ -#define SI114X_COVERED_THRESHOLD 5 -#define SI114X_OVERFLOW 0xffff - -/* Time to wait before re-initializing the device if access is denied */ -#define SI114X_DENIED_THRESHOLD (10 * SECOND) - -/* Delay used for deferred callback when polling is enabled */ -#define SI114x_POLLING_DELAY (8 * MSEC) - -/* Min and Max sampling frequency in mHz */ -#define SI114X_PROX_MIN_FREQ 504 -#define SI114X_PROX_MAX_FREQ 50000 -#define SI114X_LIGHT_MIN_FREQ 504 -#define SI114X_LIGHT_MAX_FREQ 50000 -#if (CONFIG_EC_MAX_SENSOR_FREQ_MILLIHZ <= SI114X_PROX_MAX_FREQ) -#error "EC too slow for light sensor" -#endif - -extern const struct accelgyro_drv si114x_drv; - -enum si114x_state { - SI114X_NOT_READY, - SI114X_IDLE, - SI114X_ALS_IN_PROGRESS, - SI114X_ALS_IN_PROGRESS_PS_PENDING, - SI114X_PS_IN_PROGRESS, - SI114X_PS_IN_PROGRESS_ALS_PENDING, -}; - -struct si114x_typed_data_t { - uint8_t base_data_reg; - uint8_t irq_flags; - /* requested frequency, in mHz */ - int rate; - /* the coef is scale.uscale */ - int16_t scale; - uint16_t uscale; - int16_t offset; -}; - -struct si114x_drv_data_t { - enum si114x_state state; - uint8_t covered; - struct si114x_typed_data_t type_data[2]; -}; - -#define SI114X_GET_DATA(_s) \ - ((struct si114x_drv_data_t *)(_s)->drv_data) - -#define SI114X_GET_TYPED_DATA(_s) \ - (&SI114X_GET_DATA(_s)->type_data[(_s)->type - MOTIONSENSE_TYPE_PROX]) - -void si114x_interrupt(enum gpio_signal signal); - -#endif /* __CROS_EC_ALS_SI114X_H */ diff --git a/driver/als_tcs3400.c b/driver/als_tcs3400.c deleted file mode 100644 index 30b24c4412..0000000000 --- a/driver/als_tcs3400.c +++ /dev/null @@ -1,816 +0,0 @@ -/* Copyright 2019 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. - * - * AMS TCS3400 light sensor driver - */ -#include "accelgyro.h" -#include "common.h" -#include "console.h" -#include "als_tcs3400.h" -#include "hooks.h" -#include "hwtimer.h" -#include "i2c.h" -#include "math_util.h" -#include "motion_sense_fifo.h" -#include "task.h" -#include "util.h" - -#define CPRINTS(fmt, args...) cprints(CC_ACCEL, "%s "fmt, __func__, ## args) - -#if defined(CONFIG_ZEPHYR) && defined(CONFIG_ACCEL_INTERRUPTS) -/* - * Get the mostion sensor ID of the TCS3400 sensor that - * generates the interrupt. - * The interrupt is converted to the event and transferred to motion - * sense task that actually handles the interrupt. - * - * Here, we use alias to get the motion sensor ID - * - * e.g) als_clear below is the label of a child node in /motionsense-sensors - * aliases { - * tcs3400-int = &als_clear; - * }; - */ -#if DT_NODE_EXISTS(DT_ALIAS(tcs3400_int)) -#define CONFIG_ALS_TCS3400_INT_EVENT \ - TASK_EVENT_MOTION_SENSOR_INTERRUPT(SENSOR_ID(DT_ALIAS(tcs3400_int))) -#endif -#endif - -STATIC_IF(CONFIG_ACCEL_FIFO) volatile uint32_t last_interrupt_timestamp; - -#ifdef CONFIG_TCS_USE_LUX_TABLE -/* - * Stores the number of atime increments/decrements needed to change light value - * by 1% of saturation for each gain setting for each predefined LUX range. - * - * Values in array are TCS_ATIME_GAIN_FACTOR (100x) times actual value to allow - * for fractions using integers. - */ -static const uint16_t -range_atime[TCS_MAX_AGAIN - TCS_MIN_AGAIN + 1][TCS_MAX_ATIME_RANGES] = { -{11200, 5600, 5600, 7200, 5500, 4500, 3800, 3800, 3300, 2900, 2575, 2275, 2075}, -{11200, 5100, 2700, 1840, 1400, 1133, 981, 963, 833, 728, 650, 577, 525}, -{250, 1225, 643, 441, 337, 276, 253, 235, 203, 176, 150, 0, 0}, -{790, 261, 163, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; - -static void -decrement_atime(struct tcs_saturation_t *sat_p, uint16_t cur_lux, int percent) -{ - int atime; - uint16_t steps; - int lux = MIN(cur_lux, TCS_GAIN_TABLE_MAX_LUX); - - steps = percent * range_atime[sat_p->again][lux / 1000] / - TCS_ATIME_GAIN_FACTOR; - atime = MAX(sat_p->atime - steps, TCS_MIN_ATIME); - sat_p->atime = MIN(atime, TCS_MAX_ATIME); -} - -#else - -static void -decrement_atime(struct tcs_saturation_t *sat_p, - uint16_t __attribute__((unused)) cur_lux, - int __attribute__((unused)) percent) -{ - sat_p->atime = MAX(sat_p->atime - TCS_ATIME_DEC_STEP, TCS_MIN_ATIME); -} - -#endif /* CONFIG_TCS_USE_LUX_TABLE */ - -static void increment_atime(struct tcs_saturation_t *sat_p) -{ - sat_p->atime = MIN(sat_p->atime + TCS_ATIME_INC_STEP, TCS_MAX_ATIME); -} - -static inline int tcs3400_i2c_read8(const struct motion_sensor_t *s, - int reg, int *data) -{ - return i2c_read8(s->port, s->i2c_spi_addr_flags, reg, data); -} - -static inline int tcs3400_i2c_write8(const struct motion_sensor_t *s, - int reg, int data) -{ - return i2c_write8(s->port, s->i2c_spi_addr_flags, reg, data); -} - -static void tcs3400_read_deferred(void) -{ - task_set_event(TASK_ID_MOTIONSENSE, CONFIG_ALS_TCS3400_INT_EVENT); -} -DECLARE_DEFERRED(tcs3400_read_deferred); - -/* convert ATIME register to integration time, in microseconds */ -int tcs3400_get_integration_time(int atime) -{ - return TCS_MAX_INTEGRATION_TIME * (TCS_ATIME_GRANULARITY - atime); -} - -static int tcs3400_read(const struct motion_sensor_t *s, intv3_t v) -{ - int atime, again; - int ret; - - /* Chip may have been off, make sure to setup important registers */ - if (TCS3400_RGB_DRV_DATA(s+1)->calibration_mode) { - atime = TCS_CALIBRATION_ATIME; - again = TCS_CALIBRATION_AGAIN; - } else { - atime = TCS3400_RGB_DRV_DATA(s+1)->saturation.atime; - again = TCS3400_RGB_DRV_DATA(s+1)->saturation.again; - } - ret = tcs3400_i2c_write8(s, TCS_I2C_ATIME, atime); - if (ret) - return ret; - ret = tcs3400_i2c_write8(s, TCS_I2C_CONTROL, again); - if (ret) - return ret; - - /* Enable power, ADC, and interrupt to start cycle */ - ret = tcs3400_i2c_write8(s, TCS_I2C_ENABLE, TCS3400_MODE_COLLECTING); - if (ret) - return ret; - - if (IS_ENABLED(CONFIG_ALS_TCS3400_EMULATED_IRQ_EVENT)) { - int atime; - - ret = tcs3400_i2c_read8(s, TCS_I2C_ATIME, &atime); - if (ret) - return ret; - - hook_call_deferred(&tcs3400_read_deferred_data, - tcs3400_get_integration_time(atime)); - } - - /* - * If write succeeded, we've started the read process, but can't - * complete it yet until data is ready, so pass back EC_RES_IN_PROGRESS - * to inform upper level that read data process is under way and data - * will be delivered when available. - */ - return EC_RES_IN_PROGRESS; -} - -static int tcs3400_rgb_read(const struct motion_sensor_t *s, intv3_t v) -{ - ccprintf("WARNING: tcs3400_rgb_read() should never be called\n"); - return EC_SUCCESS; -} - -/* - * tcs3400_adjust_sensor_for_saturation() tries to keep CRGB values as - * close to saturation as possible without saturating by implementing - * the following logic: - * - * If any of the R, G, B, or C channels have saturated, then decrease AGAIN. - * If AGAIN is already at its minimum, increase ATIME if not at its max already. - * - * Else if none of the R, G, B, or C channels have saturated, and - * all samples read are less than 90% of saturation, then increase - * AGAIN if it is not already at its maximum, or if it is, decrease - * ATIME if it is not at it's minimum already. - */ -static int -tcs3400_adjust_sensor_for_saturation(struct motion_sensor_t *s, - uint16_t cur_lux, - uint16_t *crgb_data, - uint32_t status) -{ - struct tcs_saturation_t *sat_p = - &TCS3400_RGB_DRV_DATA(s+1)->saturation; - const uint8_t save_again = sat_p->again; - const uint8_t save_atime = sat_p->atime; - uint16_t max_val = 0; - int ret; - int percent_left = 0; - - /* Adjust for saturation if needed */ - if (!(status & TCS_I2C_STATUS_RGBC_VALID)) - return EC_SUCCESS; - - for (int i = 0; i < CRGB_COUNT; i++) - max_val = MAX(max_val, crgb_data[i]); - - /* Don't process if status isn't valid yet */ - if ((status & TCS_I2C_STATUS_ALS_SATURATED) || - (max_val >= TCS_SATURATION_LEVEL)) { - /* Saturation occurred, decrease AGAIN if we can */ - if (sat_p->again > TCS_MIN_AGAIN) - sat_p->again--; - else if (sat_p->atime < TCS_MAX_ATIME) - /* reduce accumulation time by incrementing ATIME reg */ - increment_atime(sat_p); - } else if (max_val < TSC_SATURATION_LOW_BAND_LEVEL) { - /* value < 90% saturation, try to increase sensitivity */ - if (max_val <= TCS_GAIN_SAT_LEVEL) { - if (sat_p->again < TCS_MAX_AGAIN) { - sat_p->again++; - } else if (sat_p->atime > TCS_MIN_ATIME) { - /* - * increase accumulation time by decrementing - * ATIME register - */ - percent_left = TSC_SATURATION_LOW_BAND_PERCENT - - (max_val * 100 / TCS_SATURATION_LEVEL); - decrement_atime(sat_p, cur_lux, percent_left); - } - } else if (sat_p->atime > TCS_MIN_ATIME) { - /* calculate percentage between current and desired */ - percent_left = TSC_SATURATION_LOW_BAND_PERCENT - - (max_val * 100 / TCS_SATURATION_LEVEL); - - /* increase accumulation time by decrementing ATIME */ - decrement_atime(sat_p, cur_lux, percent_left); - } else if (sat_p->again < TCS_MAX_AGAIN) { - /* - * Although we're not at maximum gain yet, we - * can't just increase gain because a 4x change - * in gain under these light conditions would - * saturate on the next sample. What we can do - * is to adjust atime to reduce sensitivity so - * that we may increase gain without saturation. - * This combination effectively acts as a half - * gain increase (2.5x estimate) instead of a full - * gain increase of > 4x that would result in - * saturation. - */ - if (max_val < TCS_GAIN_UPSHIFT_LEVEL) { - sat_p->atime = TCS_GAIN_UPSHIFT_ATIME; - sat_p->again++; - } - } - } - - /* If atime or gain setting changed, update atime and gain registers */ - if (save_again != sat_p->again) { - ret = tcs3400_i2c_write8(s, TCS_I2C_CONTROL, - (sat_p->again & TCS_I2C_CONTROL_MASK)); - if (ret) - return ret; - } - - if (save_atime != sat_p->atime) { - ret = tcs3400_i2c_write8(s, TCS_I2C_ATIME, sat_p->atime); - if (ret) - return ret; - } - - return EC_SUCCESS; -} - -/** - * normalize_channel_data - normalize the light data to remove effect of - * different atime and again settings from the sample. - */ -static uint32_t normalize_channel_data(struct motion_sensor_t *s, - uint32_t sample) -{ - struct tcs_saturation_t *sat_p = - &(TCS3400_RGB_DRV_DATA(s+1)->saturation); - const uint16_t cur_gain = (1 << (2 * sat_p->again)); - const uint16_t cal_again = (1 << (2 * TCS_CALIBRATION_AGAIN)); - - return DIV_ROUND_NEAREST(sample * (TCS_ATIME_GRANULARITY - - TCS_CALIBRATION_ATIME) * cal_again, - (TCS_ATIME_GRANULARITY - sat_p->atime) * - cur_gain); -} - - -__overridable void tcs3400_translate_to_xyz(struct motion_sensor_t *s, - int32_t *crgb_data, int32_t *xyz_data) -{ - struct tcs3400_rgb_drv_data_t *rgb_drv_data = TCS3400_RGB_DRV_DATA(s+1); - int32_t crgb_prime[CRGB_COUNT]; - int32_t ir; - int i; - - /* normalize the data for atime and again changes */ - for (i = 0; i < CRGB_COUNT; i++) - crgb_data[i] = normalize_channel_data(s, crgb_data[i]); - - /* IR removal */ - ir = FP_TO_INT(fp_mul(INT_TO_FP(crgb_data[1] + crgb_data[2] + - crgb_data[3] - crgb_data[0]), - rgb_drv_data->calibration.irt) / 2); - - for (i = 0; i < ARRAY_SIZE(crgb_prime); i++) { - if (crgb_data[i] < ir) - crgb_prime[i] = 0; - else - crgb_prime[i] = crgb_data[i] - ir; - } - - /* if CC == 0, set BC = 0 */ - if (crgb_prime[CLEAR_CRGB_IDX] == 0) - crgb_prime[BLUE_CRGB_IDX] = 0; - - /* regression fit to XYZ space */ - for (i = 0; i < 3; i++) { - const struct rgb_channel_calibration_t *p = - &rgb_drv_data->calibration.rgb_cal[i]; - - xyz_data[i] = p->offset + FP_TO_INT( - (fp_inter_t)p->coeff[RED_CRGB_IDX] * - crgb_prime[RED_CRGB_IDX] + - (fp_inter_t)p->coeff[GREEN_CRGB_IDX] * - crgb_prime[GREEN_CRGB_IDX] + - (fp_inter_t)p->coeff[BLUE_CRGB_IDX] * - crgb_prime[BLUE_CRGB_IDX] + - (fp_inter_t)p->coeff[CLEAR_CRGB_IDX] * - crgb_prime[CLEAR_CRGB_IDX]); - - if (xyz_data[i] < 0) - xyz_data[i] = 0; - } -} - -static void tcs3400_process_raw_data(struct motion_sensor_t *s, - uint8_t *raw_data_buf, - uint16_t *raw_light_data, int32_t *xyz_data) -{ - struct als_drv_data_t *als_drv_data = TCS3400_DRV_DATA(s); - struct tcs3400_rgb_drv_data_t *rgb_drv_data = TCS3400_RGB_DRV_DATA(s+1); - const uint8_t calibration_mode = rgb_drv_data->calibration_mode; - uint16_t k_channel_scale = - als_drv_data->als_cal.channel_scale.k_channel_scale; - uint16_t cover_scale = als_drv_data->als_cal.channel_scale.cover_scale; - int32_t crgb_data[CRGB_COUNT]; - int i; - - /* adjust for calibration and scale data */ - for (i = 0; i < CRGB_COUNT; i++) { - int index = i * 2; - - /* assemble the light value for this channel */ - crgb_data[i] = raw_light_data[i] = - ((raw_data_buf[index+1] << 8) | raw_data_buf[index]); - - /* in calibration mode, we only assemble the raw data */ - if (calibration_mode) - continue; - - /* rgb data at index 1, 2, and 3 owned by rgb driver, not ALS */ - if (i > 0) { - struct als_channel_scale_t *csp = - &rgb_drv_data->calibration.rgb_cal[i-1].scale; - k_channel_scale = csp->k_channel_scale; - cover_scale = csp->cover_scale; - } - - /* Step 1: divide by individual channel scale value */ - crgb_data[i] = SENSOR_APPLY_DIV_SCALE(crgb_data[i], - k_channel_scale); - - /* compensate for the light cover */ - crgb_data[i] = SENSOR_APPLY_SCALE(crgb_data[i], cover_scale); - } - - if (!calibration_mode) { - /* we're not in calibration mode & we want xyz translation */ - tcs3400_translate_to_xyz(s, crgb_data, xyz_data); - } else { - /* normalize the data for atime and again changes */ - for (i = 0; i < CRGB_COUNT; i++) - crgb_data[i] = normalize_channel_data(s, crgb_data[i]); - - /* calibration mode returns raw data */ - for (i = 0; i < 3; i++) - xyz_data[i] = crgb_data[i+1]; - } -} - -static int32_t get_lux_from_xyz(struct motion_sensor_t *s, int32_t *xyz_data) -{ - int32_t lux = xyz_data[Y]; - const int32_t offset = - TCS3400_RGB_DRV_DATA(s+1)->calibration.rgb_cal[Y].offset; - - /* - * Do not include the offset when determining LUX from XYZ. - */ - lux = MAX(0, lux - offset); - - return lux; -} - -static bool is_spoof(struct motion_sensor_t *s) -{ - return IS_ENABLED(CONFIG_ACCEL_SPOOF_MODE) && - (s->flags & MOTIONSENSE_FLAG_IN_SPOOF_MODE); -} - -static int tcs3400_post_events(struct motion_sensor_t *s, - uint32_t last_ts, - uint32_t status) -{ - /* - * Rule says RGB sensor is right after ALS sensor. - * This routine will only get called from ALS sensor driver. - */ - struct motion_sensor_t *rgb_s = s + 1; - const uint8_t is_calibration = - TCS3400_RGB_DRV_DATA(rgb_s)->calibration_mode; - struct ec_response_motion_sensor_data vector = { .flags = 0, }; - uint8_t buf[TCS_RGBC_DATA_SIZE]; /* holds raw data read from chip */ - int32_t xyz_data[3] = { 0, 0, 0 }; - uint16_t raw_data[CRGB_COUNT]; /* holds raw CRGB assembled from buf[] */ - int *last_v; - int32_t lux = 0; - int ret; - - if (IS_ENABLED(CONFIG_ALS_TCS3400_EMULATED_IRQ_EVENT)) { - int i = 5; /* 100ms max */ - - while (i--) { - /* Make sure data is valid */ - if (status & TCS_I2C_STATUS_RGBC_VALID) - break; - msleep(20); - /* - * When not in interrupt mode, we could have scheduled - * the handler too early. - */ - ret = tcs3400_i2c_read8(s, TCS_I2C_STATUS, &status); - if (ret) - return ret; - } - if (i < 0) { - CPRINTS("RGBC invalid (0x%x)", status); - return EC_ERROR_UNCHANGED; - } - } - - /* Read the light registers */ - ret = i2c_read_block(s->port, s->i2c_spi_addr_flags, - TCS_DATA_START_LOCATION, - buf, sizeof(buf)); - if (ret) - return ret; - - /* Process the raw light data, adjusting for scale and calibration */ - tcs3400_process_raw_data(s, buf, raw_data, xyz_data); - - /* get lux value */ - lux = is_calibration ? xyz_data[Y] : get_lux_from_xyz(s, xyz_data); - - /* if clear channel data changed, send illuminance upstream */ - last_v = s->raw_xyz; - if (is_calibration || - ((raw_data[CLEAR_CRGB_IDX] != TCS_SATURATION_LEVEL) && - (last_v[X] != lux))) { - if (is_spoof(s)) - last_v[X] = s->spoof_xyz[X]; - else - last_v[X] = is_calibration ? raw_data[CLEAR_CRGB_IDX] : lux; - - vector.udata[X] = ec_motion_sensor_clamp_u16(last_v[X]); - vector.udata[Y] = 0; - vector.udata[Z] = 0; - - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) { - vector.sensor_num = s - motion_sensors; - motion_sense_fifo_stage_data(&vector, s, 3, last_ts); - } - } - - /* - * If rgb channel data changed since last sample and didn't saturate, - * send it upstream - */ - last_v = rgb_s->raw_xyz; - if (is_calibration || - (((last_v[X] != xyz_data[X]) || (last_v[Y] != xyz_data[Y]) || - (last_v[Z] != xyz_data[Z])) && - ((raw_data[RED_CRGB_IDX] != TCS_SATURATION_LEVEL) && - (raw_data[BLUE_CRGB_IDX] != TCS_SATURATION_LEVEL) && - (raw_data[GREEN_CRGB_IDX] != TCS_SATURATION_LEVEL)))) { - - if (is_spoof(rgb_s)) { - memcpy(last_v, rgb_s->spoof_xyz, sizeof(rgb_s->spoof_xyz)); - } else if (is_calibration) { - last_v[0] = raw_data[RED_CRGB_IDX]; - last_v[1] = raw_data[GREEN_CRGB_IDX]; - last_v[2] = raw_data[BLUE_CRGB_IDX]; - } else { - memcpy(last_v, xyz_data, sizeof(xyz_data)); - } - - ec_motion_sensor_clamp_u16s(vector.udata, last_v); - - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) { - vector.sensor_num = rgb_s - motion_sensors; - motion_sense_fifo_stage_data(&vector, rgb_s, 3, last_ts); - } - } - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) - motion_sense_fifo_commit_data(); - - if (!is_calibration) - ret = tcs3400_adjust_sensor_for_saturation(s, xyz_data[Y], - raw_data, status); - - return ret; -} - -void tcs3400_interrupt(enum gpio_signal signal) -{ - if (IS_ENABLED(CONFIG_ACCEL_FIFO)) - last_interrupt_timestamp = __hw_clock_source_read(); - - task_set_event(TASK_ID_MOTIONSENSE, CONFIG_ALS_TCS3400_INT_EVENT); -} - -/* - * tcs3400_irq_handler - bottom half of the interrupt stack. - * Ran from the motion_sense task, finds the events that raised the interrupt, - * and posts those events via motion_sense_fifo_stage_data().. - * - * This routine will get called for the TCS3400 ALS driver, but NOT for the - * RGB driver. We harvest data for both drivers in this routine. The RGB - * driver is guaranteed to directly follow the ALS driver in the sensor list - * (i.e rgb's motion_sensor_t structure can be found at (s+1) ). - */ -static int tcs3400_irq_handler(struct motion_sensor_t *s, uint32_t *event) -{ - uint32_t status = 0; - int ret; - - if (!(*event & CONFIG_ALS_TCS3400_INT_EVENT)) - return EC_ERROR_NOT_HANDLED; - - ret = tcs3400_i2c_read8(s, TCS_I2C_STATUS, &status); - if (ret) - return ret; - - /* Disable future interrupts */ - ret = tcs3400_i2c_write8(s, TCS_I2C_ENABLE, TCS3400_MODE_IDLE); - if (ret) - return ret; - - if ((status & TCS_I2C_STATUS_RGBC_VALID) || - IS_ENABLED(CONFIG_ALS_TCS3400_EMULATED_IRQ_EVENT)) { - ret = tcs3400_post_events(s, last_interrupt_timestamp, status); - if (ret) - return ret; - } - - tcs3400_i2c_write8(s, TCS_I2C_AICLEAR, 0); - - /* Disable ADC and turn off internal oscillator */ - ret = tcs3400_i2c_write8(s, TCS_I2C_ENABLE, TCS3400_MODE_SUSPEND); - if (ret) - return ret; - - return EC_SUCCESS; -} - -static int tcs3400_rgb_get_scale(const struct motion_sensor_t *s, - uint16_t *scale, - int16_t *temp) -{ - struct rgb_channel_calibration_t *rgb_cal = - TCS3400_RGB_DRV_DATA(s)->calibration.rgb_cal; - - scale[X] = rgb_cal[RED_RGB_IDX].scale.k_channel_scale; - scale[Y] = rgb_cal[GREEN_RGB_IDX].scale.k_channel_scale; - scale[Z] = rgb_cal[BLUE_RGB_IDX].scale.k_channel_scale; - *temp = EC_MOTION_SENSE_INVALID_CALIB_TEMP; - return EC_SUCCESS; -} - -static int tcs3400_rgb_set_scale(const struct motion_sensor_t *s, - const uint16_t *scale, - int16_t temp) -{ - struct rgb_channel_calibration_t *rgb_cal = - TCS3400_RGB_DRV_DATA(s)->calibration.rgb_cal; - - if (scale[X] == 0 || scale[Y] == 0 || scale[Z] == 0) - return EC_ERROR_INVAL; - rgb_cal[RED_RGB_IDX].scale.k_channel_scale = scale[X]; - rgb_cal[GREEN_RGB_IDX].scale.k_channel_scale = scale[Y]; - rgb_cal[BLUE_RGB_IDX].scale.k_channel_scale = scale[Z]; - return EC_SUCCESS; -} - -static int tcs3400_rgb_get_offset(const struct motion_sensor_t *s, - int16_t *offset, - int16_t *temp) -{ - offset[X] = TCS3400_RGB_DRV_DATA(s)->calibration.rgb_cal[X].offset; - offset[Y] = TCS3400_RGB_DRV_DATA(s)->calibration.rgb_cal[Y].offset; - offset[Z] = TCS3400_RGB_DRV_DATA(s)->calibration.rgb_cal[Z].offset; - *temp = EC_MOTION_SENSE_INVALID_CALIB_TEMP; - return EC_SUCCESS; -} - -static int tcs3400_rgb_set_offset(const struct motion_sensor_t *s, - const int16_t *offset, - int16_t temp) -{ - /* do not allow offset to be changed, it's predetermined */ - return EC_SUCCESS; -} - -static int tcs3400_rgb_set_data_rate(const struct motion_sensor_t *s, - int rate, - int rnd) -{ - return EC_SUCCESS; -} - -/* Enable/disable special factory calibration mode */ -static int tcs3400_perform_calib(struct motion_sensor_t *s, int enable) -{ - TCS3400_RGB_DRV_DATA(s+1)->calibration_mode = enable; - return EC_SUCCESS; -} - -static int tcs3400_rgb_set_range(struct motion_sensor_t *s, - int range, - int rnd) -{ - return EC_SUCCESS; -} - -static int tcs3400_set_range(struct motion_sensor_t *s, - int range, - int rnd) -{ - TCS3400_DRV_DATA(s)->als_cal.scale = range >> 16; - TCS3400_DRV_DATA(s)->als_cal.uscale = range & 0xffff; - s->current_range = range; - return EC_SUCCESS; -} - -static int tcs3400_get_scale(const struct motion_sensor_t *s, - uint16_t *scale, - int16_t *temp) -{ - scale[X] = TCS3400_DRV_DATA(s)->als_cal.channel_scale.k_channel_scale; - scale[Y] = 0; - scale[Z] = 0; - *temp = EC_MOTION_SENSE_INVALID_CALIB_TEMP; - return EC_SUCCESS; -} - -static int tcs3400_set_scale(const struct motion_sensor_t *s, - const uint16_t *scale, - int16_t temp) -{ - if (scale[X] == 0) - return EC_ERROR_INVAL; - TCS3400_DRV_DATA(s)->als_cal.channel_scale.k_channel_scale = scale[X]; - return EC_SUCCESS; -} - -static int tcs3400_get_offset(const struct motion_sensor_t *s, - int16_t *offset, - int16_t *temp) -{ - offset[X] = TCS3400_DRV_DATA(s)->als_cal.offset; - offset[Y] = 0; - offset[Z] = 0; - *temp = EC_MOTION_SENSE_INVALID_CALIB_TEMP; - return EC_SUCCESS; -} - -static int tcs3400_set_offset(const struct motion_sensor_t *s, - const int16_t *offset, - int16_t temp) -{ - /* do not allow offset to be changed, it's predetermined */ - return EC_SUCCESS; -} - -static int tcs3400_get_data_rate(const struct motion_sensor_t *s) -{ - return TCS3400_DRV_DATA(s)->rate; -} - -static int tcs3400_rgb_get_data_rate(const struct motion_sensor_t *s) -{ - return tcs3400_get_data_rate(s - 1); -} - -static int tcs3400_set_data_rate(const struct motion_sensor_t *s, - int rate, - int rnd) -{ - enum tcs3400_mode mode; - int data; - int ret; - - if (rate == 0) { - /* Suspend driver */ - mode = TCS3400_MODE_SUSPEND; - } else { - /* - * We set the sensor for continuous mode, - * integrating over 800ms. - * Do not allow range higher than 1Hz. - */ - if (rate > TCS3400_LIGHT_MAX_FREQ) - rate = TCS3400_LIGHT_MAX_FREQ; - mode = TCS3400_MODE_COLLECTING; - } - TCS3400_DRV_DATA(s)->rate = rate; - - ret = tcs3400_i2c_read8(s, TCS_I2C_ENABLE, &data); - if (ret) - return ret; - - data = (data & TCS_I2C_ENABLE_MASK) | mode; - ret = tcs3400_i2c_write8(s, TCS_I2C_ENABLE, data); - - return ret; -} - -/** - * Initialise TCS3400 light sensor. - */ -static int tcs3400_rgb_init(struct motion_sensor_t *s) -{ - return EC_SUCCESS; -} - -static int tcs3400_init(struct motion_sensor_t *s) -{ - /* - * These are default power-on register values with two exceptions: - * Set ATIME = 0 (712 ms) - * Set AGAIN = 16 (0x10) (AGAIN is in CONTROL register) - */ - const struct reg_data { - uint8_t reg; - uint8_t data; - } defaults[] = { - { TCS_I2C_ENABLE, 0 }, - { TCS_I2C_ATIME, TCS_DEFAULT_ATIME }, - { TCS_I2C_WTIME, 0xFF }, - { TCS_I2C_AILTL, 0 }, - { TCS_I2C_AILTH, 0 }, - { TCS_I2C_AIHTL, 0 }, - { TCS_I2C_AIHTH, 0 }, - { TCS_I2C_PERS, 0 }, - { TCS_I2C_CONFIG, 0x40 }, - { TCS_I2C_CONTROL, (TCS_DEFAULT_AGAIN & TCS_I2C_CONTROL_MASK) }, - { TCS_I2C_AUX, 0 }, - { TCS_I2C_IR, 0 }, - { TCS_I2C_CICLEAR, 0 }, - { TCS_I2C_AICLEAR, 0 } - }; - int data = 0; - int ret; - - ret = tcs3400_i2c_read8(s, TCS_I2C_ID, &data); - if (ret) { - CPRINTS("failed reading ID reg 0x%x, ret=%d", TCS_I2C_ID, ret); - return ret; - } - if ((data != TCS340015_DEVICE_ID) && (data != TCS340037_DEVICE_ID)) { - CPRINTS("no ID match, data = 0x%x", data); - return EC_ERROR_ACCESS_DENIED; - } - - /* reset chip to default power-on settings, changes ATIME and CONTROL */ - for (int x = 0; x < ARRAY_SIZE(defaults); x++) { - ret = tcs3400_i2c_write8(s, defaults[x].reg, defaults[x].data); - if (ret) - return ret; - } - - return sensor_init_done(s); -} - -const struct accelgyro_drv tcs3400_drv = { - .init = tcs3400_init, - .read = tcs3400_read, - .set_range = tcs3400_set_range, - .set_offset = tcs3400_set_offset, - .get_offset = tcs3400_get_offset, - .set_scale = tcs3400_set_scale, - .get_scale = tcs3400_get_scale, - .set_data_rate = tcs3400_set_data_rate, - .get_data_rate = tcs3400_get_data_rate, - .perform_calib = tcs3400_perform_calib, -#ifdef CONFIG_ACCEL_INTERRUPTS - .irq_handler = tcs3400_irq_handler, -#endif -}; - -const struct accelgyro_drv tcs3400_rgb_drv = { - .init = tcs3400_rgb_init, - .read = tcs3400_rgb_read, - .set_range = tcs3400_rgb_set_range, - .set_offset = tcs3400_rgb_set_offset, - .get_offset = tcs3400_rgb_get_offset, - .set_scale = tcs3400_rgb_set_scale, - .get_scale = tcs3400_rgb_get_scale, - .set_data_rate = tcs3400_rgb_set_data_rate, - .get_data_rate = tcs3400_rgb_get_data_rate, -}; diff --git a/driver/amd_stt.c b/driver/amd_stt.c deleted file mode 100644 index 90fd82523b..0000000000 --- a/driver/amd_stt.c +++ /dev/null @@ -1,143 +0,0 @@ -/* Copyright 2021 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 "amd_stt.h" -#include "common.h" -#include "chipset.h" -#include "console.h" -#include "driver/sb_rmi.h" -#include "hooks.h" -#include "math_util.h" -#include "temp_sensor.h" -#include "util.h" - -/* Debug flag can be toggled with console command: stt debug */ -static bool amd_stt_debug; - -/* Console output macros */ -#define CPUTS(outstr) cputs(CC_THERMAL, outstr) -#define CPRINTS(format, args...) cprints(CC_THERMAL, format, ## args) - -static const char * const amd_stt_sensor_name[] = { - [AMD_STT_PCB_SENSOR_APU] = "APU", - [AMD_STT_PCB_SENSOR_REMOTE] = "Ambient", - [AMD_STT_PCB_SENSOR_GPU] = "GPU", -}; - -/** - * Write temperature sensor value to AP via SB-RMI - * - * sensor: - * AMD_STT_PCB_SENSOR_APU - * AMD_STT_PCB_SENSOR_REMOTE - * AMD_STT_PCB_SENSOR_GPU - * - * temp_mk: - * Temperature in degrees milli kelvin - */ -static int write_stt_sensor_val(enum amd_stt_pcb_sensor sensor, int temp_mk) -{ - uint32_t msgIn = 0; - uint32_t msgOut; - int temp_mc; - int temp_c_fp_msb; - int temp_c_fp_lsb; - - temp_mc = MILLI_KELVIN_TO_MILLI_CELSIUS(temp_mk); - - if (amd_stt_debug) - CPRINTS("STT: %s = %d.%d °C", amd_stt_sensor_name[sensor], - temp_mc / 1000, temp_mc % 1000); - - /* Divide by 1000 to get MSB of fixed point temp */ - temp_c_fp_msb = temp_mc / 1000; - /* Modulus 1000 and multiply by 256/1000 to get LSB of fixed point*/ - temp_c_fp_lsb = ((temp_mc % 1000) << 8) / 1000; - - /* - * [15:0]: temperature as signed integer with 8 fractional bits. - * [23:16]: sensor index - * [31:24]: unused - */ - msgIn |= (temp_c_fp_lsb & 0xff); - msgIn |= (temp_c_fp_msb & 0xff) << 8; - msgIn |= (sensor & 0xff) << 16; - return sb_rmi_mailbox_xfer(SB_RMI_WRITE_STT_SENSOR_CMD, msgIn, &msgOut); -} - -static void amd_stt_handler(void) -{ - int rv; - int soc_temp_mk; - int ambient_temp_mk; - - /* STT interface is only active in S0 */ - if (!chipset_in_state(CHIPSET_STATE_ON)) - return; - - /* - * TODO(b/192391025): Replace with temp_sensor_read_mk(TEMP_SENSOR_SOC) - */ - rv = board_get_soc_temp_mk(&soc_temp_mk); - if (rv) { - CPRINTS("STT: Failed to read SOC temp rv:%d", rv); - return; - } - - rv = write_stt_sensor_val(AMD_STT_PCB_SENSOR_APU, soc_temp_mk); - if (rv) { - CPRINTS("STT: Failed to write SOC temp rv:%d", rv); - return; - } - - /* - * TODO(b/192391025): Replace with - * temp_sensor_read_mk(TEMP_SENSOR_AMBIENT) - */ - rv = board_get_ambient_temp_mk(&ambient_temp_mk); - if (rv) { - CPRINTS("STT: Failed to read AMBIENT temp rv:%d", rv); - return; - } - - rv = write_stt_sensor_val(AMD_STT_PCB_SENSOR_REMOTE, ambient_temp_mk); - if (rv) { - CPRINTS("STT: Failed to write AMBIENT temp rv:%d", rv); - return; - } -} -DECLARE_HOOK(HOOK_SECOND, amd_stt_handler, HOOK_PRIO_TEMP_SENSOR+1); - -static int command_stt(int argc, char **argv) -{ - int sensor_id; - int temp; - - if (argc < 2) - return EC_ERROR_PARAM1; - else if (!strcasecmp(argv[1], "debug")) { - amd_stt_debug = !amd_stt_debug; - return EC_SUCCESS; - } else if (argc != 3) - return EC_ERROR_PARAM2; - else if (!strcasecmp(argv[1], - amd_stt_sensor_name[AMD_STT_PCB_SENSOR_APU])) - sensor_id = AMD_STT_PCB_SENSOR_APU; - else if (!strcasecmp(argv[1], - amd_stt_sensor_name[AMD_STT_PCB_SENSOR_REMOTE])) - sensor_id = AMD_STT_PCB_SENSOR_REMOTE; - else if (!strcasecmp(argv[1], - amd_stt_sensor_name[AMD_STT_PCB_SENSOR_GPU])) - sensor_id = AMD_STT_PCB_SENSOR_GPU; - else - return EC_ERROR_PARAM2; - - temp = atoi(argv[2]); - - return write_stt_sensor_val(sensor_id, temp); -} -DECLARE_CONSOLE_COMMAND(stt, command_stt, - "<apu|ambient|gpu|debug> <temp in mK>", - "Write an STT mK temperature to AP"); diff --git a/driver/baro_bmp280.c b/driver/baro_bmp280.c deleted file mode 100644 index 037a77d963..0000000000 --- a/driver/baro_bmp280.c +++ /dev/null @@ -1,383 +0,0 @@ -/* Copyright 2016 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. - */ -/* -**************************************************************************** -* Copyright (C) 2012 - 2015 Bosch Sensortec GmbH -* -* File : bmp280.h -* -* Date : 2015/03/27 -* -* Revision : 2.0.4(Pressure and Temperature compensation code revision is 1.1) -* -* Usage: Sensor Driver for BMP280 sensor -* -**************************************************************************** -* -* \section License -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* -* Neither the name of the copyright holder nor the names of the -* contributors may be used to endorse or promote products derived from -* this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR -* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER -* OR CONTRIBUTORS BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, -* OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, -* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -* ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE -* -* The information provided is believed to be accurate and reliable. -* The copyright holder assumes no responsibility -* for the consequences of use -* of such information nor for any infringement of patents or -* other rights of third parties which may result from its use. -* No license is granted by implication or otherwise under any patent or -* patent rights of the copyright holder. -**************************************************************************/ -#include "accelgyro.h" -#include "common.h" -#include "console.h" -#include "driver/baro_bmp280.h" -#include "i2c.h" -#include "timer.h" - -#define CPRINTF(format, args...) cprintf(CC_ACCEL, format, ## args) -#define CPRINTS(format, args...) cprints(CC_ACCEL, format, ## args) - -static const uint16_t standby_durn[] = {1, 63, 125, 250, 500, 1000, 2000, 4000}; - -/* - * This function is used to get calibration parameters used for - * calculation in the registers - * - * parameter | Register address | bit - *------------|------------------|---------------- - * dig_T1 | 0x88 and 0x89 | from 0 : 7 to 8: 15 - * dig_T2 | 0x8A and 0x8B | from 0 : 7 to 8: 15 - * dig_T3 | 0x8C and 0x8D | from 0 : 7 to 8: 15 - * dig_P1 | 0x8E and 0x8F | from 0 : 7 to 8: 15 - * dig_P2 | 0x90 and 0x91 | from 0 : 7 to 8: 15 - * dig_P3 | 0x92 and 0x93 | from 0 : 7 to 8: 15 - * dig_P4 | 0x94 and 0x95 | from 0 : 7 to 8: 15 - * dig_P5 | 0x96 and 0x97 | from 0 : 7 to 8: 15 - * dig_P6 | 0x98 and 0x99 | from 0 : 7 to 8: 15 - * dig_P7 | 0x9A and 0x9B | from 0 : 7 to 8: 15 - * dig_P8 | 0x9C and 0x9D | from 0 : 7 to 8: 15 - * dig_P9 | 0x9E and 0x9F | from 0 : 7 to 8: 15 - * - * @return results of bus communication function - * @retval 0 -> Success - * - */ -static int bmp280_get_calib_param(const struct motion_sensor_t *s) -{ - int ret; - - uint8_t a_data_u8[BMP280_CALIB_DATA_SIZE] = {0}; - struct bmp280_drv_data_t *data = BMP280_GET_DATA(s); - - ret = i2c_read_block(s->port, s->i2c_spi_addr_flags, - BMP280_TEMPERATURE_CALIB_DIG_T1_LSB_REG, - a_data_u8, BMP280_CALIB_DATA_SIZE); - - if (ret) - return ret; - - /* read calibration values*/ - data->calib_param.dig_T1 = (a_data_u8[1] << 8) | a_data_u8[0]; - data->calib_param.dig_T2 = (a_data_u8[3] << 8 | a_data_u8[2]); - data->calib_param.dig_T3 = (a_data_u8[5] << 8) | a_data_u8[4]; - - data->calib_param.dig_P1 = (a_data_u8[7] << 8) | a_data_u8[6]; - data->calib_param.dig_P2 = (a_data_u8[9] << 8) | a_data_u8[8]; - data->calib_param.dig_P3 = (a_data_u8[11] << 8) | a_data_u8[10]; - data->calib_param.dig_P4 = (a_data_u8[13] << 8) | a_data_u8[12]; - data->calib_param.dig_P5 = (a_data_u8[15] << 8) | a_data_u8[14]; - data->calib_param.dig_P6 = (a_data_u8[17] << 8) | a_data_u8[16]; - data->calib_param.dig_P7 = (a_data_u8[19] << 8) | a_data_u8[18]; - data->calib_param.dig_P8 = (a_data_u8[21] << 8) | a_data_u8[20]; - data->calib_param.dig_P9 = (a_data_u8[23] << 8) | a_data_u8[22]; - - return EC_SUCCESS; -} - -static int bmp280_read_uncomp_pressure(const struct motion_sensor_t *s, - int *uncomp_pres) -{ - int ret; - uint8_t a_data_u8[BMP280_PRESSURE_DATA_SIZE] = {0}; - - ret = i2c_read_block(s->port, s->i2c_spi_addr_flags, - BMP280_PRESSURE_MSB_REG, - a_data_u8, BMP280_PRESSURE_DATA_SIZE); - - if (ret) - return ret; - - *uncomp_pres = (int32_t)((a_data_u8[0] << 12) | - (a_data_u8[1] << 4) | - (a_data_u8[2] >> 4)); - - return EC_SUCCESS; -} - -/* - * Reads actual pressure from uncompensated pressure - * and returns the value in Pascal(Pa) - * @note Output value of "96386" equals 96386 Pa = - * 963.86 hPa = 963.86 millibar - * - * Algorithm from BMP280 Datasheet Rev 1.15 Section 8.2 - * - */ -static int bmp280_compensate_pressure(const struct motion_sensor_t *s, - int uncomp_pressure) -{ - int var1, var2; - uint32_t p; - struct bmp280_drv_data_t *data = BMP280_GET_DATA(s); - - /* calculate x1 */ - var1 = (((int32_t)data->calib_param.t_fine) - >> 1) - 64000; - /* calculate x2 */ - var2 = (((var1 >> 2) * (var1 >> 2)) >> 11) - * ((int32_t)data->calib_param.dig_P6); - var2 = var2 + ((var1 * ((int32_t)data->calib_param.dig_P5)) << 1); - var2 = (var2 >> 2) + (((int32_t)data->calib_param.dig_P4) << 16); - /* calculate x1 */ - var1 = (((data->calib_param.dig_P3 * - (((var1 >> 2) * (var1 >> 2)) >> 13)) >> 3) + - ((((int32_t)data->calib_param.dig_P2) * var1) >> 1)) >> 18; - var1 = ((((32768 + var1)) * - ((int32_t)data->calib_param.dig_P1)) >> 15); - - /* Avoid exception caused by division by zero */ - if (!var1) - return 0; - - /* calculate pressure */ - p = (((uint32_t)((1048576) - uncomp_pressure) - - (var2 >> 12))) * 3125; - - /* check overflow */ - if (p < 0x80000000) - p = (p << 1) / ((uint32_t)var1); - else - p = (p / (uint32_t)var1) << 1; - - /* calculate x1 */ - var1 = (((int32_t)data->calib_param.dig_P9) * - ((int32_t)(((p >> 3) * (p >> 3)) >> 13))) >> 12; - /* calculate x2 */ - var2 = (((int32_t)(p >> 2)) * - ((int32_t)data->calib_param.dig_P8)) >> 13; - /* calculate true pressure */ - return (uint32_t)((int32_t)p + ((var1 + var2 + - data->calib_param.dig_P7) >> 4)); -} - -/* - * Set the standby duration - * standby_durn: The standby duration time value. - * value | standby duration - * ----------|-------------------- - * 0x00 | 1_MS - * 0x01 | 63_MS - * 0x02 | 125_MS - * 0x03 | 250_MS - * 0x04 | 500_MS - * 0x05 | 1000_MS - * 0x06 | 2000_MS - * 0x07 | 4000_MS - */ -static int bmp280_set_standby_durn(const struct motion_sensor_t *s, - uint8_t durn) -{ - int ret, val; - - ret = i2c_read8(s->port, s->i2c_spi_addr_flags, - BMP280_CONFIG_REG, &val); - - if (ret == EC_SUCCESS) { - val = (val & 0xE0) | ((durn << 5) & 0xE0); - /* write the standby duration*/ - ret = i2c_write8(s->port, s->i2c_spi_addr_flags, - BMP280_CONFIG_REG, val); - } - - return ret; -} - -static int bmp280_set_power_mode(const struct motion_sensor_t *s, - uint8_t power_mode) -{ - int val; - - val = (BMP280_OVERSAMP_TEMP << 5) + - (BMP280_OVERSAMP_PRES << 2) + power_mode; - - return i2c_write8(s->port, s->i2c_spi_addr_flags, - BMP280_CTRL_MEAS_REG, val); -} - -static int bmp280_set_range(struct motion_sensor_t *s, - int range, - int rnd) -{ - struct bmp280_drv_data_t *data = BMP280_GET_DATA(s); - /* - * ->range contains the number of bit to right shift in order for the - * measurment to fit into 16 bits (or less if the AP wants to). - */ - data->range = 15 - __builtin_clz(range); - s->current_range = 1 << (16 + data->range); - return EC_SUCCESS; -} - -/* - * bmp280_init() - Used to initialize barometer with default config - * - * @return results of bus communication function - * @retval 0 -> Success - */ - -static int bmp280_init(struct motion_sensor_t *s) -{ - int val, ret; - - if (!s) - return EC_ERROR_INVAL; - - /* Read chip id */ - ret = i2c_read8(s->port, s->i2c_spi_addr_flags, - BMP280_CHIP_ID_REG, &val); - if (ret) - return ret; - - if (val != BMP280_CHIP_ID) - return EC_ERROR_INVAL; - - /* set power mode */ - ret = bmp280_set_power_mode(s, BMP280_SLEEP_MODE); - if (ret) - return ret; - - /* Read bmp280 calibration parameter */ - ret = bmp280_get_calib_param(s); - if (ret) - return ret; - - return sensor_init_done(s); -} - -static int bmp280_read(const struct motion_sensor_t *s, intv3_t v) -{ - int ret, pres; - struct bmp280_drv_data_t *data = BMP280_GET_DATA(s); - - ret = bmp280_read_uncomp_pressure(s, &pres); - - if (ret) - return ret; - - v[0] = bmp280_compensate_pressure(s, pres) >> data->range; - v[1] = v[2] = 0; - - return EC_SUCCESS; -} - -/* - * Set data rate, rate in mHz. - * Calculate the delay (in ms) to apply. - */ -static int bmp280_set_data_rate(const struct motion_sensor_t *s, int rate, - int roundup) -{ - struct bmp280_drv_data_t *data = BMP280_GET_DATA(s); - int durn, i, ret; - int period; /* Period in ms */ - - if (rate == 0) { - /* Set to sleep mode */ - data->rate = 0; - return bmp280_set_power_mode(s, BMP280_SLEEP_MODE); - } else - period = 1000000 / rate; - - /* reset power mode, waking from sleep */ - if (!data->rate) { - ret = bmp280_set_power_mode(s, BMP280_NORMAL_MODE); - if (ret) - return ret; - } - - durn = 0; - for (i = BMP280_STANDBY_CNT-1; i > 0; i--) { - if (period >= standby_durn[i] + BMP280_COMPUTE_TIME) { - durn = i; - break; - } else if (period > standby_durn[i-1] + BMP280_COMPUTE_TIME) { - durn = roundup ? i-1 : i; - break; - } - } - ret = bmp280_set_standby_durn(s, durn); - if (ret == EC_SUCCESS) - /* - * The maximum frequency is around 76Hz. Be sure it fits in 16 - * bits by shifting by one bit. - */ - data->rate = (1000000 >> BMP280_RATE_SHIFT) / - (standby_durn[durn] + BMP280_COMPUTE_TIME); - return ret; -} - -static int bmp280_get_data_rate(const struct motion_sensor_t *s) -{ - struct bmp280_drv_data_t *data = BMP280_GET_DATA(s); - - return data->rate << BMP280_RATE_SHIFT; -} - -const struct accelgyro_drv bmp280_drv = { - .init = bmp280_init, - .read = bmp280_read, - .set_range = bmp280_set_range, - .set_data_rate = bmp280_set_data_rate, - .get_data_rate = bmp280_get_data_rate, -}; - -#ifdef CONFIG_CMD_I2C_STRESS_TEST_ACCEL -struct i2c_stress_test_dev bmp280_i2c_stress_test_dev = { - .reg_info = { - .read_reg = BMP280_CHIP_ID_REG, - .read_val = BMP280_CHIP_ID, - .write_reg = BMP280_CONFIG_REG, - }, - .i2c_read = &i2c_read8, - .i2c_write = &i2c_write8, -}; -#endif /* CONFIG_CMD_I2C_STRESS_TEST_ACCEL */ diff --git a/driver/baro_bmp280.h b/driver/baro_bmp280.h deleted file mode 100644 index ee95bd886f..0000000000 --- a/driver/baro_bmp280.h +++ /dev/null @@ -1,224 +0,0 @@ -/* Copyright 2016 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. - */ -/** \mainpage -* -**************************************************************************** -* Copyright (C) 2012 - 2015 Bosch Sensortec GmbH -* -* File : bmp280.h -* -* Date : 2015/03/27 -* -* Revision : 2.0.4(Pressure and Temperature compensation code revision is 1.1) -* -* Usage: Sensor Driver for BMP280 sensor -* -**************************************************************************** -* -* \section License -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* -* Neither the name of the copyright holder nor the names of the -* contributors may be used to endorse or promote products derived from -* this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR -* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER -* OR CONTRIBUTORS BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, -* OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, -* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -* ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE -* -* The information provided is believed to be accurate and reliable. -* The copyright holder assumes no responsibility -* for the consequences of use -* of such information nor for any infringement of patents or -* other rights of third parties which may result from its use. -* No license is granted by implication or otherwise under any patent or -* patent rights of the copyright holder. -**************************************************************************/ -/* BMP280 pressure and temperature module for Chrome EC */ - -#ifndef __CROS_EC_BARO_BMP280_H -#define __CROS_EC_BARO_BMP280_H - -/* - * The addr field of barometer_sensor for I2C: - * - * +-------------------------------+---+ - * | 7 bit i2c address | 0 | - * +-------------------------------+---+ - */ - -/* - * Bit 1 of 7-bit address: 0 - If SDO is connected to GND - * Bit 1 of 7-bit address: 1 - If SDO is connected to Vddio - */ -#define BMP280_I2C_ADDRESS1_FLAGS 0x76 -#define BMP280_I2C_ADDRESS2_FLAGS 0x77 - -/* - * CHIP ID - */ -#define BMP280_CHIP_ID 0x58 -/************************************************/ -/* CALIBRATION PARAMETERS DEFINITION */ -/************************************************/ - -#define BMP280_TEMPERATURE_CALIB_DIG_T1_LSB_REG 0x88 - -/************************************************/ -/* REGISTER ADDRESS DEFINITION */ -/************************************************/ -#define BMP280_CHIP_ID_REG 0xD0 -#define BMP280_RST_REG 0xE0 /*Softreset Register */ -#define BMP280_STAT_REG 0xF3 /*Status Register */ -#define BMP280_CTRL_MEAS_REG 0xF4 /*Ctrl Measure Register */ -#define BMP280_CONFIG_REG 0xF5 /*Configuration Register */ -#define BMP280_PRESSURE_MSB_REG 0xF7 /*Pressure MSB Register */ -#define BMP280_PRESSURE_LSB_REG 0xF8 /*Pressure LSB Register */ -#define BMP280_PRESSURE_XLSB_REG 0xF9 /*Pressure XLSB Register */ -/************************************************/ -/* POWER MODE DEFINITION */ -/************************************************/ -/* Sensor Specific constants */ -#define BMP280_SLEEP_MODE 0x00 -#define BMP280_FORCED_MODE 0x01 -#define BMP280_NORMAL_MODE 0x03 -#define BMP280_SOFT_RESET_CODE 0xB6 -/************************************************/ -/* STANDBY TIME DEFINITION */ -/************************************************/ -#define BMP280_STANDBY_TIME_1_MS 0x00 -#define BMP280_STANDBY_TIME_63_MS 0x01 -#define BMP280_STANDBY_TIME_125_MS 0x02 -#define BMP280_STANDBY_TIME_250_MS 0x03 -#define BMP280_STANDBY_TIME_500_MS 0x04 -#define BMP280_STANDBY_TIME_1000_MS 0x05 -#define BMP280_STANDBY_TIME_2000_MS 0x06 -#define BMP280_STANDBY_TIME_4000_MS 0x07 -/************************************************/ -/* OVERSAMPLING DEFINITION */ -/************************************************/ -#define BMP280_OVERSAMP_SKIPPED 0x00 -#define BMP280_OVERSAMP_1X 0x01 -#define BMP280_OVERSAMP_2X 0x02 -#define BMP280_OVERSAMP_4X 0x03 -#define BMP280_OVERSAMP_8X 0x04 -#define BMP280_OVERSAMP_16X 0x05 -/************************************************/ -/* DEFINITIONS FOR ARRAY SIZE OF DATA */ -/************************************************/ -#define BMP280_PRESSURE_DATA_SIZE 3 -#define BMP280_DATA_FRAME_SIZE 6 -#define BMP280_CALIB_DATA_SIZE 24 -/*******************************************************/ -/* SAMPLING PERIOD COMPUTATION CONSTANT */ -/*******************************************************/ -#define BMP280_STANDBY_CNT 8 -#define T_INIT_MAX (20) /* (20/16 = 1.25ms) */ -#define T_MEASURE_PER_OSRS_MAX (37) /* (37/16 = 2.31ms) */ -#define T_SETUP_PRESSURE_MAX (10) /* (10/16 = 0.62ms) */ - -/* - * This is the measurement time required for pressure and temp - */ -#define BMP280_COMPUTE_TIME \ - ((T_INIT_MAX + T_MEASURE_PER_OSRS_MAX * \ - ((BIT(BMP280_OVERSAMP_TEMP) >> 1) + \ - (BIT(BMP280_OVERSAMP_PRES) >> 1)) + \ - (BMP280_OVERSAMP_PRES ? T_SETUP_PRESSURE_MAX : 0) + 15) / 16) - -/* - * These values are selected as per Bosch recommendation for - * standard handheld devices, with temp sensor not being used - */ -#define BMP280_OVERSAMP_PRES BMP280_OVERSAMP_4X -#define BMP280_OVERSAMP_TEMP BMP280_OVERSAMP_SKIPPED -/*******************************************************/ -/* GET DRIVER DATA */ -/*******************************************************/ -#define BMP280_GET_DATA(_s) \ - ((struct bmp280_drv_data_t *)(_s)->drv_data) - -/* Min and Max sampling frequency in mHz based on x4 oversampling used */ -/* FIXME - verify how chip is setup to make sure MAX is correct, manual says - * "Typical", not Max. - */ -#define BMP280_BARO_MIN_FREQ 75000 -#define BMP280_BARO_MAX_FREQ 87000 -#if (CONFIG_EC_MAX_SENSOR_FREQ_MILLIHZ <= BMP280_BARO_MAX_FREQ) -#error "EC too slow for accelerometer" -#endif - -/**************************************************************/ -/* STRUCTURE and ENUM DEFINITIONS */ -/**************************************************************/ - -/* - * struct bmp280_calib_param_t - Holds all device specific - * calibration parameters - * - * @dig_T1 to dig_T3: calibration Temp data - * @dig_P1 to dig_P9: calibration Pressure data - * @t_fine: calibration t_fine data - * - */ -struct bmp280_calib_param_t { - uint16_t dig_T1; - int16_t dig_T2; - int16_t dig_T3; - uint16_t dig_P1; - int16_t dig_P2; - int16_t dig_P3; - int16_t dig_P4; - int16_t dig_P5; - int16_t dig_P6; - int16_t dig_P7; - int16_t dig_P8; - int16_t dig_P9; - - int32_t t_fine; -}; - -/* - * struct bmp280_t - This structure holds BMP280 initialization parameters - * @calib_param: calibration data - * @rate: frequency, in mHz. - * @range: bit offset to fit data in 16 bit or less. - */ -struct bmp280_drv_data_t { - - struct bmp280_calib_param_t calib_param; - uint16_t rate; - uint16_t range; -}; -#define BMP280_RATE_SHIFT 1 - -extern const struct accelgyro_drv bmp280_drv; - -#ifdef CONFIG_CMD_I2C_STRESS_TEST_ACCEL -extern struct i2c_stress_test_dev bmp280_i2c_stress_test_dev; -#endif - -#endif diff --git a/driver/battery/bq20z453.c b/driver/battery/bq20z453.c deleted file mode 100644 index 3cd16e8b8f..0000000000 --- a/driver/battery/bq20z453.c +++ /dev/null @@ -1,35 +0,0 @@ -/* Copyright 2012 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. - * - * Smart battery driver for BQ20Z453. - */ - -#include "battery_smart.h" -#include "hooks.h" -#include "host_command.h" - -#define PARAM_CUT_OFF 0x0010 - -static void cutoff(void) -{ - /* Claim i2c and send cutoff command to battery. */ - sb_write(SB_MANUFACTURER_ACCESS, PARAM_CUT_OFF); -} -DECLARE_DEFERRED(cutoff); - -enum ec_status battery_command_cut_off(struct host_cmd_handler_args *args) -{ - /* - * Queue battery cutoff. This must be deferred so we can send the - * response to the host first. Some platforms (snow) share an I2C bus - * between the EC, AP, and battery, so we need the host to complete the - * transaction and release the I2C bus before we'll be abl eto send the - * cutoff command. - */ - hook_call_deferred(&cutoff_data, 1000); - - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_BATTERY_CUT_OFF, battery_command_cut_off, - EC_VER_MASK(0)); diff --git a/driver/battery/bq27541.c b/driver/battery/bq27541.c deleted file mode 100644 index b39147092f..0000000000 --- a/driver/battery/bq27541.c +++ /dev/null @@ -1,432 +0,0 @@ -/* Copyright 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. - * - * Battery driver for BQ27541/BQ27542/BQ27741/BQ27742. - */ - -#include "battery.h" -#include "battery_smart.h" -#include "console.h" -#include "extpower.h" -#include "hooks.h" -#include "i2c.h" -#include "util.h" - -#define BQ27541_ADDR_FLAGS 0x55 -#define BQ27541_TYPE_ID 0x0541 -#define BQ27542_TYPE_ID 0x0542 -#define BQ27741_TYPE_ID 0x0741 -#define BQ27742_TYPE_ID 0x0742 - -#define REG_CTRL 0x00 -#define REG_AT_RATE 0x02 -#define REG_AT_RATE_TIME_TO_EMPTY 0x04 -#define REG_TEMPERATURE 0x06 -#define REG_VOLTAGE 0x08 -#define REG_FLAGS 0x0a -#define REG_NOMINAL_CAPACITY 0x0c -#define REG_FULL_AVAILABLE_CAPACITY 0x0e -#define REG_REMAINING_CAPACITY 0x10 -#define REG_FULL_CHARGE_CAPACITY 0x12 -#define REG_AVERAGE_CURRENT 0x14 -#define REG_TIME_TO_EMPTY 0x16 -#define REG_TIME_TO_FULL 0x18 -#define REG_STANDBY_CURRENT 0x1a -#define REG_STANDBY_TIME_TO_EMPTY 0x1c -#define REG_MAX_LOAD_CURRENT 0x1e -#define REG_MAX_LOAD_TIME_TO_EMPTY 0x20 -#define REG_AVAILABLE_ENERGY 0x22 -#define REG_AVERAGE_POEWR 0x24 -#define REG_TT_EAT_CONSTANT_POWER 0x26 -#define REG_CYCLE_COUNT 0x2a -#define REG_STATE_OF_CHARGE 0x2c -#define REG_DATA_FLASH_BLOCK 0x3f -#define REG_DESIGN_CAPACITY 0x3c -#define REG_MANUFACTURER_INFO 0x52 -#define REG_DEVICE_NAME_LENGTH 0x62 -#define MAX_DEVICE_NAME_LENGTH 7 -#define REG_DEVICE_NAME 0x63 -#define REG_PROTECTOR 0x6d - -/* Over-charge */ -#define BQ27542_FLAG_BATHI BIT(13) -/* Over Temperature in discharge */ -#define BQ27542_FLAG_OTD BIT(11) -/* Over Temperature in charge */ -#define BQ27542_FLAG_OTC BIT(7) -/* Charge allowed */ -#define BQ27542_FLAG_CHG BIT(3) -/* Discharge */ -#define BQ27542_FLAG_DSG BIT(0) - -static int battery_type_id; -static int fake_state_of_charge = -1; - -static int bq27541_read(int offset, int *data) -{ - return i2c_read16(I2C_PORT_BATTERY, BQ27541_ADDR, offset, data); -} - -static int bq27541_read8(int offset, int *data) -{ - return i2c_read8(I2C_PORT_BATTERY, BQ27541_ADDR, offset, data); -} - -static int bq27541_write(int offset, int data) -{ - return i2c_write16(I2C_PORT_BATTERY, BQ27541_ADDR, offset, data); -} - -int bq27541_probe(void) -{ - int rv; - - rv = bq27541_write(REG_CTRL, 0x1); - rv |= bq27541_read(REG_CTRL, &battery_type_id); - /* Read twice to get the right value */ - rv |= bq27541_read(REG_CTRL, &battery_type_id); - if (rv) - return rv; - if (battery_type_id == BQ27541_TYPE_ID || - battery_type_id == BQ27542_TYPE_ID || - battery_type_id == BQ27741_TYPE_ID || - battery_type_id == BQ27742_TYPE_ID) - return EC_SUCCESS; - return EC_ERROR_UNKNOWN; -} - -static void probe_type_id(void) -{ - bq27541_probe(); -} -DECLARE_HOOK(HOOK_INIT, probe_type_id, HOOK_PRIO_DEFAULT); - -int battery_device_name(char *device_name, int buf_size) -{ - int rv, i, val; - int len = MIN(7, buf_size - 1); - - if (battery_type_id == BQ27742_TYPE_ID) { - /* No device name register available */ - strzcpy(device_name, "<BATT>", len); - return 0; - } - /* Battery pack vendor specific */ - if (battery_type_id == BQ27542_TYPE_ID) { - rv = bq27541_write(REG_DATA_FLASH_BLOCK, 0x1); - for (i = 0; i < len; ++i) { - rv |= bq27541_read8(REG_MANUFACTURER_INFO + i, &val); - device_name[i] = val; - } - device_name[i] = '\0'; - return rv; - } - - rv = bq27541_read8(REG_DEVICE_NAME_LENGTH, &val); - if (rv) - return rv; - len = MIN(len, val); - - for (i = 0; i < len; ++i) { - rv |= bq27541_read8(REG_DEVICE_NAME + i, &val); - device_name[i] = val; - } - device_name[i] = '\0'; - - return rv; -} - -int battery_state_of_charge_abs(int *percent) -{ - return bq27541_read(REG_STATE_OF_CHARGE, percent); -} - -int battery_remaining_capacity(int *capacity) -{ - return bq27541_read(REG_REMAINING_CAPACITY, capacity); -} - -int battery_full_charge_capacity(int *capacity) -{ - return bq27541_read(REG_FULL_CHARGE_CAPACITY, capacity); -} - -int battery_time_to_empty(int *minutes) -{ - return bq27541_read(REG_TIME_TO_EMPTY, minutes); -} - -int battery_time_to_full(int *minutes) -{ - return bq27541_read(REG_TIME_TO_FULL, minutes); -} - -int battery_cycle_count(int *count) -{ - return bq27541_read(REG_CYCLE_COUNT, count); -} - -int battery_design_capacity(int *capacity) -{ - return bq27541_read(REG_DESIGN_CAPACITY, capacity); -} - -int battery_time_at_rate(int rate, int *minutes) -{ - int rv; - - if (battery_type_id == BQ27542_TYPE_ID) - return EC_ERROR_UNIMPLEMENTED; - - rv = bq27541_write(REG_AT_RATE, rate); - if (rv) - return rv; - return bq27541_read(REG_AT_RATE_TIME_TO_EMPTY, minutes); -} - -int battery_device_chemistry(char *dest, int size) -{ - strzcpy(dest, "<unkn>", size); - - return EC_SUCCESS; -} - -int battery_serial_number(int *serial) -{ - *serial = 0x0BAD0BAD; - - return EC_SUCCESS; -} - -int battery_manufacture_date(int *year, int *month, int *day) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -int battery_design_voltage(int *voltage) -{ - *voltage = battery_get_info()->voltage_normal; - - return EC_SUCCESS; -} - -/** - * Check if battery allows charging. - * - * @param allowed Non-zero if charging allowed; zero if not allowed. - * @return non-zero if error. - */ -static int battery_charging_allowed(int *allowed) -{ - int rv, val; - - rv = bq27541_read(REG_FLAGS, &val); - if (rv) - return rv; - if (battery_type_id == BQ27541_TYPE_ID || - battery_type_id == BQ27741_TYPE_ID) - *allowed = (val & 0x100); - else /* BQ27742_TYPE_ID, BQ27542_TYPE_ID */ - *allowed = (val & 0x8); - - return EC_SUCCESS; -} - -int battery_get_mode(int *mode) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -int battery_status(int *status) -{ - int rv; - int flag = 0; - - *status = 0; - if (battery_type_id == BQ27542_TYPE_ID) { - rv = bq27541_read(REG_FLAGS, &flag); - if (rv) - return rv; - - if (flag & (BQ27542_FLAG_OTC | BQ27542_FLAG_OTD)) - *status |= STATUS_OVERTEMP_ALARM; - if (flag & BQ27542_FLAG_DSG) - *status |= STATUS_DISCHARGING; - if (flag & BQ27542_FLAG_BATHI) - *status |= STATUS_OVERCHARGED_ALARM; - - return EC_SUCCESS; - } - - return EC_ERROR_UNIMPLEMENTED; -} - -enum battery_present battery_is_present(void) -{ - int v; - if (bq27541_read(REG_TEMPERATURE, &v)) - return BP_NO; - return BP_YES; -} - -void battery_get_params(struct batt_params *batt) -{ - int v; - const uint32_t flags_to_check = BATT_FLAG_BAD_TEMPERATURE | - BATT_FLAG_BAD_STATE_OF_CHARGE | - BATT_FLAG_BAD_VOLTAGE | - BATT_FLAG_BAD_CURRENT; - - /* Reset flags */ - batt->flags = 0; - - if (bq27541_read(REG_TEMPERATURE, &batt->temperature)) - batt->flags |= BATT_FLAG_BAD_TEMPERATURE; - - if (bq27541_read8(REG_STATE_OF_CHARGE, &v) && fake_state_of_charge < 0) - batt->flags |= BATT_FLAG_BAD_STATE_OF_CHARGE; - - batt->state_of_charge = fake_state_of_charge >= 0 ? - fake_state_of_charge : v; - - if (bq27541_read(REG_VOLTAGE, &batt->voltage)) - batt->flags |= BATT_FLAG_BAD_VOLTAGE; - - v = 0; - if (bq27541_read(REG_AVERAGE_CURRENT, &v)) - batt->flags |= BATT_FLAG_BAD_CURRENT; - batt->current = (int16_t)v; - - if (battery_remaining_capacity(&batt->remaining_capacity)) - batt->flags |= BATT_FLAG_BAD_REMAINING_CAPACITY; - - if (battery_full_charge_capacity(&batt->full_capacity)) - batt->flags |= BATT_FLAG_BAD_FULL_CAPACITY; - - /* Default to not desiring voltage and current */ - batt->desired_voltage = batt->desired_current = 0; - - /* If any of those reads worked, the battery is responsive */ - if ((batt->flags & flags_to_check) != flags_to_check) { - batt->flags |= BATT_FLAG_RESPONSIVE; - batt->is_present = BP_YES; - } else { - - /* If all of those reads error, the battery is not present */ - batt->is_present = BP_NO; - } - - /* update the battery status */ - if (battery_status(&batt->status)) - batt->flags |= BATT_FLAG_BAD_STATUS; - - v = 0; - if (battery_charging_allowed(&v)) { - batt->flags |= BATT_FLAG_BAD_ANY; - } else if (v) { - batt->flags |= BATT_FLAG_WANT_CHARGE; - - /* - * Desired voltage and current are not provided by the battery. - * So ask for battery's max voltage and an arbitrarily large - * current. - */ - batt->desired_voltage = battery_get_info()->voltage_max; - batt->desired_current = 4096; - } -} - -/* Wait until battery is totally stable */ -int battery_wait_for_stable(void) -{ - /* TODO(crosbug.com/p/30426): implement me */ - return EC_SUCCESS; -} - -#ifdef CONFIG_BATTERY_REVIVE_DISCONNECT -/* - * Check if battery is in disconnect state, a state entered by pulling - * BATT_DISCONN_N low, and clear that state if we have external power plugged - * and no battery faults are detected. Disconnect state resembles battery - * shutdown mode, but extra steps must be taken to get the battery out of this - * mode. - */ -enum battery_disconnect_state battery_get_disconnect_state(void) -{ - int val, rv; - /* - * Take note if we find that the battery isn't in disconnect state, - * and always return NOT_DISCONNECTED without probing the battery. - * This assumes the battery will not go to disconnect state during - * runtime. - */ - static int not_disconnected; - - if (not_disconnected) - return BATTERY_NOT_DISCONNECTED; - - if (extpower_is_present()) { - /* Check DSG_OFF bit */ - rv = bq27541_read(REG_PROTECTOR, &val); - if (rv) - return BATTERY_DISCONNECT_ERROR; - if (!(val & BIT(6))) { - not_disconnected = 1; - return BATTERY_NOT_DISCONNECTED; - } - - /* DSG_OFF is set. Verify this is not due to a safety fault */ - if (val & 0x3f) - return BATTERY_DISCONNECT_ERROR; - rv = bq27541_read(REG_FLAGS, &val); - if (rv) - return BATTERY_DISCONNECT_ERROR; - if (val & 0xfc60) - return BATTERY_DISCONNECT_ERROR; - return BATTERY_DISCONNECTED; - } - not_disconnected = 1; - return BATTERY_NOT_DISCONNECTED; -} -#endif /* CONFIG_BATTERY_REVIVE_DISCONNECT */ - -static int command_battfake(int argc, char **argv) -{ - char *e; - int v; - - if (argc == 2) { - v = strtoi(argv[1], &e, 0); - if (*e || v < -1 || v > 100) - return EC_ERROR_PARAM1; - - fake_state_of_charge = v; - } - - if (fake_state_of_charge >= 0) - ccprintf("Fake batt %d%%\n", - fake_state_of_charge); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(battfake, command_battfake, - "percent (-1 = use real level)", - "Set fake battery level"); - -#ifdef CONFIG_CMD_PWR_AVG -int battery_get_avg_current(void) -{ - int current = -EC_ERROR_UNKNOWN; - - bq27541_read(REG_AVERAGE_CURRENT, ¤t); - return current; -} - -int battery_get_avg_voltage(void) -{ - /* BQ27541 does not have this parameter */ - return -EC_ERROR_UNIMPLEMENTED; -} -#endif /* CONFIG_CMD_PWR_AVG */ - diff --git a/driver/battery/bq27621_g1.c b/driver/battery/bq27621_g1.c deleted file mode 100644 index dbda6f9c65..0000000000 --- a/driver/battery/bq27621_g1.c +++ /dev/null @@ -1,747 +0,0 @@ -/* Copyright 2014 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. - * - * Battery driver for BQ27621-G1 - */ - -#include "battery.h" -#include "console.h" -#include "extpower.h" -#include "hooks.h" -#include "i2c.h" -#include "util.h" -#include "timer.h" - -#define BQ27621_ADDR_FLAGS 0x55 -#define BQ27621_TYPE_ID 0x0621 - -#define REG_CTRL 0x00 -#define REG_TEMPERATURE 0x02 -#define REG_VOLTAGE 0x04 -#define REG_FLAGS 0x06 -#define REG_NOMINAL_CAPACITY 0x08 -#define REG_FULL_AVAILABLE_CAPACITY 0x0a -#define REG_REMAINING_CAPACITY 0x0c -#define REG_FULL_CHARGE_CAPACITY 0x0e -#define REG_EFFECTIVE_CURRENT 0x10 -#define REG_AVERAGE_POWER 0x18 -#define REG_STATE_OF_CHARGE 0x1c -#define REG_INTERNAL_TEMPERATURE 0x1e -#define REG_REMAINING_CAPACITY_UNFILTERED 0x28 -#define REG_REMAINING_CAPACITY_FILTERED 0x2a -#define REG_FULL_CHARGE_CAPACITY_UNFILTERED 0x28 -#define REG_FULL_CHARGE_CAPACITY_FILTERED 0x2a -#define REG_STATE_OF_CHARGE_UNFILTERED 0x30 -#define REG_OP_CONFIG 0x3a -#define REG_DESIGN_CAPACITY 0x3c -#define REG_DATA_CLASS 0x3e -#define REG_DATA_BLOCK 0x3f -#define REG_BLOCK_DATA_CHECKSUM 0x60 -#define REG_BLOCK_DATA_CONTROL 0x61 - -#define REGISTERS_BLOCK_OFFSET 64 -#define REGISTERS_BLOCK_OP_CONFIG 0x40 -#define REGISTERS_BLOCK_OP_CONFIG_B 0x42 -#define REGISTERS_BLOCK_DF_VERSION 0x43 - -/* State block */ -#define STATE_BLOCK_OFFSET 82 -#define STATE_BLOCK_DESIGN_CAPACITY 0x43 -#define STATE_BLOCK_DESIGN_ENERGY 0x45 -#define STATE_BLOCK_TERMINATE_VOLTAGE 0x49 -#define STATE_BLOCK_TAPER_RATE 0x54 - -/* BQ27621 Control subcommands */ -#define CONTROL_CONTROL_STATUS 0x00 -#define CONTROL_DEVICE_TYPE 0x01 -#define CONTROL_FW_VERSION 0x02 -#define CONTROL_PREV_MACWRITE 0x07 -#define CONTROL_CHEM_ID 0x08 -#define CONTROL_BAT_INSERT 0x0C -#define CONTROL_BAT_REMOVE 0x0D -#define CONTROL_TOGGLE_POWERMIN 0x10 -#define CONTROL_SET_HIBERNATE 0x11 -#define CONTROL_CLEAR_HIBERNATE 0x12 -#define CONTROL_SET_CFGUPDATE 0x13 -#define CONTROL_SHUTDOWN_ENABLE 0x1B -#define CONTROL_SHUTDOWN 0x1C -#define CONTROL_SEALED 0x20 -#define CONTROL_TOGGLE_GPOUT 0x23 -#define CONTROL_ALT_CHEM1 0x31 -#define CONTROL_ALT_CHEM2 0x32 -#define CONTROL_RESET 0x41 -#define CONTROL_SOFT_RESET 0x42 -#define CONTROL_EXIT_CFGUPDATE 0x43 -#define CONTROL_EXIT_RESIM 0x44 -#define CONTROL_UNSEAL 0x8000 - -/* BQ27621 Status bits */ -#define STATUS_SHUTDOWNEN 0x8000 -#define STATUS_WDRESET 0x4000 -#define STATUS_SS 0x2000 -#define STATUS_CALMODE 0x1000 -#define STATUS_OCVCMDCOMP 0x0200 -#define STATUS_OCVFAIL 0x0100 -#define STATUS_INITCOMP 0x0080 -#define STATUS_HIBERNATE 0x0040 -#define STATUS_POWERMIN 0x0020 -#define STATUS_SLEEP 0x0010 -#define STATUS_LDMD 0x0008 -#define STATUS_CHEMCHNG 0x0001 - -/* BQ27621 Flags bits */ -#define FLAGS_OT 0x8000 -#define FLAGS_UT 0x4000 -#define FLAGS_FC 0x0200 -#define FLAGS_CHG 0x0100 -#define FLAGS_OCVTAKEN 0x0080 -#define FLAGS_ITPOR 0x0020 -#define FLAGS_CFGUPD 0x0010 -#define FLAGS_BAT_DET 0x0008 -#define FLAGS_SOC1 0x0004 -#define FLAGS_SOCF 0x0002 -#define FLAGS_DSG 0x0001 - -/* - * There are some parameters that need to be defined in the board file: - * BQ27621_TOGGLE_POWER_MIN - Put it in minimum power mode - * (may affect I2C timing) - * BQ27621_DESIGN_CAPACITY - mAh - * BQ27621_DESIGN_ENERGY - Design Capacity x 3.7 - * BQ27621_TERMINATE_VOLTAGE - mV - * BQ27621_TAPER_CURRENT - mA - * BQ27621_CHEM_ID - 0x1202 (DEFAULT) 0x1210 (ALT_CHEM1) - * 0x354 (ALT_CHEM2) - * - * For extra large or extra small batteries, this driver scales everything but - * voltages. The recommended range is 150mAh - 6Ah - * - */ - -#define BQ27621_SCALE_FACTOR (BQ27621_DESIGN_CAPACITY < 150 ? 10.0 : \ - (BQ27621_DESIGN_CAPACITY > 6000 ? 0.1 : 1)) - -#define BQ27621_UNSCALE(x) (BQ27621_SCALE_FACTOR == 10 ? (x) / 10 : \ - (BQ27621_SCALE_FACTOR == 0.1 ? (x) * 10 : (x))) - -#define BQ27621_TAPER_RATE ((int)(BQ27621_DESIGN_CAPACITY/ \ - (0.1 * BQ27621_TAPER_CURRENT))) - -#define BQ27621_SCALED_DESIGN_CAPACITY ((int)(BQ27621_DESIGN_CAPACITY * \ - BQ27621_SCALE_FACTOR)) -#define BQ27621_SCALED_DESIGN_ENERGY ((int)(BQ27621_DESIGN_CAPACITY * \ - BQ27621_SCALE_FACTOR)) - -/* - *Everything is LSB first. Parameters need to be converted. - * - * The values from the data sheet are already LSB-first. - */ - -#define ENDIAN_SWAP_2B(x) ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8)) -#define DESIGN_CAPACITY ENDIAN_SWAP_2B(BQ27621_SCALED_DESIGN_CAPACITY) -#define DESIGN_ENERGY ENDIAN_SWAP_2B(BQ27621_SCALED_DESIGN_ENERGY) -#define TAPER_RATE ENDIAN_SWAP_2B(BQ27621_TAPER_RATE) -#define TERMINATE_VOLTAGE ENDIAN_SWAP_2B(BQ27621_TERMINATE_VOLTAGE) - -struct battery_info battery_params; - -static int bq27621_read(int offset, int *data) -{ - return i2c_read16(I2C_PORT_BATTERY, BQ27621_ADDR, offset, data); -} - -static int bq27621_read8(int offset, int *data) -{ - return i2c_read8(I2C_PORT_BATTERY, BQ27621_ADDR, offset, data); -} - -static int bq27621_write(int offset, int data) -{ - return i2c_write16(I2C_PORT_BATTERY, BQ27621_ADDR, offset, data); -} - -static int bq27621_write8(int offset, int data) -{ - return i2c_write8(I2C_PORT_BATTERY, BQ27621_ADDR, offset, data); -} - -static int bq27621_probe(void) -{ - int rv; - int battery_type_id; - - /* Delays need to be added for correct operation at > 100Kbps */ - ASSERT(i2c_ports[I2C_PORT_BATTERY].kbps <= 100); - - rv = bq27621_write(REG_CTRL, CONTROL_DEVICE_TYPE); - rv |= bq27621_read(REG_CTRL, &battery_type_id); - - if (rv) - return rv; - if (battery_type_id == BQ27621_TYPE_ID) { - battery_params.voltage_max = BATTERY_VOLTAGE_MAX; - battery_params.voltage_normal = BATTERY_VOLTAGE_NORMAL; - battery_params.voltage_min = BATTERY_VOLTAGE_MIN; - return EC_SUCCESS; - } - return EC_ERROR_UNKNOWN; -} - -static inline int bq27621_unseal(void) -{ - return bq27621_write(REG_CTRL, CONTROL_UNSEAL) | - bq27621_write(REG_CTRL, CONTROL_UNSEAL); -} - -static int bq27621_enter_config_update(void) -{ - int tries, flags = 0, rv = EC_SUCCESS; - - /* Enter Config Update Mode (Can take up to a second) */ - for (tries = 2000; tries > 0 && !(flags & FLAGS_CFGUPD) && - (rv == EC_SUCCESS); tries--) { - rv |= bq27621_write(REG_CTRL, CONTROL_SET_CFGUPDATE); - rv |= bq27621_read(REG_FLAGS, &flags); - } - - if (tries == 0) - return EC_ERROR_TIMEOUT; - else - return EC_SUCCESS; -} - -static int bq27621_enter_block_mode(int block) -{ - int rv; - rv = bq27621_write8(REG_BLOCK_DATA_CONTROL, 0); - rv |= bq27621_write8(REG_DATA_CLASS, block); - rv |= bq27621_write8(REG_DATA_BLOCK, 0); - udelay(500); /* Shouldn't be needed, doesn't work without it. */ - return rv; -} - -static int bq27621_seal(void) -{ - int rv = 0; - int status = 0, param = 0, checksum = 0; - - rv |= bq27621_write(REG_CTRL, CONTROL_CONTROL_STATUS); - rv |= bq27621_read(REG_CTRL, &status); - - if (status & STATUS_SS) /* Already sealed */ - return EC_SUCCESS; - - /* Enter Config Update Mode */ - rv = bq27621_enter_config_update(); - - if (rv) - return rv; - - /* Set up block RAM update */ - rv = bq27621_enter_block_mode(REGISTERS_BLOCK_OFFSET); - - if (rv) - return rv; - - rv = bq27621_read8(REG_BLOCK_DATA_CHECKSUM, &checksum); - - if (rv) - return rv; - - checksum = 0xff - checksum; - - rv = bq27621_read8(REGISTERS_BLOCK_OP_CONFIG_B, ¶m); - checksum -= param; /* 1B */ - - param |= 1<<5; /* Set DEF_SEAL */ - - rv = bq27621_write8(REGISTERS_BLOCK_OP_CONFIG_B, param); - checksum += param; /* 1B */ - - checksum = 0xff - (0xff & checksum); - - rv = bq27621_write8(REG_BLOCK_DATA_CHECKSUM, checksum); - - if (rv) - return rv; - - /* Exit Update */ - rv = bq27621_write(REG_CTRL, CONTROL_SOFT_RESET); - - return rv; -} - -#define CHECKSUM_2B(x) ((x & 0xff) + ((x>>8) & 0xff)) - -static int bq27621_init(void) -{ - int rv; - int status = 0, param = 0, checksum = 0; - - rv = bq27621_probe(); - - if (rv) - return rv; - - /* Unseal the device if necessary */ - rv |= bq27621_write(REG_CTRL, CONTROL_CONTROL_STATUS); - rv |= bq27621_read(REG_CTRL, &status); - - if (status & STATUS_SS) - rv |= bq27621_unseal(); - - if (rv) - return rv; - - /* Select the alternate chemistry if needed */ - rv = bq27621_write(REG_CTRL, CONTROL_CHEM_ID); - rv |= bq27621_read(REG_CTRL, ¶m); - - if (param != BQ27621_CHEM_ID) { /* Change needed */ - - if (BQ27621_CHEM_ID == 0x1202) { /* Return to default */ - rv |= bq27621_write(REG_CTRL, CONTROL_RESET); - } else { - rv |= bq27621_enter_config_update(); - - if (BQ27621_CHEM_ID == 0x1210) - rv |= bq27621_write(REG_CTRL, - CONTROL_ALT_CHEM1); - if (BQ27621_CHEM_ID == 0x0354) - rv |= bq27621_write(REG_CTRL, - CONTROL_ALT_CHEM2); - - /* - * The datasheet recommends checking the status here. - * - * If the CHEMCHG is active, it wasn't successful. - * - * There's no recommendation for what to do if it isn't. - */ - - rv |= bq27621_write(REG_CTRL, CONTROL_EXIT_CFGUPDATE); - } - } - - if (rv) - return rv; - - rv = bq27621_enter_config_update(); - - if (rv) - return rv; - - /* Set up block RAM update */ - rv = bq27621_enter_block_mode(STATE_BLOCK_OFFSET); - - if (rv) - return rv; - - rv = bq27621_read8(REG_BLOCK_DATA_CHECKSUM, &checksum); - if (rv) - return rv; - - checksum = 0xff - checksum; - - rv = bq27621_read(STATE_BLOCK_DESIGN_CAPACITY, ¶m); - checksum -= CHECKSUM_2B(param); - - rv |= bq27621_read(STATE_BLOCK_DESIGN_ENERGY, ¶m); - checksum -= CHECKSUM_2B(param); - - rv |= bq27621_read(STATE_BLOCK_TERMINATE_VOLTAGE, ¶m); - checksum -= CHECKSUM_2B(param); - - rv |= bq27621_read(STATE_BLOCK_TAPER_RATE, ¶m); - checksum -= CHECKSUM_2B(param); - - if (rv) - return rv; - - rv = bq27621_write(STATE_BLOCK_DESIGN_CAPACITY, DESIGN_CAPACITY); - checksum += CHECKSUM_2B(DESIGN_CAPACITY); - - rv |= bq27621_write(STATE_BLOCK_DESIGN_ENERGY, DESIGN_ENERGY); - checksum += CHECKSUM_2B(DESIGN_ENERGY); - - rv |= bq27621_write(STATE_BLOCK_TERMINATE_VOLTAGE, TERMINATE_VOLTAGE); - checksum += CHECKSUM_2B(TERMINATE_VOLTAGE); - - rv |= bq27621_write(STATE_BLOCK_TAPER_RATE, TAPER_RATE); - checksum += CHECKSUM_2B(TAPER_RATE); - - checksum = 0xff - (0xff & checksum); - - - if (rv) - return rv; - - rv = bq27621_write8(REG_BLOCK_DATA_CHECKSUM, checksum); - - rv |= bq27621_write(REG_CTRL, CONTROL_SOFT_RESET); - - if (rv) - return rv; - - bq27621_seal(); - - return rv; -} - -static void probe_type_id_init(void) -{ - int rv = EC_SUCCESS; - - rv = bq27621_probe(); - - if (rv) - return; - - rv = bq27621_init(); - - if (rv) { /* Try it once more */ - rv = bq27621_write(REG_CTRL, CONTROL_RESET); - rv |= bq27621_init(); - } -} - -DECLARE_HOOK(HOOK_INIT, probe_type_id_init, HOOK_PRIO_DEFAULT); - -/* Some of the functions to make this battery "smart" */ - -int battery_device_name(char *device_name, int buf_size) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -int battery_state_of_charge_abs(int *percent) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -int battery_remaining_capacity(int *capacity) -{ - int scaled_value, err_code; - - err_code = bq27621_read(REG_REMAINING_CAPACITY, &scaled_value); - - *capacity = BQ27621_UNSCALE(scaled_value); - - return err_code; -} - -int battery_full_charge_capacity(int *capacity) -{ - int scaled_value, err_code; - - err_code = bq27621_read(REG_FULL_CHARGE_CAPACITY, &scaled_value); - - *capacity = BQ27621_UNSCALE(scaled_value); - - return err_code; -} - -int battery_time_to_empty(int *minutes) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -int battery_time_to_full(int *minutes) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -int battery_cycle_count(int *count) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -int battery_design_capacity(int *capacity) -{ - int scaled_value, err_code; - - err_code = bq27621_read(REG_DESIGN_CAPACITY, &scaled_value); - - *capacity = BQ27621_UNSCALE(scaled_value); - - return err_code; -} - -int battery_time_at_rate(int rate, int *minutes) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -int battery_device_chemistry(char *dest, int size) -{ - uint32_t rv; - int param; - - rv = bq27621_write(REG_CTRL, CONTROL_CHEM_ID); - rv |= bq27621_read(REG_CTRL, ¶m); - - if (param == 0x1202) - strzcpy(dest, "0x1202 (default)", size); - if (param == 0x1210) - strzcpy(dest, "0x1210 (ALT_CHEM1)", size); - if (param == 0x0354) - strzcpy(dest, "0x0354 (ALT_CHEM2)", size); - - return EC_SUCCESS; -} - -int battery_serial_number(int *serial) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -int battery_manufacture_date(int *year, int *month, int *day) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -int battery_design_voltage(int *voltage) -{ - *voltage = BATTERY_VOLTAGE_NORMAL; - - return EC_SUCCESS; -} - -int battery_get_mode(int *mode) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -int battery_status(int *status) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -enum battery_present battery_is_present(void) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -void battery_get_params(struct batt_params *batt) -{ - /* Reset flags */ - batt->flags = 0; - - if (bq27621_read(REG_TEMPERATURE, &batt->temperature)) - batt->flags |= BATT_FLAG_BAD_TEMPERATURE; - else - batt->flags |= BATT_FLAG_RESPONSIVE; /* Battery is responding */ - - if (bq27621_read8(REG_STATE_OF_CHARGE, &batt->state_of_charge)) - batt->flags |= BATT_FLAG_BAD_STATE_OF_CHARGE; - - if (bq27621_read(REG_VOLTAGE, &batt->voltage)) - batt->flags |= BATT_FLAG_BAD_VOLTAGE; - - batt->flags |= BATT_FLAG_BAD_CURRENT; - batt->current = 0; - - /* Default to not desiring voltage and current */ - batt->desired_voltage = batt->desired_current = 0; -} - -/* Wait until battery is totally stable */ -int battery_wait_for_stable(void) -{ - /* TODO(crosbug.com/p/30426): implement me */ - return EC_SUCCESS; -} - -#ifdef CONFIG_CMD_BATDEBUG - #define CPRINTF(format, args...) cprintf(CC_I2C, format, ## args) -#else - #define CPRINTF(format, args...) -#endif - -#ifdef CONFIG_CMD_BATDEBUG - -static int command_fgunseal(int argc, char **argv) -{ - int rv = EC_SUCCESS; - - if (argc > 1) - return EC_ERROR_PARAM_COUNT; - - rv = bq27621_unseal(); - - return rv; -} - -DECLARE_CONSOLE_COMMAND(fgunseal, command_fgunseal, - "", - "Unseal the fg"); - -static int command_fgseal(int argc, char **argv) -{ - int rv = EC_SUCCESS; - - if (argc > 1) - return EC_ERROR_PARAM_COUNT; - - rv = bq27621_seal(); - - return rv; -} - -DECLARE_CONSOLE_COMMAND(fgseal, command_fgseal, - "", - "Seal the fg"); - -static int command_fginit(int argc, char **argv) -{ - int rv = EC_SUCCESS; - int force = 0; - int flags = 0; - int unconfigured = 0; - char *e; - - if (argc > 2) - return EC_ERROR_PARAM_COUNT; - - if (argc == 2) { - force = strtoi(argv[1], &e, 0); - if (*e) - return EC_ERROR_PARAM1; - } - - rv = bq27621_read(REG_FLAGS, &flags); - unconfigured = flags & FLAGS_ITPOR; - - if (!unconfigured && force) { - rv |= bq27621_write(REG_CTRL, CONTROL_RESET); - unconfigured = (rv == EC_SUCCESS); - } - - if (unconfigured) - rv |= bq27621_init(); - - return rv; -} - -DECLARE_CONSOLE_COMMAND(fginit, command_fginit, - "[force]", - "Initialize the fg"); - -static int command_fgprobe(int argc, char **argv) -{ - int rv = EC_SUCCESS; - - if (argc != 1) - return EC_ERROR_PARAM_COUNT; - - rv = bq27621_probe(); - - return rv; -} - -DECLARE_CONSOLE_COMMAND(fgprobe, command_fgprobe, - "", - "Probe the fg"); - -static int command_fgrd(int argc, char **argv) -{ - int cmd, len; - int rv = EC_SUCCESS; - int data; - char *e; - - if (argc < 3) - return EC_ERROR_PARAM_COUNT; - - cmd = strtoi(argv[1], &e, 0); - if (*e) - return EC_ERROR_PARAM1; - - len = strtoi(argv[2], &e, 0); - if (*e) - return EC_ERROR_PARAM2; - - if (len == 2) - rv = bq27621_read(cmd, &data); - else if (len == 1) - rv = bq27621_read8(cmd, &data); - else - return EC_ERROR_PARAM2; - - CPRINTF("Read %d bytes @0xaa %0x: 0x%0x\n", len, cmd, data); - - return rv; -} - -DECLARE_CONSOLE_COMMAND(fgrd, command_fgrd, - "cmd len", - "Read _len_ words from the fg"); - -static int command_fgcmd(int argc, char **argv) -{ - int cmd, data, byte = 0; - char *e; - - if (argc < 3 || argc > 4) - return EC_ERROR_PARAM_COUNT; - - cmd = strtoi(argv[1], &e, 0); - if (*e) - return EC_ERROR_PARAM1; - - data = strtoi(argv[2], &e, 0); - if (*e) - return EC_ERROR_PARAM2; - - if (argc >= 4) { - byte = strtoi(argv[3], &e, 0); - if (*e) - return EC_ERROR_PARAM3; - } - - if (byte) { - CPRINTF("Write a byte @0xaa %0x: 0x%0x\n", cmd, data); - return bq27621_write8(cmd, data); - } else { - CPRINTF("Write 2 bytes @0xaa %0x: 0x%0x\n", cmd, data); - return bq27621_write(cmd, data); - } - -} - -DECLARE_CONSOLE_COMMAND(fgcmd, command_fgcmd, - "cmd data [byte]", - "Send a cmd to the fg"); - -static int command_fgcmdrd(int argc, char **argv) -{ - int cmd, data, val; - int rv = EC_SUCCESS; - char *e; - - if (argc < 3) - return EC_ERROR_PARAM_COUNT; - - cmd = strtoi(argv[1], &e, 0); - if (*e) - return EC_ERROR_PARAM1; - - data = strtoi(argv[2], &e, 0); - if (*e) - return EC_ERROR_PARAM2; - - rv = bq27621_write(cmd, data); - rv |= bq27621_read(cmd, &val); - - CPRINTF("Read: @0xaa (%x %x) %x\n", cmd, data, val); - return rv; -} - -DECLARE_CONSOLE_COMMAND(fgcmdrd, command_fgcmdrd, - "cmd data", - "Send a 2-byte cmd to the fg, read back the 2-byte result"); - -#endif /* CONFIG_CMD_BATDEBUG */ - diff --git a/driver/battery/bq4050.c b/driver/battery/bq4050.c deleted file mode 100644 index 684ade47e6..0000000000 --- a/driver/battery/bq4050.c +++ /dev/null @@ -1,39 +0,0 @@ -/* Copyright 2018 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. - * - * Smart battery driver for TI BQ4050 family, including BQ40Z50 (and -R1, -R2), - * BQ40Z552, and BQ40Z60. - */ - -#include "battery_smart.h" -#include "util.h" - -#include <stdint.h> - -int battery_bq4050_imbalance_mv(void) -{ - /* - * The BQ4050 family can manage up to four cells. In testing it always - * returns a voltage for each cell, regardless of the number of cells - * actually installed in the pack. Unpopulated cells read exactly zero. - */ - static const uint8_t cell_voltage_address[4] = { - 0x3c, 0x3d, 0x3e, 0x3f - }; - int i, res, cell_voltage; - int n_cells = 0; - int max_voltage = 0; - int min_voltage = 0xffff; - - for (i = 0; i != ARRAY_SIZE(cell_voltage_address); ++i) { - res = sb_read(cell_voltage_address[i], &cell_voltage); - if (res == EC_SUCCESS && cell_voltage != 0) { - n_cells++; - max_voltage = MAX(max_voltage, cell_voltage); - min_voltage = MIN(min_voltage, cell_voltage); - } - } - return (n_cells == 0) ? 0 : max_voltage - min_voltage; -} - diff --git a/driver/battery/max17055.c b/driver/battery/max17055.c deleted file mode 100644 index bb0b941937..0000000000 --- a/driver/battery/max17055.c +++ /dev/null @@ -1,692 +0,0 @@ -/* Copyright 2017 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. - * - * Battery driver for MAX17055. - */ - -#include "battery.h" -#include "console.h" -#include "extpower.h" -#include "hooks.h" -#include "i2c.h" -#include "max17055.h" -#include "printf.h" -#include "timer.h" -#include "util.h" - -/* Console output macros */ -#define CPRINTS(format, args...) cprints(CC_CHARGER, format, ## args) - -/* - * For max17055 to finish battery presence detection, this is the minimal time - * we have to wait since the last POR. LSB = 175ms. - */ -#define RELIABLE_BATT_DETECT_TIME 0x10 - -/* - * Convert the register values to the units that match - * smart battery protocol. - */ - -/* Voltage reg value to mV */ -#define VOLTAGE_CONV(REG) ((REG * 5) >> 6) -/* Current reg value to mA */ -#define CURRENT_CONV(REG) (((REG * 25) >> 4) / BATTERY_MAX17055_RSENSE) -/* Capacity reg value to mAh */ -#define CAPACITY_CONV(REG) (REG * 5 / BATTERY_MAX17055_RSENSE) -/* Time reg value to minute */ -#define TIME_CONV(REG) ((REG * 3) >> 5) -/* Temperature reg value to 0.1K */ -#define TEMPERATURE_CONV(REG) (((REG * 10) >> 8) + 2731) -/* Percentage reg value to 1% */ -#define PERCENTAGE_CONV(REG) (REG >> 8) -/* Cycle count reg value (LSB = 1%) to absolute count (100%) */ -#define CYCLE_COUNT_CONV(REG) ((REG * 5) >> 9) - -/* Useful macros */ -#define MAX17055_READ_DEBUG(offset, ptr_reg) \ - do { \ - if (max17055_read(offset, ptr_reg)) { \ - CPRINTS("%s: failed to read reg %02x", \ - __func__, offset); \ - return; \ - } \ - } while (0) -#define MAX17055_WRITE_DEBUG(offset, reg) \ - do { \ - if (max17055_write(offset, reg)) { \ - CPRINTS("%s: failed to read reg %02x", \ - __func__, offset); \ - return; \ - } \ - } while (0) - -static int fake_state_of_charge = -1; - -static int max17055_read(int offset, int *data) -{ - return i2c_read16(I2C_PORT_BATTERY, MAX17055_ADDR_FLAGS, - offset, data); -} - -static int max17055_write(int offset, int data) -{ - return i2c_write16(I2C_PORT_BATTERY, MAX17055_ADDR_FLAGS, - offset, data); -} - -/* Return 1 if the device id is correct. */ -static int max17055_probe(void) -{ - int dev_id; - - if (max17055_read(REG_DEVICE_NAME, &dev_id)) - return 0; - if (dev_id == MAX17055_DEVICE_ID) - return 1; - return 0; -} - -int battery_device_name(char *device_name, int buf_size) -{ - int dev_id; - int rv; - - rv = max17055_read(REG_DEVICE_NAME, &dev_id); - if (!rv) - snprintf(device_name, buf_size, "0x%04x", dev_id); - - return rv; -} - -int battery_state_of_charge_abs(int *percent) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -int battery_remaining_capacity(int *capacity) -{ - int rv; - int reg; - - rv = max17055_read(REG_REMAINING_CAPACITY, ®); - if (!rv) - *capacity = CAPACITY_CONV(reg); - return rv; -} - -int battery_full_charge_capacity(int *capacity) -{ - int rv; - int reg; - - rv = max17055_read(REG_FULL_CHARGE_CAPACITY, ®); - if (!rv) - *capacity = CAPACITY_CONV(reg); - return rv; -} - -int battery_time_to_empty(int *minutes) -{ - int rv; - int reg; - - rv = max17055_read(REG_TIME_TO_EMPTY, ®); - if (!rv) - *minutes = TIME_CONV(reg); - return rv; -} - -int battery_time_to_full(int *minutes) -{ - int rv; - int reg; - - rv = max17055_read(REG_TIME_TO_FULL, ®); - if (!rv) - *minutes = TIME_CONV(reg); - return rv; -} - -int battery_cycle_count(int *count) -{ - int rv; - int reg; - - rv = max17055_read(REG_CYCLE_COUNT, ®); - if (!rv) - *count = CYCLE_COUNT_CONV(reg); - return rv; -} - -int battery_design_capacity(int *capacity) -{ - int rv; - int reg; - - rv = max17055_read(REG_DESIGN_CAPACITY, ®); - if (!rv) - *capacity = CAPACITY_CONV(reg); - return rv; -} - -int battery_time_at_rate(int rate, int *minutes) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -int battery_device_chemistry(char *dest, int size) -{ - strzcpy(dest, "<unkn>", size); - - return EC_SUCCESS; -} - -int battery_serial_number(int *serial) -{ - /* TODO(philipchen): Implement this function. */ - *serial = 0xFFFFFFFF; - return EC_SUCCESS; -} - -int battery_manufacture_date(int *year, int *month, int *day) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -int battery_design_voltage(int *voltage) -{ - *voltage = battery_get_info()->voltage_normal; - - return EC_SUCCESS; -} - -int battery_get_mode(int *mode) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -int battery_status(int *status) -{ - int rv; - int reg; - - *status = 0; - - rv = max17055_read(REG_FSTAT, ®); - if (rv) - return rv; - if (reg & FSTAT_FQ) - *status |= BATTERY_FULLY_CHARGED; - - rv = max17055_read(REG_AVERAGE_CURRENT, ®); - if (rv) - return rv; - if (reg >> 15) - *status |= BATTERY_DISCHARGING; - - return EC_SUCCESS; -} - -enum battery_present battery_is_present(void) -{ - int reg = 0; - static uint8_t batt_pres_sure; - - if (max17055_read(REG_STATUS, ®)) - return BP_NOT_SURE; - - if (reg & STATUS_BST) - return BP_NO; - - if (!batt_pres_sure) { - /* - * The battery detection result is not reliable within - * ~2.8 secs since POR. - */ - if (!max17055_read(REG_TIMERH, ®)) { - /* - * The LSB of TIMERH reg is 3.2 hrs. If the reg has a - * nonzero value, battery detection must have been - * settled. - */ - if (reg) { - batt_pres_sure = 1; - return BP_YES; - } - if (!max17055_read(REG_TIMER, ®) && - ((uint32_t)reg > RELIABLE_BATT_DETECT_TIME)) { - batt_pres_sure = 1; - return BP_YES; - } - } - return BP_NOT_SURE; - } - return BP_YES; -} - -void battery_get_params(struct batt_params *batt) -{ - int reg = 0; - struct batt_params batt_new = {0}; - - /* - * Assuming the battery is responsive as long as - * max17055 finds battery is present. - */ - batt_new.is_present = battery_is_present(); - - if (batt_new.is_present == BP_YES) - batt_new.flags |= BATT_FLAG_RESPONSIVE; - else if (batt_new.is_present == BP_NO) - /* Battery is not present, gauge won't report useful info. */ - goto batt_out; - - if (max17055_read(REG_TEMPERATURE, ®)) - batt_new.flags |= BATT_FLAG_BAD_TEMPERATURE; - - batt_new.temperature = TEMPERATURE_CONV((int16_t)reg); - - if (max17055_read(REG_STATE_OF_CHARGE, ®) && - fake_state_of_charge < 0) - batt_new.flags |= BATT_FLAG_BAD_STATE_OF_CHARGE; - - batt_new.state_of_charge = fake_state_of_charge >= 0 ? - fake_state_of_charge : PERCENTAGE_CONV(reg); - - if (max17055_read(REG_VOLTAGE, ®)) - batt_new.flags |= BATT_FLAG_BAD_VOLTAGE; - - batt_new.voltage = VOLTAGE_CONV(reg); - - if (max17055_read(REG_AVERAGE_CURRENT, ®)) - batt_new.flags |= BATT_FLAG_BAD_CURRENT; - - batt_new.current = CURRENT_CONV((int16_t)reg); - - batt_new.desired_voltage = battery_get_info()->voltage_max; - batt_new.desired_current = BATTERY_DESIRED_CHARGING_CURRENT; - - if (battery_remaining_capacity(&batt_new.remaining_capacity)) - batt_new.flags |= BATT_FLAG_BAD_REMAINING_CAPACITY; - - if (battery_full_charge_capacity(&batt_new.full_capacity)) - batt_new.flags |= BATT_FLAG_BAD_FULL_CAPACITY; - - /* - * Charging allowed if both desired voltage and current are nonzero - * and battery isn't full (and we read them all correctly). - */ - if (!(batt_new.flags & BATT_FLAG_BAD_STATE_OF_CHARGE) && - batt_new.desired_voltage && - batt_new.desired_current && - batt_new.state_of_charge < BATTERY_LEVEL_FULL) - batt_new.flags |= BATT_FLAG_WANT_CHARGE; - - if (battery_status(&batt_new.status)) - batt_new.flags |= BATT_FLAG_BAD_STATUS; - -batt_out: - /* Update visible battery parameters */ - memcpy(batt, &batt_new, sizeof(*batt)); -} - -#ifdef CONFIG_CMD_PWR_AVG -int battery_get_avg_current(void) -{ - /* TODO(crbug.com/752320) implement this */ - return EC_ERROR_UNIMPLEMENTED; -} - -int battery_get_avg_voltage(void) -{ - /* TODO(crbug.com/752320) implement this */ - return -EC_ERROR_UNIMPLEMENTED; -} -#endif /* CONFIG_CMD_PWR_AVG */ - -/* Wait until battery is totally stable. */ -int battery_wait_for_stable(void) -{ - /* TODO(philipchen): Implement this function. */ - return EC_SUCCESS; -} - -static int max17055_poll_flag_clear(int regno, int mask, int timeout) -{ - int reg; - - do { - if (max17055_read(regno, ®)) - return EC_ERROR_UNKNOWN; - - if (!(mask & reg)) - return EC_SUCCESS; - - msleep(10); - timeout -= 10; - } while (timeout > 0); - - return EC_ERROR_TIMEOUT; -} - -static int max17055_load_ocv_table(const struct max17055_batt_profile *config) -{ - int i; - int reg; - int retries = 3; - - /* Unlock ocv table */ - if (max17055_write(REG_LOCK1, 0x0059) || - max17055_write(REG_LOCK2, 0x00c4)) - return EC_ERROR_UNKNOWN; - - ASSERT(config->ocv_table); - - /* Write ocv data */ - for (i = 0; i < MAX17055_OCV_TABLE_SIZE; i++) { - if (max17055_write(REG_OCV_TABLE_START + i, - config->ocv_table[i])) - return EC_ERROR_UNKNOWN; - } - - /* Read and compare ocv data */ - for (i = 0; i < MAX17055_OCV_TABLE_SIZE; i++) { - if (max17055_read(REG_OCV_TABLE_START + i, ®) || - reg != config->ocv_table[i]) - return EC_ERROR_UNKNOWN; - } - - while (--retries) { - /* Lock ocv table */ - if (max17055_write(REG_LOCK1, 0x0000) || - max17055_write(REG_LOCK2, 0x0000)) - return EC_ERROR_UNKNOWN; - - /* - * If the ocv table remains unlocked, the MAX17055 cannot - * monitor the capacity of the battery. Therefore, it is very - * critical that the ocv table is locked. To verify it is - * locked, simply read back the values. However, this time, - * all values should be read as 0x0000. - */ - for (i = 0; i < MAX17055_OCV_TABLE_SIZE; i++) { - reg = 0xff; - if (max17055_read(REG_OCV_TABLE_START + i, ®)) - return EC_ERROR_UNKNOWN; - if (reg) - break; - } - if (i == MAX17055_OCV_TABLE_SIZE) - break; - msleep(20); - } - if (!retries) - return EC_ERROR_TIMEOUT; - - /* - * Delay 180ms is to prepare the environment to load the custom - * battery parameters. Otherwise, the initialization operation - * has a very small probability of failure. - */ - msleep(180); - - return EC_SUCCESS; -} - -static int max17055_exit_hibernate(void) -{ - /* - * Write REG_COMMAND with 0x90 to force the firmware to stop running. - * Write REG_HIBCFG with 0x00 to exit hibernate mode immediately. - * Write REG_COMMAND with 0x00 to run the firmware again. - */ - if (max17055_write(REG_COMMAND, 0x90) || - max17055_write(REG_HIBCFG, 0x00) || - max17055_write(REG_COMMAND, 0x00)) - return EC_ERROR_UNKNOWN; - - return EC_SUCCESS; -} - -/* Configured MAX17055 with the battery parameters for full model. */ -static int max17055_load_batt_model_full(void) -{ - int reg; - int hib_cfg; - - const struct max17055_batt_profile *config; - - config = max17055_get_batt_profile(); - - /* Store the original HibCFG value. */ - if (max17055_read(REG_HIBCFG, &hib_cfg)) - return EC_ERROR_UNKNOWN; - - /* Force exit from hibernate */ - if (max17055_exit_hibernate()) - return EC_ERROR_UNKNOWN; - - /* Write LearnCFG with LS 7 */ - if (max17055_write(REG_LEARNCFG, config->learn_cfg | 0x0070)) - return EC_ERROR_UNKNOWN; - - /* - * Unlock ocv table access, write/compare/verify custom ocv table, - * lock ocv table access. - */ - if (max17055_load_ocv_table(config)) - return EC_ERROR_UNKNOWN; - - /* Write custom parameters */ - if (max17055_write(REG_DESIGN_CAPACITY, config->design_cap) || - max17055_write(REG_DQACC, config->design_cap >> 4) || - max17055_write(REG_DPACC, 0x0c80) || - max17055_write(REG_CHARGE_TERM_CURRENT, config->ichg_term) || - max17055_write(REG_EMPTY_VOLTAGE, config->v_empty_detect)) - return EC_ERROR_UNKNOWN; - - if (max17055_write(REG_RCOMP0, config->rcomp0) || - max17055_write(REG_TEMPCO, config->tempco) || - max17055_write(REG_QR_TABLE00, config->qr_table00) || - max17055_write(REG_QR_TABLE10, config->qr_table10)) - return EC_ERROR_UNKNOWN; - - /* Update required capacity registers */ - if (max17055_write(REG_REMAINING_CAPACITY, 0x0000) || - max17055_read(REG_VFSOC, ®)) - return EC_ERROR_UNKNOWN; - - if (max17055_write(REG_VFSOC0, reg) || - max17055_write(REG_FULL_CHARGE_CAPACITY, config->design_cap) || - max17055_write(REG_FULLCAPNOM, config->design_cap)) - return EC_ERROR_UNKNOWN; - - /* Prepare to Load Model */ - if (max17055_write(REG_REMAINING_CAPACITY, 0x0000) || - max17055_write(REG_MIXCAP, config->design_cap)) - return EC_ERROR_UNKNOWN; - - /* Initiate model loading */ - if (max17055_read(REG_CONFIG2, ®) || - max17055_write(REG_CONFIG2, reg | CONFIG2_LDMDL)) - return EC_ERROR_UNKNOWN; - - if (max17055_poll_flag_clear(REG_CONFIG2, CONFIG2_LDMDL, 500)) - return EC_ERROR_UNKNOWN; - - /* Write LearnCFG with LS 0 */ - if (max17055_write(REG_LEARNCFG, config->learn_cfg & 0xff8f) || - max17055_write(REG_QR_TABLE20, config->qr_table20) || - max17055_write(REG_QR_TABLE30, config->qr_table30)) - return EC_ERROR_UNKNOWN; - - /* Restore the original HibCFG value. */ - if (max17055_write(REG_HIBCFG, hib_cfg)) - return EC_ERROR_UNKNOWN; - - return EC_SUCCESS; -} - -/* - * Configured MAX17055 with the battery parameters for short model or ez model - */ -static int max17055_load_batt_model_short_or_ez(void) -{ - int hib_cfg; - int dqacc; - int dpacc; - - const struct max17055_batt_profile *config; - - config = max17055_get_batt_profile(); - - if (config->is_ez_config) { - dqacc = config->design_cap / 32; - /* Choose the model for charge voltage > 4.275V. */ - dpacc = dqacc * 51200 / config->design_cap; - } else { - dqacc = config->design_cap / 16; - dpacc = config->dpacc; - } - - if (max17055_write(REG_DESIGN_CAPACITY, config->design_cap) || - max17055_write(REG_DQACC, dqacc) || - max17055_write(REG_CHARGE_TERM_CURRENT, config->ichg_term) || - max17055_write(REG_EMPTY_VOLTAGE, config->v_empty_detect)) - return EC_ERROR_UNKNOWN; - - if (!config->is_ez_config) { - if (max17055_write(REG_LEARNCFG, config->learn_cfg)) - return EC_ERROR_UNKNOWN; - } - - /* Store the original HibCFG value. */ - if (max17055_read(REG_HIBCFG, &hib_cfg)) - return EC_ERROR_UNKNOWN; - - /* Force exit from hibernate */ - if (max17055_exit_hibernate()) - return EC_ERROR_UNKNOWN; - - if (max17055_write(REG_DPACC, dpacc) || - max17055_write(REG_MODELCFG, (MODELCFG_REFRESH | MODELCFG_VCHG))) - return EC_ERROR_UNKNOWN; - - /* Delay up to 500 ms until MODELCFG.REFRESH bit == 0. */ - if (max17055_poll_flag_clear(REG_MODELCFG, MODELCFG_REFRESH, 500)) - return EC_ERROR_UNKNOWN; - - if (!config->is_ez_config) { - if (max17055_write(REG_RCOMP0, config->rcomp0) || - max17055_write(REG_TEMPCO, config->tempco) || - max17055_write(REG_QR_TABLE00, config->qr_table00) || - max17055_write(REG_QR_TABLE10, config->qr_table10) || - max17055_write(REG_QR_TABLE20, config->qr_table20) || - max17055_write(REG_QR_TABLE30, config->qr_table30)) - return EC_ERROR_UNKNOWN; - } - - /* Restore the original HibCFG value. */ - if (max17055_write(REG_HIBCFG, hib_cfg)) - return EC_ERROR_UNKNOWN; - return EC_SUCCESS; -} - -static int max17055_load_batt_model(void) -{ - if (IS_ENABLED(CONFIG_BATTERY_MAX17055_FULL_MODEL)) - return max17055_load_batt_model_full(); - else - return max17055_load_batt_model_short_or_ez(); -} - -static void max17055_init(void) -{ - int reg; - int retries = 80; -#ifdef CONFIG_BATTERY_MAX17055_ALERT - const struct max17055_alert_profile *alert_profile = - max17055_get_alert_profile(); -#endif - - if (!max17055_probe()) { - CPRINTS("Wrong max17055 id!"); - return; - } - - /* - * Set CONFIG.TSEL to measure temperature using external thermistor. - * Set it as early as possible because max17055 takes up to 1000ms to - * have the first reliable external temperature reading. - */ - MAX17055_READ_DEBUG(REG_CONFIG, ®); - MAX17055_WRITE_DEBUG(REG_CONFIG, (reg | CONF_TSEL)); - - MAX17055_READ_DEBUG(REG_STATUS, ®); - - /* Check for POR */ - if (STATUS_POR & reg) { - /* Delay up to 800 ms until FSTAT.DNR bit == 0. */ - while (--retries) { - MAX17055_READ_DEBUG(REG_FSTAT, ®); - if (!(FSTAT_DNR & reg)) - break; - msleep(10); - } - if (!retries) { - CPRINTS("%s: timeout waiting for FSTAT.DNR cleared", - __func__); - return; - } - - if (max17055_load_batt_model()) { - CPRINTS("max17055 configuration failed!"); - return; - } - - /* Clear POR bit */ - MAX17055_READ_DEBUG(REG_STATUS, ®); - MAX17055_WRITE_DEBUG(REG_STATUS, (reg & ~STATUS_POR)); - } else { - const struct max17055_batt_profile *config; - - config = max17055_get_batt_profile(); - MAX17055_READ_DEBUG(REG_DESIGN_CAPACITY, ®); - - /* - * Reload the battery model if the current running one - * is wrong. - */ - if (config->design_cap != reg) { - CPRINTS("max17055 reconfig..."); - if (max17055_load_batt_model()) { - CPRINTS("max17055 configuration failed!"); - return; - } - } - } - -#ifdef CONFIG_BATTERY_MAX17055_ALERT - /* Set voltage alert range */ - MAX17055_WRITE_DEBUG(REG_VALRTTH, alert_profile->v_alert_mxmn); - /* Set temperature alert range */ - MAX17055_WRITE_DEBUG(REG_TALRTTH, alert_profile->t_alert_mxmn); - /* Set state-of-charge alert range */ - MAX17055_WRITE_DEBUG(REG_SALRTTH, alert_profile->s_alert_mxmn); - /* Set current alert range */ - MAX17055_WRITE_DEBUG(REG_IALRTTH, alert_profile->i_alert_mxmn); - - /* Disable all sticky bits; enable alert AEN */ - MAX17055_READ_DEBUG(REG_CONFIG, ®); - MAX17055_WRITE_DEBUG(REG_CONFIG, (reg & ~CONF_ALL_STICKY) | CONF_AEN); - - /* Clear alerts */ - MAX17055_READ_DEBUG(REG_STATUS, ®); - MAX17055_WRITE_DEBUG(REG_STATUS, reg & ~STATUS_ALL_ALRT); -#endif - - CPRINTS("max17055 configuration succeeded!"); -} -DECLARE_HOOK(HOOK_INIT, max17055_init, HOOK_PRIO_DEFAULT); diff --git a/driver/battery/max17055.h b/driver/battery/max17055.h deleted file mode 100644 index 0f97fb90f0..0000000000 --- a/driver/battery/max17055.h +++ /dev/null @@ -1,250 +0,0 @@ -/* Copyright 2017 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. - * - * Battery driver for MAX17055. - */ - -#ifndef __CROS_EC_MAX17055_H -#define __CROS_EC_MAX17055_H - -#define MAX17055_ADDR_FLAGS 0x36 -#define MAX17055_DEVICE_ID 0x4010 -#define MAX17055_OCV_TABLE_SIZE 48 - -#define REG_STATUS 0x00 -#define REG_VALRTTH 0x01 -#define REG_TALRTTH 0x02 -#define REG_SALRTTH 0x03 -#define REG_AT_RATE 0x04 -#define REG_REMAINING_CAPACITY 0x05 -#define REG_STATE_OF_CHARGE 0x06 -#define REG_TEMPERATURE 0x08 -#define REG_VOLTAGE 0x09 -#define REG_CURRENT 0x0a -#define REG_AVERAGE_CURRENT 0x0b -#define REG_MIXCAP 0x0f -#define REG_FULL_CHARGE_CAPACITY 0x10 -#define REG_TIME_TO_EMPTY 0x11 -#define REG_QR_TABLE00 0x12 -#define REG_CONFIG 0x1D -#define REG_AVERAGE_TEMPERATURE 0x16 -#define REG_CYCLE_COUNT 0x17 -#define REG_DESIGN_CAPACITY 0x18 -#define REG_AVERAGE_VOLTAGE 0x19 -#define REG_MAX_MIN_TEMP 0x1a -#define REG_MAX_MIN_VOLT 0x1b -#define REG_MAX_MIN_CURR 0x1c -#define REG_CHARGE_TERM_CURRENT 0x1e -#define REG_TIME_TO_FULL 0x20 -#define REG_DEVICE_NAME 0x21 -#define REG_QR_TABLE10 0x22 -#define REG_FULLCAPNOM 0x23 -#define REG_LEARNCFG 0x28 -#define REG_QR_TABLE20 0x32 -#define REG_RCOMP0 0x38 -#define REG_TEMPCO 0x39 -#define REG_EMPTY_VOLTAGE 0x3a -#define REG_FSTAT 0x3d -#define REG_TIMER 0x3e -#define REG_QR_TABLE30 0x42 -#define REG_DQACC 0x45 -#define REG_DPACC 0x46 -#define REG_VFSOC0 0x48 -#define REG_COMMAND 0x60 -#define REG_LOCK1 0x62 -#define REG_LOCK2 0x63 -#define REG_OCV_TABLE_START 0x80 -#define REG_STATUS2 0xb0 -#define REG_IALRTTH 0xb4 -#define REG_HIBCFG 0xba -#define REG_CONFIG2 0xbb -#define REG_TIMERH 0xbe -#define REG_MODELCFG 0xdb -#define REG_VFSOC 0xff - -/* Status reg (0x00) flags */ -#define STATUS_POR BIT(1) -#define STATUS_IMN BIT(2) -#define STATUS_BST BIT(3) -#define STATUS_IMX BIT(6) -#define STATUS_VMN BIT(8) -#define STATUS_TMN BIT(9) -#define STATUS_SMN BIT(10) -#define STATUS_VMX BIT(12) -#define STATUS_TMX BIT(13) -#define STATUS_SMX BIT(14) -#define STATUS_ALL_ALRT \ - (STATUS_IMN | STATUS_IMX | STATUS_VMN | STATUS_VMX | STATUS_TMN | \ - STATUS_TMX | STATUS_SMN | STATUS_SMX) - -/* Alert disable values (0x01, 0x02, 0x03, 0xb4) */ -#define VALRT_DISABLE 0xff00 -#define TALRT_DISABLE 0x7f80 -#define SALRT_DISABLE 0xff00 -#define IALRT_DISABLE 0x7f80 - -/* Config reg (0x1d) flags */ -#define CONF_AEN BIT(2) -#define CONF_IS BIT(11) -#define CONF_VS BIT(12) -#define CONF_TS BIT(13) -#define CONF_SS BIT(14) -#define CONF_TSEL BIT(15) -#define CONF_ALL_STICKY (CONF_IS | CONF_VS | CONF_TS | CONF_SS) - -/* FStat reg (0x3d) flags */ -#define FSTAT_DNR 0x0001 -#define FSTAT_FQ 0x0080 - -/* Config2 reg (0xbb) flags */ -#define CONFIG2_LDMDL BIT(5) - -/* ModelCfg reg (0xdb) flags */ -#define MODELCFG_REFRESH BIT(15) -#define MODELCFG_VCHG BIT(10) - -/* Smart battery status bits (sbs reg 0x16) */ -#define BATTERY_DISCHARGING 0x40 -#define BATTERY_FULLY_CHARGED 0x20 - -/* - * Before we have the battery fully characterized, we use these macros to - * convert basic battery parameters to max17055 reg values for ez config. - */ - -/* Convert design capacity in mAh to max17055 0x18 reg value */ -#define MAX17055_DESIGNCAP_REG(bat_cap_mah) \ - (bat_cap_mah * BATTERY_MAX17055_RSENSE / 5) -/* Convert charge termination current in mA to max17055 0x1e reg value */ -#define MAX17055_ICHGTERM_REG(term_cur_ma) \ - (((term_cur_ma * BATTERY_MAX17055_RSENSE) << 4) / 25) -/* - * This macro converts empty voltage target (VE) and recovery voltage (VR) - * in mV to max17055 0x3a reg value. max17055 declares 0% (empty battery) at - * VE. max17055 reenables empty detection when the cell voltage rises above VR. - * VE ranges from 0 to 5110mV, and VR ranges from 0 to 5080mV. - */ -#define MAX17055_VEMPTY_REG(ve_mv, vr_mv) \ - (((ve_mv / 10) << 7) | (vr_mv / 40)) - -#define MAX17055_MAX_MIN_REG(mx, mn) ((((int16_t)(mx)) << 8) | ((mn))) -/* Converts voltages alert range for VALRTTH_REG */ -#define MAX17055_VALRTTH_RESOLUTION 20 -#define MAX17055_VALRTTH_REG(mx, mn) \ - MAX17055_MAX_MIN_REG((uint8_t)(mx / MAX17055_VALRTTH_RESOLUTION), \ - (uint8_t)(mn / MAX17055_VALRTTH_RESOLUTION)) -/* Converts temperature alert range for TALRTTH_REG */ -#define MAX17055_TALRTTH_REG(mx, mn) \ - MAX17055_MAX_MIN_REG((int8_t)(mx), (int8_t)(mn)) -/* Converts state-of-charge alert range for SALRTTH_REG */ -#define MAX17055_SALRTTH_REG(mx, mn) \ - MAX17055_MAX_MIN_REG((uint8_t)(mx), (uint8_t)(mn)) -/* Converts current alert range for IALRTTH_REG */ -/* Current resolution: 0.4mV/RSENSE */ -#define MAX17055_IALRTTH_MUL (10 * BATTERY_MAX17055_RSENSE) -#define MAX17055_IALRTTH_DIV 4 -#define MAX17055_IALRTTH_REG(mx, mn) \ - MAX17055_MAX_MIN_REG( \ - (int8_t)(mx * MAX17055_IALRTTH_MUL / MAX17055_IALRTTH_DIV), \ - (int8_t)(mn * MAX17055_IALRTTH_MUL / MAX17055_IALRTTH_DIV)) - -/* - * max17055 needs some special battery parameters for fuel gauge - * learning algorithm. Maxim can help characterize the battery pack - * to get a full parameter list. We create a data structure to store - * the battery parameters in the format of max17055 register values. - */ -struct max17055_batt_profile { - /* Design capacity of the cell (LSB = 5uVH / Rsense) */ - uint16_t design_cap; - /* Charge termination current (LSB = 1.5625uV / Rsense) */ - uint16_t ichg_term; - /* The combination of empty voltage target and recovery voltage */ - uint16_t v_empty_detect; - - /* - * The parameters below are used for advanced (non-EZ) config - * (dpacc, learn_cfg, tempco, qr_table00, qr_table10, - * qr_table20, and qr_table30) - */ - - /* Change in battery SOC between relaxation points (LSB = pct / 16) */ - uint16_t dpacc; - /* Magic cell tuning parameters */ - uint16_t learn_cfg; - uint16_t rcomp0; - uint16_t tempco; - uint16_t qr_table00; - uint16_t qr_table10; - uint16_t qr_table20; - uint16_t qr_table30; - - /* - * If is_ez_config is nonzero, we only use design_cap, ichg_term, - * and v_empty_detect to config max17055 (a.k.a. EZ-config). - */ - uint8_t is_ez_config; - - /* Used only for full model */ - const uint16_t *ocv_table; -}; - -/* Return the special battery parameters max17055 needs. */ -const struct max17055_batt_profile *max17055_get_batt_profile(void); - -#ifdef CONFIG_BATTERY_MAX17055_ALERT -/* - * max17055 supports alert on voltage, current, state-of-charge, and - * temperature. To enable this feature, the information of the limit range is - * needed. - */ -struct max17055_alert_profile { - /* - * Sets voltage upper and lower limits that generate an alert if - * voltage is outside of the v_alert_mxmn range. - * The upper 8 bits set the maximum value and the lower 8 bits set the - * minimum value. Interrupt threshold limits are selectable with 20mV - * resolution. - * Use MAX17055_VALRTTH_REG(max, min) to setup the desired range, - * VALRT_DISABLE to disable the alert. - */ - const uint16_t v_alert_mxmn; - /* - * Sets temperature upper and lower limits that generate an alert if - * temperature is outside of the t_alert_mxmn range. - * The upper 8 bits set the maximum value and the lower 8 bits set the - * minimum value. Interrupt threshold limits are stored in - * 2’s-complement format with 1°C resolution. - * Use MAX17055_TALRTTH_REG(max, min) to setup the desired range, - * TALRT_DISABLE to disable the alert. - */ - const uint16_t t_alert_mxmn; - /* - * Sets reported state-of-charge upper and lower limits that generate - * an alert if SOC is outside of the s_alert_mxmn range. - * The upper 8 bits set the maximum value and the lower 8 bits set the - * minimum value. Interrupt threshold limits are configurable with 1% - * resolution. - * Use MAX17055_SALRTTH_REG(max, min) to setup the desired range, - * SALRT_DISABLE to disable the alert. - */ - const uint16_t s_alert_mxmn; - /* - * Sets current upper and lower limits that generate an alert if - * current is outside of the i_alert_mxmn range. - * The upper 8 bits set the maximum value and the lower 8 bits set the - * minimum value. Interrupt threshold limits are selectable with - * 0.4mV/R SENSE resolution. - * Use MAX17055_IALRTTH_REG(max, min) to setup the desired range, - * IALRT_DISABLE to disable the alert. - */ - const uint16_t i_alert_mxmn; -}; - -/* - * Return the battery/system's alert threshoulds that max17055 needs. - */ -const struct max17055_alert_profile *max17055_get_alert_profile(void); -#endif /* CONFIG_BATTERY_MAX17055_ALERT */ -#endif /* __CROS_EC_MAX17055_H */ diff --git a/driver/battery/mm8013.c b/driver/battery/mm8013.c deleted file mode 100644 index 04503da2f5..0000000000 --- a/driver/battery/mm8013.c +++ /dev/null @@ -1,250 +0,0 @@ -/* Copyright 2019 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. - * - * Battery driver for MM8013. - */ - -#include "battery.h" -#include "battery_smart.h" -#include "console.h" -#include "i2c.h" -#include "mm8013.h" -#include "timer.h" -#include "util.h" - -#define BATTERY_PACK_INFO_LENGTH 8 - -/* MM8013 requires a 100us wait time after a read operation. */ -#define I2C_WAIT_TIME 100 - -static int mm8013_read16(int offset, int *data) -{ - int rv; - - *data = 0; - rv = i2c_read16(I2C_PORT_BATTERY, MM8013_ADDR_FLAGS, offset, data); - usleep(I2C_WAIT_TIME); - if (rv) - return rv; - return EC_SUCCESS; -} - -static int mm8013_read_block(int offset, uint8_t *data, int len) -{ - int rv; - - rv = i2c_read_block(I2C_PORT_BATTERY, MM8013_ADDR_FLAGS, - offset, data, len); - usleep(I2C_WAIT_TIME); - if (rv) - return rv; - return EC_SUCCESS; -} - -static int battery_flag(int *flag) -{ - return mm8013_read16(REG_FLAGS, flag); -} - -static int battery_current(int *current) -{ - int16_t tmp; - int rv; - - rv = mm8013_read_block(REG_AVERAGE_CURRENT, - (uint8_t *)&tmp, sizeof(int16_t)); - if (rv) - return rv; - *current = tmp; - - return EC_SUCCESS; -} - -int battery_device_name(char *device_name, int buf_size) -{ - int rv; - char out_buf[BATTERY_PACK_INFO_LENGTH + 1]; - - rv = mm8013_read_block(REG_PRODUCT_INFORMATION, - (uint8_t *)out_buf, BATTERY_PACK_INFO_LENGTH); - if (rv) - return rv; - - out_buf[BATTERY_PACK_INFO_LENGTH] = '\0'; - strzcpy(device_name, out_buf, buf_size); - - return EC_SUCCESS; -} - -int battery_state_of_charge_abs(int *percent) -{ - return mm8013_read16(REG_STATE_OF_CHARGE, percent); -} - -int battery_remaining_capacity(int *capacity) -{ - return mm8013_read16(REG_REMAINING_CAPACITY, capacity); -} - -int battery_full_charge_capacity(int *capacity) -{ - return mm8013_read16(REG_FULL_CHARGE_CAPACITY, capacity); -} - -int battery_time_to_empty(int *minutes) -{ - return mm8013_read16(REG_AVERAGE_TIME_TO_EMPTY, minutes); -} - -int battery_time_to_full(int *minutes) -{ - return mm8013_read16(REG_AVERAGE_TIME_TO_FULL, minutes); -} - -int battery_cycle_count(int *count) -{ - return mm8013_read16(REG_CYCLE_COUNT, count); -} - -int battery_design_capacity(int *capacity) -{ - return mm8013_read16(REG_DESIGN_CAPACITY, capacity); -} - -int battery_time_at_rate(int rate, int *minutes) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -int battery_device_chemistry(char *dest, int size) -{ - strzcpy(dest, "<unkn>", size); - - return EC_SUCCESS; -} - -int battery_serial_number(int *serial) -{ - *serial = 0xFFFFFFFF; - return EC_SUCCESS; -} - -int battery_manufacture_date(int *year, int *month, int *day) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -int battery_design_voltage(int *voltage) -{ - *voltage = battery_get_info()->voltage_normal; - - return EC_SUCCESS; -} - -int battery_get_mode(int *mode) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -int battery_status(int *status) -{ - int rv; - int flag = 0; - - *status = 0; - - rv = battery_flag(&flag); - if (rv) - return rv; - - if (flag & (MM8013_FLAG_OTC | MM8013_FLAG_OTD)) - *status |= STATUS_OVERTEMP_ALARM; - if (flag & MM8013_FLAG_FC) - *status |= STATUS_FULLY_CHARGED; - if (flag & MM8013_FLAG_DSG) - *status |= STATUS_DISCHARGING; - if (flag & MM8013_FLAG_BATHI) - *status |= STATUS_OVERCHARGED_ALARM; - - return EC_SUCCESS; -} - -enum battery_present battery_is_present(void) -{ - int temp; - - if (mm8013_read16(REG_TEMPERATURE, &temp)) - return BP_NO; - return BP_YES; -} - -void battery_get_params(struct batt_params *batt) -{ - struct batt_params batt_new = {0}; - int flag = 0; - - /* - * Assuming the battery is responsive as long as - * mm8013 finds battery is present. - */ - batt_new.is_present = battery_is_present(); - - if (batt_new.is_present == BP_YES) - batt_new.flags |= BATT_FLAG_RESPONSIVE; - else if (batt_new.is_present == BP_NO) - /* Battery is not present, gauge won't report useful info. */ - goto batt_out; - - if (mm8013_read16(REG_TEMPERATURE, &batt_new.temperature)) - batt_new.flags |= BATT_FLAG_BAD_TEMPERATURE; - - if (mm8013_read16(REG_STATE_OF_CHARGE, &batt_new.state_of_charge)) - batt_new.flags |= BATT_FLAG_BAD_STATE_OF_CHARGE; - - if (mm8013_read16(REG_VOLTAGE, &batt_new.voltage)) - batt_new.flags |= BATT_FLAG_BAD_VOLTAGE; - - if (battery_current(&batt_new.current)) - batt_new.flags |= BATT_FLAG_BAD_CURRENT; - - batt_new.desired_voltage = battery_get_info()->voltage_max; - batt_new.desired_current = BATTERY_DESIRED_CHARGING_CURRENT; - - if (battery_remaining_capacity(&batt_new.remaining_capacity)) - batt_new.flags |= BATT_FLAG_BAD_REMAINING_CAPACITY; - - if (battery_full_charge_capacity(&batt_new.full_capacity)) - batt_new.flags |= BATT_FLAG_BAD_FULL_CAPACITY; - - if (battery_status(&batt_new.status)) - batt_new.flags |= BATT_FLAG_BAD_STATUS; - - if (!battery_flag(&flag) && (flag & MM8013_FLAG_CHG)) - batt_new.flags |= BATT_FLAG_WANT_CHARGE; - -batt_out: - /* Update visible battery parameters */ - memcpy(batt, &batt_new, sizeof(*batt)); -} - -#ifdef CONFIG_CMD_PWR_AVG -int battery_get_avg_current(void) -{ - /* TODO(crbug.com/752320) implement this */ - return -EC_ERROR_UNIMPLEMENTED; -} - -int battery_get_avg_voltage(void) -{ - /* TODO(crbug.com/752320) implement this */ - return -EC_ERROR_UNIMPLEMENTED; -} -#endif /* CONFIG_CMD_PWR_AVG */ - -/* Wait until battery is totally stable. */ -int battery_wait_for_stable(void) -{ - /* TODO(phoenixshen): Implement this function. */ - return EC_SUCCESS; -} diff --git a/driver/battery/mm8013.h b/driver/battery/mm8013.h deleted file mode 100644 index 2ffaca7b5d..0000000000 --- a/driver/battery/mm8013.h +++ /dev/null @@ -1,40 +0,0 @@ -/* Copyright 2019 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. - * - * Battery driver for MM8013. - */ - -#ifndef __CROS_EC_MM8013_H -#define __CROS_EC_MM8013_H - -#define MM8013_ADDR_FLAGS 0x55 - -#define REG_TEMPERATURE 0x06 -#define REG_VOLTAGE 0x08 -#define REG_FLAGS 0x0a -#define REG_FULL_CHARGE_CAPACITY 0x0e -#define REG_REMAINING_CAPACITY 0x10 -#define REG_AVERAGE_CURRENT 0x14 -#define REG_AVERAGE_TIME_TO_EMPTY 0x16 -#define REG_AVERAGE_TIME_TO_FULL 0x18 -#define REG_STATE_OF_CHARGE 0x2c -#define REG_CYCLE_COUNT 0x2a -#define REG_DESIGN_CAPACITY 0x3c -#define REG_PRODUCT_INFORMATION 0x64 - -/* Over Temperature in charge */ -#define MM8013_FLAG_OTC BIT(15) -/* Over Temperature in discharge */ -#define MM8013_FLAG_OTD BIT(14) -/* Over-charge */ -#define MM8013_FLAG_BATHI BIT(13) -/* Full Charge */ -#define MM8013_FLAG_FC BIT(9) -/* Charge allowed */ -#define MM8013_FLAG_CHG BIT(8) -/* Discharge */ -#define MM8013_FLAG_DSG BIT(0) - - -#endif /* __CROS_EC_MM8013_H */ diff --git a/driver/battery/smart.c b/driver/battery/smart.c deleted file mode 100644 index 3704618e36..0000000000 --- a/driver/battery/smart.c +++ /dev/null @@ -1,695 +0,0 @@ -/* Copyright 2012 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. - * - * Smart battery driver. - */ - -#include "battery.h" -#include "battery_smart.h" -#include "console.h" -#include "host_command.h" -#include "i2c.h" -#include "timer.h" -#include "util.h" - -/* Console output macros */ -#define CPUTS(outstr) cputs(CC_CHARGER, outstr); -#define CPRINTS(format, args...) cprints(CC_CHARGER, format, ## args) - -#define BATTERY_NO_RESPONSE_TIMEOUT (1000*MSEC) - -static int fake_state_of_charge = -1; -static int fake_temperature = -1; - -static int battery_supports_pec(void) -{ - static int supports_pec = -1; - - if (!IS_ENABLED(CONFIG_SMBUS_PEC)) - return 0; - - if (supports_pec < 0) { - int spec_info; - int rv = i2c_read16(I2C_PORT_BATTERY, BATTERY_ADDR_FLAGS, - SB_SPECIFICATION_INFO, &spec_info); - /* failed, assuming not support and try again later */ - if (rv) - return 0; - - supports_pec = (BATTERY_SPEC_VERSION(spec_info) == - BATTERY_SPEC_VER_1_1_WITH_PEC); - CPRINTS("battery supports pec: %d", supports_pec); - } - return supports_pec; -} - -test_mockable int sb_read(int cmd, int *param) -{ - uint16_t addr_flags = BATTERY_ADDR_FLAGS; - -#ifdef CONFIG_BATTERY_CUT_OFF - /* - * Some batteries would wake up after cut-off if we talk to it. - */ - if (battery_is_cut_off()) - return EC_RES_ACCESS_DENIED; -#endif - if (battery_supports_pec()) - addr_flags |= I2C_FLAG_PEC; - - return i2c_read16(I2C_PORT_BATTERY, addr_flags, cmd, param); -} - -test_mockable int sb_write(int cmd, int param) -{ - uint16_t addr_flags = BATTERY_ADDR_FLAGS; - -#ifdef CONFIG_BATTERY_CUT_OFF - /* - * Some batteries would wake up after cut-off if we talk to it. - */ - if (battery_is_cut_off()) - return EC_RES_ACCESS_DENIED; -#endif - if (battery_supports_pec()) - addr_flags |= I2C_FLAG_PEC; - - return i2c_write16(I2C_PORT_BATTERY, addr_flags, cmd, param); -} - -int sb_read_string(int offset, uint8_t *data, int len) -{ - uint16_t addr_flags = BATTERY_ADDR_FLAGS; - -#ifdef CONFIG_BATTERY_CUT_OFF - /* - * Some batteries would wake up after cut-off if we talk to it. - */ - if (battery_is_cut_off()) - return EC_RES_ACCESS_DENIED; -#endif - if (battery_supports_pec()) - addr_flags |= I2C_FLAG_PEC; - - return i2c_read_string(I2C_PORT_BATTERY, addr_flags, offset, data, len); -} - -int sb_read_mfgacc(int cmd, int block, uint8_t *data, int len) -{ - int rv; - - /* - * First two bytes returned from read are command sent hence read - * doesn't yield anything if the length is less than 3 bytes. - */ - if (len < 3) - return EC_ERROR_INVAL; - - /* Send manufacturer access command */ - rv = sb_write(SB_MANUFACTURER_ACCESS, cmd); - if (rv) - return rv; - - /* - * Read data on the register block. - * First two bytes returned are command sent, - * rest are actual data LSB to MSB. - */ - rv = sb_read_string(block, data, len); - if (rv) - return rv; - if ((data[0] | data[1] << 8) != cmd) - return EC_ERROR_UNKNOWN; - - return EC_SUCCESS; -} - -int sb_write_block(int reg, const uint8_t *val, int len) -{ - uint16_t addr_flags = BATTERY_ADDR_FLAGS; - -#ifdef CONFIG_BATTERY_CUT_OFF - /* - * Some batteries would wake up after cut-off if we talk to it. - */ - if (battery_is_cut_off()) - return EC_RES_ACCESS_DENIED; -#endif - - if (battery_supports_pec()) - addr_flags |= I2C_FLAG_PEC; - - /* TODO: implement smbus_write_block. */ - return i2c_write_block(I2C_PORT_BATTERY, addr_flags, reg, val, len); -} - -int battery_get_mode(int *mode) -{ - return sb_read(SB_BATTERY_MODE, mode); -} - -/** - * Force battery to mAh mode (instead of 10mW mode) for reporting capacity. - * - * @return non-zero if error. - */ - -static int battery_force_mah_mode(void) -{ - int val, rv; - rv = battery_get_mode(&val); - if (rv) - return rv; - - if (val & MODE_CAPACITY) - rv = sb_write(SB_BATTERY_MODE, val & ~MODE_CAPACITY); - - return rv; -} - -int battery_state_of_charge_abs(int *percent) -{ - return sb_read(SB_ABSOLUTE_STATE_OF_CHARGE, percent); -} - -int battery_remaining_capacity(int *capacity) -{ - int rv = battery_force_mah_mode(); - if (rv) - return rv; - - return sb_read(SB_REMAINING_CAPACITY, capacity); -} - -int battery_full_charge_capacity(int *capacity) -{ - int rv = battery_force_mah_mode(); - if (rv) - return rv; - - return sb_read(SB_FULL_CHARGE_CAPACITY, capacity); -} - -int battery_time_to_empty(int *minutes) -{ - return sb_read(SB_AVERAGE_TIME_TO_EMPTY, minutes); -} - -int battery_run_time_to_empty(int *minutes) -{ - return sb_read(SB_RUN_TIME_TO_EMPTY, minutes); -} - -int battery_time_to_full(int *minutes) -{ - return sb_read(SB_AVERAGE_TIME_TO_FULL, minutes); -} - -/* Read battery status */ -int battery_status(int *status) -{ - return sb_read(SB_BATTERY_STATUS, status); -} - -/* Battery charge cycle count */ -int battery_cycle_count(int *count) -{ - return sb_read(SB_CYCLE_COUNT, count); -} - -int battery_design_capacity(int *capacity) -{ - int rv = battery_force_mah_mode(); - if (rv) - return rv; - - return sb_read(SB_DESIGN_CAPACITY, capacity); -} - -/* Designed battery output voltage - * unit: mV - */ -int battery_design_voltage(int *voltage) -{ - return sb_read(SB_DESIGN_VOLTAGE, voltage); -} - -/* Read serial number */ -int battery_serial_number(int *serial) -{ - return sb_read(SB_SERIAL_NUMBER, serial); -} - -test_mockable int battery_time_at_rate(int rate, int *minutes) -{ - int rv; - int ok, time; - int loop, cmd, output_sign; - - if (rate == 0) { - *minutes = 0; - return EC_ERROR_INVAL; - } - - rv = sb_write(SB_AT_RATE, rate); - if (rv) - return rv; - loop = 5; - while (loop--) { - rv = sb_read(SB_AT_RATE_OK, &ok); - if (rv) - return rv; - if (ok) { - if (rate > 0) { - cmd = SB_AT_RATE_TIME_TO_FULL; - output_sign = -1; - } else { - cmd = SB_AT_RATE_TIME_TO_EMPTY; - output_sign = 1; - } - rv = sb_read(cmd, &time); - if (rv) - return rv; - - *minutes = (time == 0xffff) ? 0 : output_sign * time; - return EC_SUCCESS; - } else { - /* wait 10ms for AT_RATE_OK */ - msleep(10); - } - } - return EC_ERROR_TIMEOUT; -} - -test_mockable int battery_manufacture_date(int *year, int *month, int *day) -{ - int rv; - int ymd; - - rv = sb_read(SB_MANUFACTURE_DATE, &ymd); - if (rv) - return rv; - - /* battery date format: - * ymd = day + month * 32 + (year - 1980) * 512 - */ - *year = ((ymd & MANUFACTURE_DATE_YEAR_MASK) >> - MANUFACTURE_DATE_YEAR_SHIFT) + MANUFACTURE_DATE_YEAR_OFFSET; - *month = (ymd & MANUFACTURE_DATE_MONTH_MASK) >> - MANUFACTURE_DATE_MONTH_SHIFT; - *day = (ymd & MANUFACTURE_DATE_DAY_MASK) >> - MANUFACTURE_DATE_DAY_SHIFT; - - return EC_SUCCESS; -} - -int get_battery_manufacturer_name(char *dest, int size) -{ - return sb_read_string(SB_MANUFACTURER_NAME, dest, size); -} - -/* Read device name */ -test_mockable int battery_device_name(char *dest, int size) -{ - return sb_read_string(SB_DEVICE_NAME, dest, size); -} - -/* Read battery type/chemistry */ -test_mockable int battery_device_chemistry(char *dest, int size) -{ - return sb_read_string(SB_DEVICE_CHEMISTRY, dest, size); -} - -int battery_get_avg_current(void) -{ - int current; - - /* This is a signed 16-bit value. */ - sb_read(SB_AVERAGE_CURRENT, ¤t); - return (int16_t)current; -} - -#ifdef CONFIG_CMD_PWR_AVG -/* - * Technically returns only the instantaneous reading, but tests showed that - * for the majority of charge states above 3% this varies by less than 40mV - * every minute, so we accept the inaccuracy here. - */ -int battery_get_avg_voltage(void) -{ - int voltage = -EC_ERROR_UNKNOWN; - - sb_read(SB_VOLTAGE, &voltage); - return voltage; -} -#endif /* CONFIG_CMD_PWR_AVG */ - -static void apply_fake_state_of_charge(struct batt_params *batt) -{ - int full; - - if (fake_state_of_charge < 0) - return; - - if (batt->flags & BATT_FLAG_BAD_FULL_CAPACITY) - battery_design_capacity(&full); - else - full = batt->full_capacity; - - batt->state_of_charge = fake_state_of_charge; - batt->remaining_capacity = full * fake_state_of_charge / 100; - battery_compensate_params(batt); - batt->flags &= ~BATT_FLAG_BAD_STATE_OF_CHARGE; - batt->flags &= ~BATT_FLAG_BAD_REMAINING_CAPACITY; -} - -void battery_get_params(struct batt_params *batt) -{ - struct batt_params batt_new = {0}; - int v; - - if (sb_read(SB_TEMPERATURE, &batt_new.temperature) - && fake_temperature < 0) - batt_new.flags |= BATT_FLAG_BAD_TEMPERATURE; - - /* If temperature is faked, override with faked data */ - if (fake_temperature >= 0) - batt_new.temperature = fake_temperature; - - if (sb_read(SB_RELATIVE_STATE_OF_CHARGE, &batt_new.state_of_charge) - && fake_state_of_charge < 0) - batt_new.flags |= BATT_FLAG_BAD_STATE_OF_CHARGE; - - if (sb_read(SB_VOLTAGE, &batt_new.voltage)) - batt_new.flags |= BATT_FLAG_BAD_VOLTAGE; - - /* This is a signed 16-bit value. */ - if (sb_read(SB_CURRENT, &v)) - batt_new.flags |= BATT_FLAG_BAD_CURRENT; - else - batt_new.current = (int16_t)v; - - if (sb_read(SB_AVERAGE_CURRENT, &v)) - batt_new.flags |= BATT_FLAG_BAD_AVERAGE_CURRENT; - if (sb_read(SB_CHARGING_VOLTAGE, &batt_new.desired_voltage)) - batt_new.flags |= BATT_FLAG_BAD_DESIRED_VOLTAGE; - - if (sb_read(SB_CHARGING_CURRENT, &batt_new.desired_current)) - batt_new.flags |= BATT_FLAG_BAD_DESIRED_CURRENT; - - if (battery_remaining_capacity(&batt_new.remaining_capacity)) - batt_new.flags |= BATT_FLAG_BAD_REMAINING_CAPACITY; - - if (battery_full_charge_capacity(&batt_new.full_capacity)) - batt_new.flags |= BATT_FLAG_BAD_FULL_CAPACITY; - - if (battery_status(&batt_new.status)) - batt_new.flags |= BATT_FLAG_BAD_STATUS; - - /* If any of those reads worked, the battery is responsive */ - if ((batt_new.flags & BATT_FLAG_BAD_ANY) != BATT_FLAG_BAD_ANY) - batt_new.flags |= BATT_FLAG_RESPONSIVE; - -#ifdef CONFIG_BATTERY_MEASURE_IMBALANCE - if (battery_imbalance_mv() > CONFIG_BATTERY_MAX_IMBALANCE_MV) - batt_new.flags |= BATT_FLAG_IMBALANCED_CELL; -#endif - -#if defined(CONFIG_BATTERY_PRESENT_CUSTOM) || \ - defined(CONFIG_BATTERY_PRESENT_GPIO) - /* Hardware can tell us for certain */ - batt_new.is_present = battery_is_present(); -#else - /* No hardware test, so we only know it's there if it responds */ - if (batt_new.flags & BATT_FLAG_RESPONSIVE) - batt_new.is_present = BP_YES; - else - batt_new.is_present = BP_NOT_SURE; -#endif - - /* - * Charging allowed if both desired voltage and current are nonzero - * and battery isn't full (and we read them all correctly). - */ - if (!(batt_new.flags & (BATT_FLAG_BAD_DESIRED_VOLTAGE | - BATT_FLAG_BAD_DESIRED_CURRENT | - BATT_FLAG_BAD_STATE_OF_CHARGE)) && -#ifdef CONFIG_BATTERY_REQUESTS_NIL_WHEN_DEAD - /* - * TODO (crosbug.com/p/29467): remove this workaround - * for dead battery that requests no voltage/current - */ - ((batt_new.desired_voltage && - batt_new.desired_current && - batt_new.state_of_charge < BATTERY_LEVEL_FULL) || - (batt_new.desired_voltage == 0 && - batt_new.desired_current == 0 && - batt_new.state_of_charge == 0))) -#else - batt_new.desired_voltage && - batt_new.desired_current && - batt_new.state_of_charge < BATTERY_LEVEL_FULL) -#endif - batt_new.flags |= BATT_FLAG_WANT_CHARGE; - else - /* Force both to zero */ - batt_new.desired_voltage = batt_new.desired_current = 0; - -#ifdef HAS_TASK_HOSTCMD - /* if there is no host, we don't care about compensation */ - battery_compensate_params(&batt_new); - board_battery_compensate_params(&batt_new); -#endif - - if (IS_ENABLED(CONFIG_CMD_BATTFAKE)) - apply_fake_state_of_charge(&batt_new); - - /* Update visible battery parameters */ - memcpy(batt, &batt_new, sizeof(*batt)); -} - -/* Wait until battery is totally stable */ -int battery_wait_for_stable(void) -{ - int status; - uint64_t wait_timeout = get_time().val + BATTERY_NO_RESPONSE_TIMEOUT; - - CPRINTS("Wait for battery stabilized during %d", - BATTERY_NO_RESPONSE_TIMEOUT); - while (get_time().val < wait_timeout) { - /* Starting pinging battery */ - if (battery_status(&status) == EC_SUCCESS) { - /* Battery is stable */ - CPRINTS("battery responded with status %x", status); - return EC_SUCCESS; - } - msleep(25); /* clock stretching could hold 25ms */ - } - CPRINTS("battery not responding"); - return EC_ERROR_NOT_POWERED; -} - -#if defined(CONFIG_CMD_BATTFAKE) -static int command_battfake(int argc, char **argv) -{ - char *e; - int v; - - if (argc == 2) { - v = strtoi(argv[1], &e, 0); - if (*e || v < -1 || v > 100) - return EC_ERROR_PARAM1; - - fake_state_of_charge = v; - } - - if (fake_state_of_charge >= 0) - ccprintf("Fake batt %d%%\n", fake_state_of_charge); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(battfake, command_battfake, - "percent (-1 = use real level)", - "Set fake battery level"); - -static int command_batttempfake(int argc, char **argv) -{ - char *e; - int t; - - if (argc == 2) { - t = strtoi(argv[1], &e, 0); - if (*e || t < -1 || t > 5000) - return EC_ERROR_PARAM1; - - fake_temperature = t; - } - - if (fake_temperature >= 0) - ccprintf("Fake batt temperature %d.%d K\n", - fake_temperature / 10, fake_temperature % 10); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(batttempfake, command_batttempfake, - "temperature (-1 = use real temperature)", - "Set fake battery temperature in deciKelvin (2731 = 273.1 K = 0 deg C)"); -#endif - -#ifdef CONFIG_CMD_BATT_MFG_ACCESS -static int command_batt_mfg_access_read(int argc, char **argv) -{ - char *e; - uint8_t data[32]; - int cmd, block, len = 6; - int rv; - - if (argc < 3 || argc > 4) - return EC_ERROR_PARAM_COUNT; - - cmd = strtoi(argv[1], &e, 0); - if (*e || cmd < 0) - return EC_ERROR_PARAM1; - - block = strtoi(argv[2], &e, 0); - if (*e || block < 0) - return EC_ERROR_PARAM2; - - if (argc > 3) { - len = strtoi(argv[3], &e, 0); - len += 2; - if (*e || len < 3 || len > sizeof(data)) - return EC_ERROR_PARAM3; - } - - rv = sb_read_mfgacc(cmd, block, data, len); - if (rv) - return rv; - - ccprintf("data[MSB->LSB]=0x"); - do { - len--; - ccprintf("%02x ", data[len]); - } while (len > 2); - ccprintf("\n"); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(battmfgacc, command_batt_mfg_access_read, - "cmd block | len", - "Read battery manufacture access data"); -#endif /* CONFIG_CMD_BATT_MFG_ACCESS */ - -/*****************************************************************************/ -/* Smart battery pass-through - */ -#ifdef CONFIG_SB_PASSTHROUGH -static enum ec_status -host_command_sb_read_word(struct host_cmd_handler_args *args) -{ - int rv; - int val; - const struct ec_params_sb_rd *p = args->params; - struct ec_response_sb_rd_word *r = args->response; - - if (p->reg > 0x1c) - return EC_RES_INVALID_PARAM; - rv = sb_read(p->reg, &val); - if (rv) - return EC_RES_ERROR; - - r->value = val; - args->response_size = sizeof(struct ec_response_sb_rd_word); - - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_SB_READ_WORD, - host_command_sb_read_word, - EC_VER_MASK(0)); - -static enum ec_status -host_command_sb_write_word(struct host_cmd_handler_args *args) -{ - int rv; - const struct ec_params_sb_wr_word *p = args->params; - - if (p->reg > 0x1c) - return EC_RES_INVALID_PARAM; - rv = sb_write(p->reg, p->value); - if (rv) - return EC_RES_ERROR; - - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_SB_WRITE_WORD, - host_command_sb_write_word, - EC_VER_MASK(0)); - -static enum ec_status -host_command_sb_read_block(struct host_cmd_handler_args *args) -{ - int rv; - const struct ec_params_sb_rd *p = args->params; - struct ec_response_sb_rd_block *r = args->response; - - if ((p->reg != SB_MANUFACTURER_NAME) && - (p->reg != SB_DEVICE_NAME) && - (p->reg != SB_DEVICE_CHEMISTRY) && - (p->reg != SB_MANUFACTURER_DATA)) - return EC_RES_INVALID_PARAM; - rv = sb_read_string(p->reg, r->data, 32); - if (rv) - return EC_RES_ERROR; - - args->response_size = sizeof(struct ec_response_sb_rd_block); - - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_SB_READ_BLOCK, - host_command_sb_read_block, - EC_VER_MASK(0)); - -static enum ec_status -host_command_sb_write_block(struct host_cmd_handler_args *args) -{ - /* Not implemented */ - return EC_RES_INVALID_COMMAND; -} -DECLARE_HOST_COMMAND(EC_CMD_SB_WRITE_BLOCK, - host_command_sb_write_block, - EC_VER_MASK(0)); -#endif - -#ifdef CONFIG_CMD_I2C_STRESS_TEST_BATTERY -test_mockable int sb_i2c_test_read(int cmd, int *param) -{ - char chemistry[sizeof(CONFIG_BATTERY_DEVICE_CHEMISTRY) + 1]; - int rv; - - if (cmd == SB_DEVICE_CHEMISTRY) { - rv = battery_device_chemistry(chemistry, - sizeof(CONFIG_BATTERY_DEVICE_CHEMISTRY)); - if (rv) - return rv; - if (strcasecmp(chemistry, CONFIG_BATTERY_DEVICE_CHEMISTRY)) - return EC_ERROR_UNKNOWN; - - *param = EC_SUCCESS; - return EC_SUCCESS; - } - - - return sb_read(cmd, param); -} - -struct i2c_stress_test_dev battery_i2c_stress_test_dev = { - .reg_info = { - .read_reg = SB_DEVICE_CHEMISTRY, - .read_val = EC_SUCCESS, - .write_reg = SB_AT_RATE, - }, - .i2c_read_dev = &sb_i2c_test_read, - .i2c_write_dev = &sb_write, -}; -#endif /* CONFIG_CMD_I2C_STRESS_TEST_BATTERY */ diff --git a/driver/bc12/max14637.c b/driver/bc12/max14637.c deleted file mode 100644 index b2e734e1c0..0000000000 --- a/driver/bc12/max14637.c +++ /dev/null @@ -1,254 +0,0 @@ -/* Copyright 2017 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. - */ - -/* - * MAX14637 USB BC 1.2 Charger Detector driver. - * - * NOTE: The driver assumes that CHG_AL_N and SW_OPEN are not connected, - * therefore the value of CHG_DET indicates whether the source is NOT a - * low-power standard downstream port (SDP). In order to use higher currents, - * the system will have to charge ramp. - */ - -#include "max14637.h" -#include "charge_manager.h" -#include "chipset.h" -#include "common.h" -#include "console.h" -#include "gpio.h" -#include "hooks.h" -#include "power.h" -#include "power/cannonlake.h" -#include "task.h" -#include "tcpm/tcpm.h" -#include "timer.h" -#include "usb_charge.h" -#include "usb_pd.h" -#include "util.h" - -#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) - -#if defined(CONFIG_CHARGE_RAMP_SW) || defined(CONFIG_CHARGE_RAMP_HW) -/** - * Returns true if the charger detect pin is activated. - * - * @parm cfg driver for chip to read the charger detect pin for. - * @return 1 if charger detect is activated (high when active high or - * low with active low), otherwise 0. - */ -static int is_chg_det_activated(const struct max14637_config_t * const cfg) -{ - return !!gpio_get_level(cfg->chg_det_pin) ^ - !!(cfg->flags & MAX14637_FLAGS_CHG_DET_ACTIVE_LOW); -} -#endif - -/** - * Activates the Chip Enable GPIO based on the enabled value. - * - * @param cfg driver for chip that will set chip enable gpio. - * @param enable 1 to activate gpio (high for active high and low for active - * low). - */ -static void activate_chip_enable( - const struct max14637_config_t * const cfg, const int enable) -{ - gpio_set_level( - cfg->chip_enable_pin, - !!enable ^ !!(cfg->flags & MAX14637_FLAGS_ENABLE_ACTIVE_LOW)); -} - -/** - * Update BC1.2 detected status to charge manager. - * - * @param port: The Type-C port where VBUS is present. - */ -static void update_bc12_status_to_charger_manager(const int port) -{ - const struct max14637_config_t * const cfg = &max14637_config[port]; - struct charge_port_info new_chg; - - new_chg.voltage = USB_CHARGER_VOLTAGE_MV; -#if defined(CONFIG_CHARGE_RAMP_SW) || defined(CONFIG_CHARGE_RAMP_HW) - /* - * The driver assumes that CHG_AL_N and SW_OPEN are not connected, - * therefore an activated CHG_DET indicates whether the source is NOT a - * low-power standard downstream port (SDP). The system will have to - * ramp the current to determine the limit. The Type-C spec prohibits - * proprietary methods now, therefore 1500mA is the max. - */ - new_chg.current = is_chg_det_activated(cfg) ? USB_CHARGER_MAX_CURR_MA : - 500; -#else - /* - * If the board doesn't support charge ramping, then assume the lowest - * denominator; that is assume the charger detected is a weak dedicated - * charging port (DCP) which can only supply 500mA. - */ - new_chg.current = 500; -#endif /* !defined(CONFIG_CHARGE_RAMP_SW && CONFIG_CHARGE_RAMP_HW) */ - - charge_manager_update_charge(CHARGE_SUPPLIER_OTHER, port, &new_chg); -} - -/** - * Perform BC1.2 detection. - * - * @param port: The Type-C port where VBUS is present. - */ -static void bc12_detect(const int port) -{ - const struct max14637_config_t * const cfg = &max14637_config[port]; - - /* - * Enable the IC to begin detection and connect switches if - * necessary. This is only necessary if the port power role is a - * sink. If the power role is a source then just keep the max14637 - * powered on so that data switches are close. Note that the gpio enable - * for this chip is active by default. In order to trigger bc1.2 - * detection, the chip enable must be driven low, then high again so the - * chip will start bc1.2 client side detection. Add a 100 msec delay to - * avoid collision with a device that might be doing bc1.2 client side - * detection. - */ - msleep(100); - activate_chip_enable(cfg, 0); - msleep(CONFIG_BC12_MAX14637_DELAY_FROM_OFF_TO_ON_MS); - activate_chip_enable(cfg, 1); - -#if defined(CONFIG_CHARGE_RAMP_SW) || defined(CONFIG_CHARGE_RAMP_HW) - /* - * Apple or TomTom charger detection can take as long as 600ms. Wait a - * little bit longer for margin. - */ - msleep(630); -#endif /* !defined(CONFIG_CHARGE_RAMP_SW && CONFIG_CHARGE_RAMP_HW) */ -} - -/** - * If VBUS is present and port power role is sink, then trigger bc1.2 client - * detection. If VBUS is not present then update charge manager. Note that both - * chip_enable and VBUS must be active for the IC to be powered up. Chip enable - * is kept enabled by default so that bc1.2 client detection is not triggered - * when the port power role is source. - * - * @param port: Which USB Type-C port to examine. - */ -static void detect_or_power_down_ic(const int port) -{ - int vbus_present; - -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - vbus_present = tcpm_check_vbus_level(port, VBUS_PRESENT); -#else - vbus_present = pd_snk_is_vbus_provided(port); -#endif /* !defined(CONFIG_USB_PD_VBUS_DETECT_TCPC) */ - - if (vbus_present) { -#if defined(CONFIG_POWER_PP5000_CONTROL) && defined(HAS_TASK_CHIPSET) - /* Turn on the 5V rail to allow the chip to be powered. */ - power_5v_enable(task_get_current(), 1); -#endif - if (pd_get_power_role(port) == PD_ROLE_SINK) { - bc12_detect(port); - update_bc12_status_to_charger_manager(port); - } - } else { - /* Let charge manager know there's no more charge available. */ - charge_manager_update_charge(CHARGE_SUPPLIER_OTHER, port, NULL); - /* - * If latest attached charger is PD Adapter then it would be - * detected as DCP and data switch of USB2.0 would be open which - * prevents USB 2.0 data path from working later. As a result, - * bc12_detect() is called again here and SCP would be detected - * due to D+/D- are NC (open) if nothing is attached then data - * switch of USB2.0 can be kept close from now on. - */ - bc12_detect(port); -#if defined(CONFIG_POWER_PP5000_CONTROL) && defined(HAS_TASK_CHIPSET) - /* Issue a request to turn off the rail. */ - power_5v_enable(task_get_current(), 0); -#endif - } -} - -static void max14637_usb_charger_task(const int port) -{ - uint32_t evt; - const struct max14637_config_t * const cfg = &max14637_config[port]; - - ASSERT(port >= 0 && port < CONFIG_USB_PD_PORT_MAX_COUNT); - /* - * Have chip enable active as default state so data switches are closed - * and bc1.2 client side detection is not activated when the port power - * role is a source. - */ - activate_chip_enable(cfg, 1); - /* Check whether bc1.2 client mode detection needs to be triggered */ - detect_or_power_down_ic(port); - - while (1) { - evt = task_wait_event(-1); - - if (evt & USB_CHG_EVENT_VBUS) - detect_or_power_down_ic(port); - } -} - -#if defined(CONFIG_CHARGE_RAMP_SW) || defined(CONFIG_CHARGE_RAMP_HW) -static int max14637_ramp_allowed(int supplier) -{ - /* - * Due to the limitations in the application of the MAX14637, we - * don't quite know exactly what we're plugged into. Therefore, - * the supplier type will be CHARGE_SUPPLIER_OTHER. - */ - return supplier == CHARGE_SUPPLIER_OTHER; -} - -static int max14637_ramp_max(int supplier, int sup_curr) -{ - /* Use the current limit that was decided by the MAX14637. */ - if (supplier == CHARGE_SUPPLIER_OTHER) - return sup_curr; - else - return 500; -} -#endif /* CONFIG_CHARGE_RAMP_SW || CONFIG_CHARGE_RAMP_HW */ - -/* Called on AP S5 -> S3 and S3/S0iX -> S0 transition */ -static void bc12_chipset_startup(void) -{ - int port; - - /* - * For each port, trigger a new USB_CHG_EVENT_VBUS event to handle cases - * where there was no change in VBUS following an AP resume/startup - * event. If a legacy charger is connected to the port, then VBUS will - * not drop even during the USB PD hard reset. - */ - for (port = 0; port < CONFIG_USB_PD_PORT_MAX_COUNT; port++) - task_set_event(USB_CHG_PORT_TO_TASK_ID(port), - USB_CHG_EVENT_VBUS); -} -DECLARE_HOOK(HOOK_CHIPSET_STARTUP, bc12_chipset_startup, HOOK_PRIO_DEFAULT); -DECLARE_HOOK(HOOK_CHIPSET_RESUME, bc12_chipset_startup, HOOK_PRIO_DEFAULT); - -const struct bc12_drv max14637_drv = { - .usb_charger_task = max14637_usb_charger_task, -#if defined(CONFIG_CHARGE_RAMP_SW) || defined(CONFIG_CHARGE_RAMP_HW) - .ramp_allowed = max14637_ramp_allowed, - .ramp_max = max14637_ramp_max, -#endif /* CONFIG_CHARGE_RAMP_SW || CONFIG_CHARGE_RAMP_HW */ -}; - -#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 = &max14637_drv, - }, -}; -#endif /* CONFIG_BC12_SINGLE_DRIVER */ diff --git a/driver/bc12/max14637.h b/driver/bc12/max14637.h deleted file mode 100644 index 2b18bc222b..0000000000 --- a/driver/bc12/max14637.h +++ /dev/null @@ -1,33 +0,0 @@ -/* Copyright 2018 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. - */ - -/* MAX14637 USB BC 1.2 Charger Detector driver definitions */ - -#include "gpio.h" - -#define MAX14637_FLAGS_ENABLE_ACTIVE_LOW BIT(0) -#define MAX14637_FLAGS_CHG_DET_ACTIVE_LOW BIT(1) - -struct max14637_config_t { - /* - * Enable signal to BC 1.2. Can be active high or low depending on - * MAX14637_FLAGS_ENABLE_ACTIVE_LOW flag bit. - */ - enum gpio_signal chip_enable_pin; - /* - * Charger detect signal from BC 1.2 chip. Can be active high or low - * depending on MAX14637_FLAGS_CHG_DET_ACTIVE_LOW flag bit. - */ - enum gpio_signal chg_det_pin; - /* Configuration flags with prefix MAX14637_FLAGS. */ - int flags; -}; - -/* - * Array that contains boards-specific configuration for BC 1.2 charging chips. - */ -extern const struct max14637_config_t - max14637_config[CONFIG_USB_PD_PORT_MAX_COUNT]; -extern const struct bc12_drv max14637_drv; 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 */ diff --git a/driver/bc12/mt6360.h b/driver/bc12/mt6360.h deleted file mode 100644 index e23a2623ed..0000000000 --- a/driver/bc12/mt6360.h +++ /dev/null @@ -1,91 +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. - */ - -#ifndef __CROS_EC_MT6360_H - -#include "bc12/mt6360_public.h" - -#define MT6360_IRQ_MASK 0x0C - -#define MT6360_REG_DEVICE_TYPE 0x22 -#define MT6360_MASK_USBCHGEN BIT(7) - -#define MT6360_REG_USB_STATUS_1 0x27 -#define MT6360_MASK_USB_STATUS 0x70 -#define MT6360_MASK_SDP 0x20 -#define MT6360_MASK_DCP 0x40 -#define MT6360_MASK_CDP 0x50 - -#define MT6360_REG_RGB_EN 0x80 -#define MT6360_MASK_ISINK_EN(x) BIT(7 - (x)) -#define MT6360_ISINK1_CHRIND_EN_SEL BIT(3) - -#define MT6360_REG_RGB_ISINK(x) (0x81 + (x)) -#define MT6360_MASK_CUR_SEL 0xF - -#define MT6360_REG_DPDMIRQ 0xD6 -#define MT6360_MASK_DPDMIRQ_ATTACH BIT(0) -#define MT6360_MASK_DPDMIRQ_DETACH BIT(1) - -#define MT6360_REG_DPDM_MASK1 0xF6 -#define MT6360_REG_DPDM_MASK1_CHGDET_DONEI_M BIT(0) - -#define MT6360_REG_LDO3_EN_CTRL2 0x05 - -#define MT6360_REG_LDO3_CTRL3 0x09 -#define MT6360_MASK_LDO3_VOSEL 0xF0 -#define MT6360_MASK_LDO3_VOSEL_SHIFT 4 -#define MT6360_MASK_LDO3_VOCAL 0x0F - -#define MT6360_REG_LDO5_EN_CTRL2 0x0B - -#define MT6360_REG_LDO5_CTRL3 0x0F -#define MT6360_MASK_LDO5_VOSEL 0x70 -#define MT6360_MASK_LDO5_VOSEL_SHIFT 4 -#define MT6360_MASK_LDO5_VOCAL 0x0F - -#define MT6360_REG_LDO6_EN_CTRL2 0x37 - -#define MT6360_REG_LDO6_CTRL3 0x3B -#define MT6360_MASK_LDO6_VOSEL 0xF0 -#define MT6360_MASK_LDO6_VOSEL_SHIFT 4 -#define MT6360_MASK_LDO6_VOCAL 0x0F - -#define MT6360_REG_LDO7_EN_CTRL2 0x31 - -#define MT6360_REG_LDO7_CTRL3 0x35 -#define MT6360_MASK_LDO7_VOSEL 0xF0 -#define MT6360_MASK_LDO7_VOSEL_SHIFT 4 -#define MT6360_MASK_LDO7_VOCAL 0x0F - -#define MT6360_REG_BUCK1_EN_CTRL2 0x17 - -#define MT6360_REG_BUCK1_VOSEL 0x10 -#define MT6360_MASK_BUCK1_VOSEL 0xFF -#define MT6360_MASK_BUCK1_VOSEL_SHIFT 0 -#define MT6360_MASK_BUCK1_VOCAL 0x0 - -#define MT6360_REG_BUCK2_EN_CTRL2 0x26 - -#define MT6360_REG_BUCK2_VOSEL 0x20 -#define MT6360_MASK_BUCK2_VOSEL 0xFF -#define MT6360_MASK_BUCK2_VOSEL_SHIFT 0 -#define MT6360_MASK_BUCK2_VOCAL 0x0 - -/* This is same for LDO{1,2,3,5,6,7}_EN_CTRL2, BUCK{1,2}_EN_CTRL2 */ -#define MT6360_MASK_RGL_SW_OP_EN BIT(7) -#define MT6360_MASK_RGL_SW_EN BIT(6) - -#define MT6360_LDO_VOCAL_STEP_MV 10 -#define MT6360_LDO_VOCAL_MAX_STEP 10 - -#define MT6360_BUCK_VOSEL_STEP_MV 5 -#define MT6360_BUCK_VOSEL_MAX_STEP 200 -#define MT6360_BUCK_VOSEL_MIN 300 -#define MT6360_BUCK_VOSEL_MAX \ - (MT6360_BUCK_VOSEL_MIN + \ - MT6360_BUCK_VOSEL_STEP_MV * MT6360_BUCK_VOSEL_MAX_STEP) - -#endif /* __CROS_EC_MT6360_H */ diff --git a/driver/bc12/pi3usb9201.c b/driver/bc12/pi3usb9201.c deleted file mode 100644 index 2a9986f823..0000000000 --- a/driver/bc12/pi3usb9201.c +++ /dev/null @@ -1,410 +0,0 @@ -/* Copyright 2019 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. - */ - -/* PI3USB9201 USB BC 1.2 Charger Detector driver. */ - -#include "pi3usb9201.h" -#include "charge_manager.h" -#include "chipset.h" -#include "common.h" -#include "console.h" -#include "gpio.h" -#include "power.h" -#include "task.h" -#include "timer.h" -#include "usb_charge.h" -#include "usb_pd.h" -#include "util.h" - -#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) - -enum pi3usb9201_client_sts { - CHG_OTHER = 0, - CHG_2_4A, - CHG_2_0A, - CHG_1_0A, - CHG_RESERVED, - CHG_CDP, - CHG_SDP, - CHG_DCP, -}; - -struct bc12_status { - enum charge_supplier supplier; - int current_limit; -}; - -/* Used to store last BC1.2 detection result */ -static enum charge_supplier bc12_supplier[CONFIG_USB_PD_PORT_MAX_COUNT]; - -/* - * The USB Type-C specification limits the maximum amount of current from BC 1.2 - * suppliers to 1.5A. Technically, proprietary methods are not allowed, but we - * will continue to allow those. - */ -static const struct bc12_status bc12_chg_limits[] = { - [CHG_OTHER] = {CHARGE_SUPPLIER_OTHER, 500}, - [CHG_2_4A] = {CHARGE_SUPPLIER_PROPRIETARY, USB_CHARGER_MAX_CURR_MA}, - [CHG_2_0A] = {CHARGE_SUPPLIER_PROPRIETARY, USB_CHARGER_MAX_CURR_MA}, - [CHG_1_0A] = {CHARGE_SUPPLIER_PROPRIETARY, 1000}, - [CHG_RESERVED] = {CHARGE_SUPPLIER_NONE, 0}, - [CHG_CDP] = {CHARGE_SUPPLIER_BC12_CDP, USB_CHARGER_MAX_CURR_MA}, - [CHG_SDP] = {CHARGE_SUPPLIER_BC12_SDP, 500}, -#if defined(CONFIG_CHARGE_RAMP_SW) || defined(CONFIG_CHARGE_RAMP_HW) - /* - * If ramping is supported, then for DCP set the current limit to be the - * max supported for the port by the board or 1.5A (whichever is lower). - * Although, the BC 1.2 specification allows DCP suppliers to ramp to - * much higher currents, the USB Type-C specification limits the - * maximum current allowed for BC 1.2 suppliers to 1.5A. - */ - [CHG_DCP] = {CHARGE_SUPPLIER_BC12_DCP, USB_CHARGER_MAX_CURR_MA}, -#else - [CHG_DCP] = {CHARGE_SUPPLIER_BC12_DCP, 500}, -#endif -}; - -static inline int raw_read8(int port, int offset, int *value) -{ - return i2c_read8(pi3usb9201_bc12_chips[port].i2c_port, - pi3usb9201_bc12_chips[port].i2c_addr_flags, - offset, value); -} - -static int pi3usb9201_raw(int port, int reg, int mask, int val) -{ - /* Clear mask and then set val in i2c reg value */ - return i2c_field_update8(pi3usb9201_bc12_chips[port].i2c_port, - pi3usb9201_bc12_chips[port].i2c_addr_flags, - reg, mask, val); -} - -static int pi3usb9201_interrupt_mask(int port, int enable) -{ - return pi3usb9201_raw(port, PI3USB9201_REG_CTRL_1, - PI3USB9201_REG_CTRL_1_INT_MASK, - enable); -} - -static int pi3usb9201_bc12_detect_ctrl(int port, int enable) -{ - return pi3usb9201_raw(port, PI3USB9201_REG_CTRL_2, - PI3USB9201_REG_CTRL_2_START_DET, - enable ? PI3USB9201_REG_CTRL_2_START_DET : 0); -} - -static int pi3usb9201_set_mode(int port, int desired_mode) -{ - return pi3usb9201_raw(port, PI3USB9201_REG_CTRL_1, - PI3USB9201_REG_CTRL_1_MODE_MASK, - desired_mode << PI3USB9201_REG_CTRL_1_MODE_SHIFT); -} - -static int pi3usb9201_get_mode(int port, int *mode) -{ - int rv; - - rv = raw_read8(port, PI3USB9201_REG_CTRL_1, mode); - if (rv) - return rv; - - *mode &= PI3USB9201_REG_CTRL_1_MODE_MASK; - *mode >>= PI3USB9201_REG_CTRL_1_MODE_SHIFT; - - return EC_SUCCESS; -} - -static int pi3usb9201_get_status(int port, int *client, int *host) -{ - int rv; - int status; - - rv = raw_read8(port, PI3USB9201_REG_CLIENT_STS, &status); - if (client) - *client = status; - rv |= raw_read8(port, PI3USB9201_REG_HOST_STS, &status); - if (host) - *host = status; - - return rv; -} - -static void bc12_update_supplier(enum charge_supplier supplier, int port, - struct charge_port_info *new_chg) -{ - /* - * If most recent supplier type is not CHARGE_SUPPLIER_NONE, then the - * charge manager table entry for that supplier type needs to be cleared - * out. - */ - if (bc12_supplier[port] != CHARGE_SUPPLIER_NONE) - charge_manager_update_charge(bc12_supplier[port], port, NULL); - /* Now update the current supplier type */ - bc12_supplier[port] = supplier; - /* If new supplier type != NONE, then notify charge manager */ - if (supplier != CHARGE_SUPPLIER_NONE) - charge_manager_update_charge(supplier, port, new_chg); -} - -static void bc12_update_charge_manager(int port, int client_status) -{ - struct charge_port_info new_chg; - enum charge_supplier supplier; - int bit_pos; - - /* Set charge voltage to 5V */ - new_chg.voltage = USB_CHARGER_VOLTAGE_MV; - - /* - * Find set bit position. Note that this funciton is only called if a - * bit was set in client_status, so bit_pos won't be negative. - */ - bit_pos = __builtin_ffs(client_status) - 1; - - new_chg.current = bc12_chg_limits[bit_pos].current_limit; - supplier = bc12_chg_limits[bit_pos].supplier; - - CPRINTS("pi3usb9201[p%d]: sts = 0x%x, lim = %d mA, supplier = %d", - port, client_status, new_chg.current, supplier); - /* bc1.2 is complete and start bit does not auto clear */ - pi3usb9201_bc12_detect_ctrl(port, 0); - /* Inform charge manager of new supplier type and current limit */ - bc12_update_supplier(supplier, port, &new_chg); -} - -static int bc12_detect_start(int port) -{ - int rv; - - /* - * Read both status registers to ensure that all interrupt indications - * are cleared prior to starting bc1.2 detection. - */ - pi3usb9201_get_status(port, NULL, NULL); - - /* Put pi3usb9201 into client mode */ - rv = pi3usb9201_set_mode(port, PI3USB9201_CLIENT_MODE); - if (rv) - return rv; - /* Have pi3usb9201 start bc1.2 detection */ - rv = pi3usb9201_bc12_detect_ctrl(port, 1); - if (rv) - return rv; - /* Unmask interrupt to wake task when detection completes */ - return pi3usb9201_interrupt_mask(port, 0); -} - -static void bc12_power_down(int port) -{ - /* Put pi3usb9201 into its power down mode */ - pi3usb9201_set_mode(port, PI3USB9201_POWER_DOWN); - /* The start bc1.2 bit does not auto clear */ - pi3usb9201_bc12_detect_ctrl(port, 0); - /* Mask interrupts unitl next bc1.2 detection event */ - pi3usb9201_interrupt_mask(port, 1); - /* - * Let charge manager know there's no more charge available for the - * supplier type that was most recently detected. - */ - bc12_update_supplier(CHARGE_SUPPLIER_NONE, port, NULL); - - /* There's nothing else to do if the part is always powered. */ - if (pi3usb9201_bc12_chips[port].flags & PI3USB9201_ALWAYS_POWERED) - return; - -#if defined(CONFIG_POWER_PP5000_CONTROL) && defined(HAS_TASK_CHIPSET) - /* Indicate PP5000_A rail is not required by USB_CHG task. */ - power_5v_enable(task_get_current(), 0); -#endif -} - -static void bc12_power_up(int port) -{ - if (IS_ENABLED(CONFIG_POWER_PP5000_CONTROL) && - IS_ENABLED(HAS_TASK_CHIPSET) && - !(pi3usb9201_bc12_chips[port].flags & PI3USB9201_ALWAYS_POWERED)) { - /* Turn on the 5V rail to allow the chip to be powered. */ - power_5v_enable(task_get_current(), 1); - /* - * Give the pi3usb9201 time so it's ready to receive i2c - * messages - */ - msleep(1); - } - - pi3usb9201_interrupt_mask(port, 1); -} - -static void pi3usb9201_usb_charger_task(const int port) -{ - uint32_t evt; - int i; - - /* - * Set most recent bc1.2 detection supplier result to - * CHARGE_SUPPLIER_NONE for all ports. - */ - for (i = 0; i < board_get_usb_pd_port_count(); i++) - bc12_supplier[port] = CHARGE_SUPPLIER_NONE; - - /* - * The is no specific initialization required for the pi3usb9201 other - * than enabling the interrupt mask. - */ - pi3usb9201_interrupt_mask(port, 1); - - while (1) { - /* Wait for interrupt */ - evt = task_wait_event(-1); - - /* Interrupt from the Pericom chip, determine charger type */ - if (evt & USB_CHG_EVENT_BC12) { - int client; - int host; - int rv; - - rv = pi3usb9201_get_status(port, &client, &host); - if (!rv && client) - /* - * Any bit set in client status register - * indicates that BC1.2 detection has - * completed. - */ - bc12_update_charge_manager(port, client); - if (!rv && host) { - /* - * Switch to SDP after device is plugged in to - * avoid noise (pulse on D-) causing USB - * disconnect (b/156014140). - */ - if (host & PI3USB9201_REG_HOST_STS_DEV_PLUG) - pi3usb9201_set_mode(port, - PI3USB9201_SDP_HOST_MODE); - /* - * Switch to CDP after device is unplugged so - * we advertise higher power available for next - * device. - */ - if (host & PI3USB9201_REG_HOST_STS_DEV_UNPLUG) - pi3usb9201_set_mode(port, - PI3USB9201_CDP_HOST_MODE); - } - /* - * TODO(b/124061702): Use host status to allocate power - * more intelligently. - */ - } - -#ifndef CONFIG_USB_PD_VBUS_DETECT_TCPC - if (evt & USB_CHG_EVENT_VBUS) - CPRINTS("VBUS p%d %d", port, - pd_snk_is_vbus_provided(port)); -#endif - - if (evt & USB_CHG_EVENT_DR_UFP) { - bc12_power_up(port); - if (bc12_detect_start(port)) { - struct charge_port_info new_chg; - - /* - * VBUS is present, but starting bc1.2 detection - * failed for some reason. So limit charge - * current to default 500 mA for this case. - */ - - new_chg.voltage = USB_CHARGER_VOLTAGE_MV; - new_chg.current = USB_CHARGER_MIN_CURR_MA; - /* Save supplier type and notify chg manager */ - bc12_update_supplier(CHARGE_SUPPLIER_OTHER, - port, &new_chg); - CPRINTS("pi3usb9201[p%d]: bc1.2 failed use " - "defaults", port); - } - } - - if (evt & USB_CHG_EVENT_DR_DFP) { - int mode; - int rv; - - /* - * Update the charge manager if bc1.2 client mode is - * currently active. - */ - bc12_update_supplier(CHARGE_SUPPLIER_NONE, port, NULL); - /* - * If the port is in DFP mode, then need to set mode to - * CDP_HOST which will auto close D+/D- switches. - */ - bc12_power_up(port); - rv = pi3usb9201_get_mode(port, &mode); - if (!rv && (mode != PI3USB9201_CDP_HOST_MODE)) { - CPRINTS("pi3usb9201[p%d]: CDP_HOST mode", port); - /* - * Read both status registers to ensure that all - * interrupt indications are cleared prior to - * starting DFP CDP host mode. - */ - pi3usb9201_get_status(port, NULL, NULL); - pi3usb9201_set_mode(port, - PI3USB9201_CDP_HOST_MODE); - /* - * Unmask interrupt to wake task when host - * status changes. - */ - pi3usb9201_interrupt_mask(port, 0); - } - } - - if (evt & USB_CHG_EVENT_CC_OPEN) - bc12_power_down(port); - } -} - -#if defined(CONFIG_CHARGE_RAMP_SW) || defined(CONFIG_CHARGE_RAMP_HW) -static int pi3usb9201_ramp_allowed(int supplier) -{ - /* Don't allow ramp if charge supplier is OTHER, SDP, or NONE */ - return !(supplier == CHARGE_SUPPLIER_OTHER || - supplier == CHARGE_SUPPLIER_BC12_SDP || - supplier == CHARGE_SUPPLIER_NONE); -} - -static int pi3usb9201_ramp_max(int supplier, int sup_curr) -{ - /* - * Use the level from the bc12_chg_limits table above except for - * proprietary or CDP and in those cases the charge current from the - * charge manager is already set at the max determined by bc1.2 - * detection. - */ - switch (supplier) { - case CHARGE_SUPPLIER_BC12_DCP: - return USB_CHARGER_MAX_CURR_MA; - case CHARGE_SUPPLIER_BC12_CDP: - case CHARGE_SUPPLIER_PROPRIETARY: - return sup_curr; - case CHARGE_SUPPLIER_BC12_SDP: - default: - return 500; - } -} -#endif /* CONFIG_CHARGE_RAMP_SW || CONFIG_CHARGE_RAMP_HW */ - -const struct bc12_drv pi3usb9201_drv = { - .usb_charger_task = pi3usb9201_usb_charger_task, -#if defined(CONFIG_CHARGE_RAMP_SW) || defined(CONFIG_CHARGE_RAMP_HW) - .ramp_allowed = pi3usb9201_ramp_allowed, - .ramp_max = pi3usb9201_ramp_max, -#endif /* CONFIG_CHARGE_RAMP_SW || CONFIG_CHARGE_RAMP_HW */ -}; - -#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 = &pi3usb9201_drv, - } -}; -#endif /* CONFIG_BC12_SINGLE_DRIVER */ diff --git a/driver/bc12/pi3usb9201.h b/driver/bc12/pi3usb9201.h deleted file mode 100644 index 3163a3eebc..0000000000 --- a/driver/bc12/pi3usb9201.h +++ /dev/null @@ -1,47 +0,0 @@ -/* Copyright 2019 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. - */ - -/* PI3USB9201 USB BC 1.2 Charger Detector driver definitions */ - -#ifndef __CROS_EC_DRIVER_BC12_PI3USB9201_H -#define __CROS_EC_DRIVER_BC12_PI3USB9201_H - -#include "driver/bc12/pi3usb9201_public.h" - -#define PI3USB9201_REG_CTRL_1 0x0 -#define PI3USB9201_REG_CTRL_2 0x1 -#define PI3USB9201_REG_CLIENT_STS 0x2 -#define PI3USB9201_REG_HOST_STS 0x3 - -/* Flags */ -#define PI3USB9201_ALWAYS_POWERED BIT(0) - -/* Control_1 regiter bit definitions */ -#define PI3USB9201_REG_CTRL_1_INT_MASK BIT(0) -#define PI3USB9201_REG_CTRL_1_MODE_SHIFT 1 -#define PI3USB9201_REG_CTRL_1_MODE_MASK (0x7 << \ - PI3USB9201_REG_CTRL_1_MODE_SHIFT) - -/* Control_2 regiter bit definitions */ -#define PI3USB9201_REG_CTRL_2_AUTO_SW BIT(1) -#define PI3USB9201_REG_CTRL_2_START_DET BIT(3) - -/* Host status register bit definitions */ -#define PI3USB9201_REG_HOST_STS_BC12_DET BIT(0) -#define PI3USB9201_REG_HOST_STS_DEV_PLUG BIT(1) -#define PI3USB9201_REG_HOST_STS_DEV_UNPLUG BIT(2) - -enum pi3usb9201_mode { - PI3USB9201_POWER_DOWN, - PI3USB9201_SDP_HOST_MODE, - PI3USB9201_DCP_HOST_MODE, - PI3USB9201_CDP_HOST_MODE, - PI3USB9201_CLIENT_MODE, - PI3USB9201_RESERVED_1, - PI3USB9201_RESERVED_2, - PI3USB9201_USB_PATH_ON, -}; - -#endif /* __CROS_EC_DRIVER_BC12_PI3USB9201_H */ diff --git a/driver/bc12/pi3usb9281.c b/driver/bc12/pi3usb9281.c deleted file mode 100644 index 9fc32e942b..0000000000 --- a/driver/bc12/pi3usb9281.c +++ /dev/null @@ -1,505 +0,0 @@ -/* Copyright 2014 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. - * - * Pericom PI3USB3281 USB port switch driver. - */ - -#include "charge_manager.h" -#include "common.h" -#include "console.h" -#include "ec_commands.h" -#include "gpio.h" -#include "hooks.h" -#include "i2c.h" -#include "pi3usb9281.h" -#include "task.h" -#include "timer.h" -#include "usb_charge.h" -#include "usb_pd.h" -#include "util.h" - - /* Console output macros */ -#define CPUTS(outstr) cputs(CC_USBCHARGE, outstr) -#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) - -/* I2C address */ -#define PI3USB9281_I2C_ADDR_FLAGS 0x25 - -/* Delay values */ -#define PI3USB9281_SW_RESET_DELAY 20 - -/* Wait after a charger is detected to debounce pin contact order */ -#define PI3USB9281_DETECT_DEBOUNCE_MS 1000 -#define PI3USB9281_RESET_DEBOUNCE_MS 100 -#define PI3USB9281_RESET_STARTUP_DELAY (200 * MSEC) -#define PI3USB9281_RESET_STARTUP_DELAY_INTERVAL_MS 40 - -/* Store the state of our USB data switches so that they can be restored. */ -static int usb_switch_state[CONFIG_USB_PD_PORT_MAX_COUNT]; - -static int pi3usb9281_reset(int port); -static int pi3usb9281_get_interrupts(int port); - -static void select_chip(int port) -{ - struct pi3usb9281_config *chip = &pi3usb9281_chips[port]; - ASSERT(port < CONFIG_BC12_DETECT_PI3USB9281_CHIP_COUNT); - - if (chip->mux_lock) { - mutex_lock(chip->mux_lock); - gpio_set_level(chip->mux_gpio, chip->mux_gpio_level); - } -} - -static void unselect_chip(int port) -{ - struct pi3usb9281_config *chip = &pi3usb9281_chips[port]; - - if (chip->mux_lock) - /* Just release the mutex, no need to change the mux gpio */ - mutex_unlock(chip->mux_lock); -} - -static uint8_t pi3usb9281_do_read(int port, uint8_t reg, int with_lock) -{ - struct pi3usb9281_config *chip = &pi3usb9281_chips[port]; - int res, val; - - if (with_lock) - select_chip(port); - - res = i2c_read8(chip->i2c_port, PI3USB9281_I2C_ADDR_FLAGS, - reg, &val); - - if (with_lock) - unselect_chip(port); - - if (res) - return 0xee; - - return val; -} - -static uint8_t pi3usb9281_read_u(int port, uint8_t reg) -{ - return pi3usb9281_do_read(port, reg, 0); -} - -static uint8_t pi3usb9281_read(int port, uint8_t reg) -{ - return pi3usb9281_do_read(port, reg, 1); -} - -static int pi3usb9281_do_write( - int port, uint8_t reg, uint8_t val, int with_lock) -{ - struct pi3usb9281_config *chip = &pi3usb9281_chips[port]; - int res; - - if (with_lock) - select_chip(port); - - res = i2c_write8(chip->i2c_port, PI3USB9281_I2C_ADDR_FLAGS, - reg, val); - - if (with_lock) - unselect_chip(port); - - if (res) - CPRINTS("PI3USB9281 I2C write failed"); - return res; -} - -static int pi3usb9281_write(int port, uint8_t reg, uint8_t val) -{ - return pi3usb9281_do_write(port, reg, val, 1); -} - -/* Write control register, taking care to correctly set reserved bits. */ -static int pi3usb9281_do_write_ctrl(int port, uint8_t ctrl, int with_lock) -{ - return pi3usb9281_do_write(port, PI3USB9281_REG_CONTROL, - (ctrl & PI3USB9281_CTRL_MASK) | - PI3USB9281_CTRL_RSVD_1, with_lock); -} - -static int pi3usb9281_write_ctrl(int port, uint8_t ctrl) -{ - return pi3usb9281_do_write_ctrl(port, ctrl, 1); -} - -static int pi3usb9281_write_ctrl_u(int port, uint8_t ctrl) -{ - return pi3usb9281_do_write_ctrl(port, ctrl, 0); -} - -/* - * Mask particular interrupts (e.g. attach, detach, ovp, ocp). - * 1: UnMask (enable). 0: Mask (disable) - */ -static int pi3usb9281_set_interrupt_mask(int port, uint8_t mask) -{ - return pi3usb9281_write(port, PI3USB9281_REG_INT_MASK, ~mask); -} - -static void pi3usb9281_init(int port) -{ - uint8_t dev_id; - - dev_id = pi3usb9281_read(port, PI3USB9281_REG_DEV_ID); - - if (dev_id != PI3USB9281_DEV_ID && dev_id != PI3USB9281_DEV_ID_A) - CPRINTS("PI3USB9281 invalid ID 0x%02x", dev_id); - - pi3usb9281_reset(port); - pi3usb9281_enable_interrupts(port); -} - - -int pi3usb9281_enable_interrupts(int port) -{ - uint8_t ctrl; - pi3usb9281_set_interrupt_mask(port, PI3USB9281_INT_ATTACH_DETACH); - ctrl = pi3usb9281_read(port, PI3USB9281_REG_CONTROL); - if (ctrl == 0xee) - return EC_ERROR_UNKNOWN; - - return pi3usb9281_write_ctrl(port, ctrl & ~PI3USB9281_CTRL_INT_DIS); -} - -static int pi3usb9281_disable_interrupts(int port) -{ - uint8_t ctrl = pi3usb9281_read(port, PI3USB9281_REG_CONTROL); - int rv; - - if (ctrl == 0xee) - return EC_ERROR_UNKNOWN; - - rv = pi3usb9281_write_ctrl(port, ctrl | PI3USB9281_CTRL_INT_DIS); - pi3usb9281_get_interrupts(port); - return rv; -} - -static int pi3usb9281_get_interrupts(int port) -{ - return pi3usb9281_read(port, PI3USB9281_REG_INT); -} - -int pi3usb9281_get_device_type(int port) -{ - return pi3usb9281_read(port, PI3USB9281_REG_DEV_TYPE) & 0x77; -} - -static int pi3usb9281_get_charger_status(int port) -{ - return pi3usb9281_read(port, PI3USB9281_REG_CHG_STATUS) & 0x1f; -} - -static int pi3usb9281_get_ilim(int device_type, int charger_status) -{ - /* Limit USB port current. 500mA for not listed types. */ - int current_limit_ma = 500; - - /* - * The USB Type-C specification limits the maximum amount of current - * from BC 1.2 suppliers to 1.5A. Technically, proprietary methods are - * not allowed, but we will continue to allow those. - */ - if (charger_status & PI3USB9281_CHG_CAR_TYPE1 || - charger_status & PI3USB9281_CHG_CAR_TYPE2) - current_limit_ma = USB_CHARGER_MAX_CURR_MA; - else if (charger_status & PI3USB9281_CHG_APPLE_1A) - current_limit_ma = 1000; - else if (charger_status & PI3USB9281_CHG_APPLE_2A) - current_limit_ma = USB_CHARGER_MAX_CURR_MA; - else if (charger_status & PI3USB9281_CHG_APPLE_2_4A) - current_limit_ma = USB_CHARGER_MAX_CURR_MA; - else if (device_type & PI3USB9281_TYPE_CDP) - current_limit_ma = USB_CHARGER_MAX_CURR_MA; - else if (device_type & PI3USB9281_TYPE_DCP) - current_limit_ma = 500; - - return current_limit_ma; -} - -static int pi3usb9281_reset(int port) -{ - int rv = pi3usb9281_write(port, PI3USB9281_REG_RESET, 0x1); - - if (!rv) - /* Reset takes ~15ms. Wait for 20ms to be safe. */ - msleep(PI3USB9281_SW_RESET_DELAY); - - return rv; -} - -static int pi3usb9281_set_switch_manual(int port, int val) -{ - int res = EC_ERROR_UNKNOWN; - uint8_t ctrl; - - select_chip(port); - ctrl = pi3usb9281_read_u(port, PI3USB9281_REG_CONTROL); - - if (ctrl != 0xee) { - if (val) - ctrl &= ~PI3USB9281_CTRL_AUTO; - else - ctrl |= PI3USB9281_CTRL_AUTO; - res = pi3usb9281_write_ctrl_u(port, ctrl); - } - - unselect_chip(port); - return res; -} - -static int pi3usb9281_set_pins(int port, uint8_t val) -{ - return pi3usb9281_write(port, PI3USB9281_REG_MANUAL, val); -} - -static int pi3usb9281_set_switches_impl(int port, int open) -{ - int res = EC_ERROR_UNKNOWN; - uint8_t ctrl; - - select_chip(port); - ctrl = pi3usb9281_read_u(port, PI3USB9281_REG_CONTROL); - - if (ctrl != 0xee) { - if (open) - ctrl &= ~PI3USB9281_CTRL_SWITCH_AUTO; - else - ctrl |= PI3USB9281_CTRL_SWITCH_AUTO; - res = pi3usb9281_write_ctrl_u(port, ctrl); - } - - unselect_chip(port); - return res; -} - -static void pi3usb9281_set_switches(int port, enum usb_switch setting) -{ - /* If switch is not changing then return */ - if (setting == usb_switch_state[port]) - return; - if (setting != USB_SWITCH_RESTORE) - usb_switch_state[port] = setting; - CPRINTS("USB MUX %d", usb_switch_state[port]); - task_set_event(TASK_ID_USB_CHG_P0 + port, USB_CHG_EVENT_MUX); -} - -static int pc3usb9281_read_interrupt(int port) -{ - timestamp_t timeout; - timeout.val = get_time().val + PI3USB9281_RESET_STARTUP_DELAY; - do { - /* Read (& clear) possible attach & detach interrupt */ - if (pi3usb9281_get_interrupts(port) & - PI3USB9281_INT_ATTACH_DETACH) - return EC_SUCCESS; - msleep(PI3USB9281_RESET_STARTUP_DELAY_INTERVAL_MS); - } while (get_time().val < timeout.val); - return EC_ERROR_TIMEOUT; -} - -/* - * Handle BC 1.2 attach & detach event - * - * On attach, it resets pi3usb9281 for debounce. This reset should immediately - * trigger another attach or detach interrupt. If other (unexpected) event is - * observed, it forwards the event so that the caller can handle it. - */ -static uint32_t bc12_detect(int port) -{ - int device_type, chg_status; - uint32_t evt = 0; - - if (usb_charger_port_is_sourcing_vbus(port)) { - /* If we're sourcing VBUS then we're not charging */ - device_type = PI3USB9281_TYPE_NONE; - chg_status = PI3USB9281_CHG_NONE; - } else { - /* Set device type */ - device_type = pi3usb9281_get_device_type(port); - chg_status = pi3usb9281_get_charger_status(port); - } - - /* Debounce pin plug order if we detect a charger */ - if (device_type || PI3USB9281_CHG_STATUS_ANY(chg_status)) { - /* next operation might trigger a detach interrupt */ - pi3usb9281_disable_interrupts(port); - /* - * Ensure D+/D- are open before resetting - * Note: we can't simply call pi3usb9281_set_switches() because - * another task might override it and set the switches closed. - */ - pi3usb9281_set_switch_manual(port, 1); - pi3usb9281_set_pins(port, 0); - - /* Delay to debounce pin attach order */ - msleep(PI3USB9281_DETECT_DEBOUNCE_MS); - - /* - * Reset PI3USB9281 to refresh detection registers. After reset, - * - Interrupt is globally disabled - * - All interrupts are unmasked (=enabled) - * - * WARNING: This reset is acceptable for samus_pd, - * but may not be acceptable for devices that have - * an OTG / device mode, as we may be interrupting - * the connection. - */ - pi3usb9281_reset(port); - - /* - * Restore data switch settings - switches return to - * closed on reset until restored. - */ - pi3usb9281_set_switches(port, USB_SWITCH_RESTORE); - - /* - * Wait after reset, before re-enabling interrupt, so that - * spurious interrupts from this port are ignored. - */ - msleep(PI3USB9281_RESET_DEBOUNCE_MS); - - /* Re-enable interrupts */ - pi3usb9281_enable_interrupts(port); - - /* - * Consume interrupt (expectedly) triggered by the reset. - * If it's other event (e.g. VBUS), return immediately. - */ - evt = task_wait_event(PI3USB9281_RESET_DEBOUNCE_MS * MSEC); - if (evt & USB_CHG_EVENT_BC12) - evt &= ~USB_CHG_EVENT_BC12; - else if (evt & USB_CHG_EVENT_INTR) - evt &= ~USB_CHG_EVENT_INTR; - else - return evt; - - /* Debounce is done. Registers should have trustworthy values */ - device_type = PI3USB9281_TYPE_NONE; - chg_status = PI3USB9281_CHG_NONE; - if (pc3usb9281_read_interrupt(port) == EC_SUCCESS) { - device_type = pi3usb9281_get_device_type(port); - chg_status = pi3usb9281_get_charger_status(port); - } - } - - /* Attachment: decode + update available charge */ - if (device_type || PI3USB9281_CHG_STATUS_ANY(chg_status)) { - struct charge_port_info chg; - int type; - - if (PI3USB9281_CHG_STATUS_ANY(chg_status)) - type = CHARGE_SUPPLIER_PROPRIETARY; - else if (device_type & PI3USB9281_TYPE_CDP) - type = CHARGE_SUPPLIER_BC12_CDP; - else if (device_type & PI3USB9281_TYPE_DCP) - type = CHARGE_SUPPLIER_BC12_DCP; - else if (device_type & PI3USB9281_TYPE_SDP) - type = CHARGE_SUPPLIER_BC12_SDP; - else - type = CHARGE_SUPPLIER_OTHER; - - chg.voltage = USB_CHARGER_VOLTAGE_MV; - chg.current = pi3usb9281_get_ilim(device_type, chg_status); - charge_manager_update_charge(type, port, &chg); - } else { - /* Detachment: update available charge to 0 */ - usb_charger_reset_charge(port); - } - - return evt; -} - -static void pi3usb9281_usb_charger_task(const int port) -{ - uint32_t evt; - - /* Initialize chip and enable interrupts */ - pi3usb9281_init(port); - - evt = bc12_detect(port); - - while (1) { - /* Interrupt from the Pericom chip, determine charger type */ - if (evt & USB_CHG_EVENT_BC12) { - /* Read interrupt register to clear on chip */ - pi3usb9281_get_interrupts(port); - evt = bc12_detect(port); - } else if (evt & USB_CHG_EVENT_INTR) { - /* USB_CHG_EVENT_INTR & _BC12 are mutually exclusive */ - /* Check the interrupt register, and clear on chip */ - if (pi3usb9281_get_interrupts(port) & - PI3USB9281_INT_ATTACH_DETACH) - evt = bc12_detect(port); - } - - if (evt & USB_CHG_EVENT_MUX) - pi3usb9281_set_switches_impl( - port, usb_switch_state[port]); - - /* - * Re-enable interrupts on pericom charger detector since the - * chip may periodically reset itself, and come back up with - * registers in default state. TODO(crosbug.com/p/33823): Fix - * these unwanted resets. - */ - if (evt & USB_CHG_EVENT_VBUS) { - pi3usb9281_enable_interrupts(port); -#ifndef CONFIG_USB_PD_VBUS_DETECT_TCPC - CPRINTS("VBUS p%d %d", port, - pd_snk_is_vbus_provided(port)); -#endif - } - - evt = task_wait_event(-1); - } -} - -#if defined(CONFIG_CHARGE_RAMP_SW) || defined(CONFIG_CHARGE_RAMP_HW) -static int pi3usb9281_ramp_allowed(int supplier) -{ - return supplier == CHARGE_SUPPLIER_BC12_DCP || - supplier == CHARGE_SUPPLIER_BC12_SDP || - supplier == CHARGE_SUPPLIER_BC12_CDP || - supplier == CHARGE_SUPPLIER_PROPRIETARY; -} - -static int pi3usb9281_ramp_max(int supplier, int sup_curr) -{ - switch (supplier) { - case CHARGE_SUPPLIER_BC12_DCP: - return USB_CHARGER_MAX_CURR_MA; - case CHARGE_SUPPLIER_BC12_SDP: - return 500; - case CHARGE_SUPPLIER_BC12_CDP: - case CHARGE_SUPPLIER_PROPRIETARY: - return sup_curr; - default: - return 500; - } -} -#endif /* CONFIG_CHARGE_RAMP_SW || CONFIG_CHARGE_RAMP_HW */ - -const struct bc12_drv pi3usb9281_drv = { - .usb_charger_task = pi3usb9281_usb_charger_task, - .set_switches = pi3usb9281_set_switches, -#if defined(CONFIG_CHARGE_RAMP_SW) || defined(CONFIG_CHARGE_RAMP_HW) - .ramp_allowed = pi3usb9281_ramp_allowed, - .ramp_max = pi3usb9281_ramp_max, -#endif /* CONFIG_CHARGE_RAMP_SW || CONFIG_CHARGE_RAMP_HW */ -}; - -#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 = &pi3usb9281_drv, - }, -}; -#endif /* CONFIG_BC12_SINGLE_DRIVER */ diff --git a/driver/bc12/pi3usb9281.h b/driver/bc12/pi3usb9281.h deleted file mode 100644 index ca1828f49c..0000000000 --- a/driver/bc12/pi3usb9281.h +++ /dev/null @@ -1,83 +0,0 @@ -/* Copyright 2014 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. - * - * Pericom PI3USB9281 USB port switch. - */ - -#ifndef __CROS_EC_PI3USB9281_H -#define __CROS_EC_PI3USB9281_H - -#define PI3USB9281_REG_DEV_ID 0x01 -#define PI3USB9281_REG_CONTROL 0x02 -#define PI3USB9281_REG_INT 0x03 -#define PI3USB9281_REG_INT_MASK 0x05 -#define PI3USB9281_REG_DEV_TYPE 0x0a -#define PI3USB9281_REG_CHG_STATUS 0x0e -#define PI3USB9281_REG_MANUAL 0x13 -#define PI3USB9281_REG_RESET 0x1b -#define PI3USB9281_REG_VBUS 0x1d - -#define PI3USB9281_DEV_ID 0x10 -#define PI3USB9281_DEV_ID_A 0x18 - -#define PI3USB9281_CTRL_INT_DIS BIT(0) -#define PI3USB9281_CTRL_AUTO BIT(2) -#define PI3USB9281_CTRL_SWITCH_AUTO BIT(4) -/* Bits 5 thru 7 are read X, write 0 */ -#define PI3USB9281_CTRL_MASK 0x1f -/* Bits 1 and 3 are read 1, write 1 */ -#define PI3USB9281_CTRL_RSVD_1 0x0a - -#define PI3USB9281_PIN_MANUAL_VBUS (3 << 0) -#define PI3USB9281_PIN_MANUAL_DP BIT(2) -#define PI3USB9281_PIN_MANUAL_DM BIT(5) - -#define PI3USB9281_INT_ATTACH BIT(0) -#define PI3USB9281_INT_DETACH BIT(1) -#define PI3USB9281_INT_OVP BIT(5) -#define PI3USB9281_INT_OCP BIT(6) -#define PI3USB9281_INT_OVP_OC BIT(7) -#define PI3USB9281_INT_ATTACH_DETACH (PI3USB9281_INT_ATTACH | \ - PI3USB9281_INT_DETACH) - -#define PI3USB9281_TYPE_NONE 0 -#define PI3USB9281_TYPE_MHL BIT(0) -#define PI3USB9281_TYPE_OTG BIT(1) -#define PI3USB9281_TYPE_SDP BIT(2) -#define PI3USB9281_TYPE_CAR BIT(4) -#define PI3USB9281_TYPE_CDP BIT(5) -#define PI3USB9281_TYPE_DCP BIT(6) - -#define PI3USB9281_CHG_NONE 0 -#define PI3USB9281_CHG_CAR_TYPE1 BIT(1) -#define PI3USB9281_CHG_CAR_TYPE2 (3 << 0) -#define PI3USB9281_CHG_APPLE_1A BIT(2) -#define PI3USB9281_CHG_APPLE_2A BIT(3) -#define PI3USB9281_CHG_APPLE_2_4A BIT(4) -/* Check if charge status has any connection */ -#define PI3USB9281_CHG_STATUS_ANY(x) (((x) & 0x1f) > 1) - -/* Define configuration of one pi3usb9281 part */ -struct pi3usb9281_config { - /* i2c port that chip resides on */ - int i2c_port; - /* GPIO for chip selection in muxed configuration */ - enum gpio_signal mux_gpio; - /* Logic level of mux_gpio to select chip */ - int mux_gpio_level; - /* Mutex to lock access to mux gpio or NULL if no mux exists */ - struct mutex *mux_lock; -}; - -/* Configuration struct defined at board level */ -extern struct pi3usb9281_config pi3usb9281_chips[]; - -/* Enable interrupts. */ -int pi3usb9281_enable_interrupts(int port); - -/* Get the device type */ -int pi3usb9281_get_device_type(int port); - -extern const struct bc12_drv pi3usb9281_drv; -#endif /* __CROS_EC_PI3USB9281_H */ diff --git a/driver/build.mk b/driver/build.mk index 4ff201c5ce..4941ba3baa 100644 --- a/driver/build.mk +++ b/driver/build.mk @@ -80,9 +80,6 @@ driver-$(CONFIG_CHARGER_SM5803)+=charger/sm5803.o # DP Redrivers driver-$(CONFIG_DP_REDRIVER_TDP142)+=retimer/tdp142.o -# Fingerprint Sensors -include $(_driver_cur_dir)fingerprint/build.mk - # I/O expander driver-$(CONFIG_IO_EXPANDER_CCGXXF)+=ioexpander/ccgxxf.o driver-$(CONFIG_IO_EXPANDER_IT8801)+=ioexpander/it8801.o diff --git a/driver/charger/bd9995x.c b/driver/charger/bd9995x.c deleted file mode 100644 index 6fd79b8d8f..0000000000 --- a/driver/charger/bd9995x.c +++ /dev/null @@ -1,1775 +0,0 @@ -/* Copyright 2016 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. - * - * ROHM BD9995X battery charger driver. - */ - -#include "battery.h" -#include "battery_smart.h" -#include "bd9995x.h" -#include "charge_manager.h" -#include "charge_state.h" -#include "charger.h" -#include "console.h" -#include "ec_commands.h" -#include "hooks.h" -#include "i2c.h" -#include "task.h" -#include "time.h" -#include "util.h" -#include "usb_charge.h" -#include "usb_pd.h" - -#define OTPROM_LOAD_WAIT_RETRY 3 - -#define BD9995X_CHARGE_PORT_COUNT 2 - -/* - * BC1.2 detection starts 100ms after VBUS/VCC attach and typically - * completes 312ms after VBUS/VCC attach. - */ -#define BC12_DETECT_US (312*MSEC) -#define BD9995X_VSYS_PRECHARGE_OFFSET_MV 200 - -/* Console output macros */ -#define CPRINTS(format, args...) cprints(CC_CHARGER, format, ## args) - -#ifdef CONFIG_BD9995X_DELAY_INPUT_PORT_SELECT -/* - * Used in a check to determine if VBUS is within the - * range of some VOLTAGE +/- VBUS_DELTA, where voltage - * is measured in mV. - */ -#define VBUS_DELTA 1000 - -/* VBUS is debounced if it's stable for this length of time */ -#define VBUS_MSEC (100*MSEC) - -/* VBUS debouncing sample interval */ -#define VBUS_CHECK_MSEC (10*MSEC) - -/* Time to wait before VBUS debouncing begins */ -#define STABLE_TIMEOUT (500*MSEC) - -/* Maximum time to wait until VBUS is debounced */ -#define DEBOUNCE_TIMEOUT (500*MSEC) - -enum vstate {START, STABLE, DEBOUNCE}; -static enum vstate vbus_state; - -static int vbus_voltage; -static uint64_t debounce_time; -static uint64_t vbus_timeout; -static int port_update; -static int select_update; -static int select_input_port_update; -#endif - -/* Charger parameters */ -#define CHARGER_NAME BD9995X_CHARGER_NAME -#define CHARGE_V_MAX 19200 -#define CHARGE_V_MIN 3072 -#define CHARGE_V_STEP 16 -#define CHARGE_I_MAX 16320 -#define CHARGE_I_MIN 128 -#define CHARGE_I_OFF 0 -#define CHARGE_I_STEP 64 -#define INPUT_I_MAX 16352 -#define INPUT_I_MIN 512 -#define INPUT_I_STEP 32 - -/* Charger parameters */ -static const struct charger_info bd9995x_charger_info = { - .name = CHARGER_NAME, - .voltage_max = CHARGE_V_MAX, - .voltage_min = CHARGE_V_MIN, - .voltage_step = CHARGE_V_STEP, - .current_max = CHARGE_I_MAX, - .current_min = CHARGE_I_MIN, - .current_step = CHARGE_I_STEP, - .input_current_max = INPUT_I_MAX, - .input_current_min = INPUT_I_MIN, - .input_current_step = INPUT_I_STEP, -}; - -/* Charge command code map */ -static enum bd9995x_command charger_map_cmd = BD9995X_INVALID_COMMAND; - -/* Mutex for active register set control. */ -static struct mutex bd9995x_map_mutex; - -/* Tracks the state of VSYS_PRIORITY */ -static int vsys_priority; -/* Mutex for VIN_CTRL_SET register */ -static struct mutex bd9995x_vin_mutex; - -#ifdef HAS_TASK_USB_CHG -/* USB switch */ -static enum usb_switch usb_switch_state[BD9995X_CHARGE_PORT_COUNT] = { - USB_SWITCH_DISCONNECT, - USB_SWITCH_DISCONNECT, -}; - -static enum ec_error_list bd9995x_set_current(int chgnum, int current); -static enum ec_error_list bd9995x_set_voltage(int chgnum, int voltage); - -/* - * The USB Type-C specification limits the maximum amount of current from BC 1.2 - * suppliers to 1.5A. Technically, proprietary methods are not allowed, but we - * will continue to allow those. - */ -static int bd9995x_get_bc12_ilim(int charge_supplier) -{ - switch (charge_supplier) { - case CHARGE_SUPPLIER_BC12_CDP: - return USB_CHARGER_MAX_CURR_MA; - case CHARGE_SUPPLIER_BC12_DCP: - return USB_CHARGER_MAX_CURR_MA; - case CHARGE_SUPPLIER_BC12_SDP: - return 900; - case CHARGE_SUPPLIER_OTHER: -#ifdef CONFIG_CHARGE_RAMP_SW - return USB_CHARGER_MAX_CURR_MA; -#else - /* - * Setting the higher limit of current may result in an - * anti-collapse hence limiting the current to 1A. - */ - return 1000; -#endif - default: - return 500; - } -} -#endif /* HAS_TASK_USB_CHG */ - -static inline enum ec_error_list ch_raw_read16(int chgnum, int cmd, int *param, - enum bd9995x_command map_cmd) -{ - int rv; - - /* Map the Charge command code to appropriate region */ - mutex_lock(&bd9995x_map_mutex); - if (charger_map_cmd != map_cmd) { - rv = i2c_write16(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, - BD9995X_CMD_MAP_SET, map_cmd); - if (rv) { - charger_map_cmd = BD9995X_INVALID_COMMAND; - goto bd9995x_read_cleanup; - } - - charger_map_cmd = map_cmd; - } - - rv = i2c_read16(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, - cmd, param); - -bd9995x_read_cleanup: - mutex_unlock(&bd9995x_map_mutex); - - return rv; -} - -static inline enum ec_error_list ch_raw_write16(int chgnum, int cmd, int param, - enum bd9995x_command map_cmd) -{ - int rv; - - /* Map the Charge command code to appropriate region */ - mutex_lock(&bd9995x_map_mutex); - if (charger_map_cmd != map_cmd) { - rv = i2c_write16(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, - BD9995X_CMD_MAP_SET, map_cmd); - if (rv) { - charger_map_cmd = BD9995X_INVALID_COMMAND; - goto bd9995x_write_cleanup; - } - - charger_map_cmd = map_cmd; - } - - rv = i2c_write16(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, - cmd, param); - -bd9995x_write_cleanup: - mutex_unlock(&bd9995x_map_mutex); - - return rv; -} - -/* BD9995X local interfaces */ - -static int bd9995x_set_vfastchg(int chgnum, int voltage) -{ - - int rv; - - /* Fast Charge Voltage Regulation Settings for fast charging. */ - rv = ch_raw_write16(chgnum, BD9995X_CMD_VFASTCHG_REG_SET1, - voltage & 0x7FF0, BD9995X_EXTENDED_COMMAND); - if (rv) - return rv; - -#ifndef CONFIG_CHARGER_BATTERY_TSENSE - /* - * If TSENSE is not connected set all the VFASTCHG_REG_SETx - * to same voltage. - */ - rv = ch_raw_write16(chgnum, BD9995X_CMD_VFASTCHG_REG_SET2, - voltage & 0x7FF0, BD9995X_EXTENDED_COMMAND); - if (rv) - return rv; - - rv = ch_raw_write16(chgnum, BD9995X_CMD_VFASTCHG_REG_SET3, - voltage & 0x7FF0, BD9995X_EXTENDED_COMMAND); -#endif - - return rv; -} - -static int bd9995x_set_vsysreg(int chgnum, int voltage) -{ - /* VSYS Regulation voltage is in 64mV steps. */ - voltage &= ~0x3F; - - return ch_raw_write16(chgnum, BD9995X_CMD_VSYSREG_SET, voltage, - BD9995X_EXTENDED_COMMAND); -} - -static int bd9995x_is_discharging_on_ac(int chgnum) -{ - int reg; - - if (ch_raw_read16(chgnum, BD9995X_CMD_CHGOP_SET2, ®, - BD9995X_EXTENDED_COMMAND)) - return 0; - - return !!(reg & BD9995X_CMD_CHGOP_SET2_BATT_LEARN); -} - -static int bd9995x_charger_enable(int chgnum, int enable) -{ - int rv, reg; - static int prev_chg_enable = -1; - const struct battery_info *bi = battery_get_info(); - -#ifdef CONFIG_CHARGER_BD9995X_CHGEN - /* - * If the battery is not yet initialized, dont turn-off the BGATE so - * that voltage from the AC is applied to the battery PACK. - */ - if (!enable && !board_battery_initialized()) - return EC_SUCCESS; -#endif - - /* Nothing to change */ - if (enable == prev_chg_enable) - return EC_SUCCESS; - - prev_chg_enable = enable; - - if (enable) { - /* - * BGATE capacitor max : 0.1uF + 20% - * Charge MOSFET threshold max : 2.8V - * BGATE charge pump current min : 3uA - * T = C * V / I so, Tmax = 112ms - */ - msleep(115); - - /* - * Set VSYSREG_SET <= VBAT so that the charger is in Fast-Charge - * state when charging. - */ - rv = bd9995x_set_vsysreg(chgnum, bi->voltage_min); - } else { - /* - * Set VSYSREG_SET > VBAT so that the charger is in Pre-Charge - * state when not charging or discharging. - */ - rv = bd9995x_set_vsysreg(chgnum, bi->voltage_max + - BD9995X_VSYS_PRECHARGE_OFFSET_MV); - - /* - * Allow charger in pre-charge state for 50ms before disabling - * the charger which prevents inrush current while moving from - * fast-charge state to pre-charge state. - */ - msleep(50); - } - if (rv) - return rv; - - rv = ch_raw_read16(chgnum, BD9995X_CMD_CHGOP_SET2, ®, - BD9995X_EXTENDED_COMMAND); - if (rv) - return rv; - - if (enable) - reg |= BD9995X_CMD_CHGOP_SET2_CHG_EN; - else - reg &= ~BD9995X_CMD_CHGOP_SET2_CHG_EN; - - return ch_raw_write16(chgnum, BD9995X_CMD_CHGOP_SET2, reg, - BD9995X_EXTENDED_COMMAND); -} - -static int bd9995x_por_reset(int chgnum) -{ - int rv; - int reg; - int i; - - rv = ch_raw_write16(chgnum, BD9995X_CMD_SYSTEM_CTRL_SET, - BD9995X_CMD_SYSTEM_CTRL_SET_OTPLD | - BD9995X_CMD_SYSTEM_CTRL_SET_ALLRST, - BD9995X_EXTENDED_COMMAND); - if (rv) - return rv; - - /* Wait until OTPROM loading is finished */ - for (i = 0; i < OTPROM_LOAD_WAIT_RETRY; i++) { - msleep(10); - rv = ch_raw_read16(chgnum, BD9995X_CMD_SYSTEM_STATUS, ®, - BD9995X_EXTENDED_COMMAND); - - if (!rv && (reg & BD9995X_CMD_SYSTEM_STATUS_OTPLD_STATE) && - (reg & BD9995X_CMD_SYSTEM_STATUS_ALLRST_STATE)) - break; - } - - if (rv) - return rv; - if (i == OTPROM_LOAD_WAIT_RETRY) - return EC_ERROR_TIMEOUT; - - return ch_raw_write16(chgnum, BD9995X_CMD_SYSTEM_CTRL_SET, 0, - BD9995X_EXTENDED_COMMAND); -} - -static int bd9995x_reset_to_zero(int chgnum) -{ - int rv; - - rv = bd9995x_set_current(chgnum, 0); - if (rv) - return rv; - - return bd9995x_set_voltage(chgnum, 0); -} - -static int bd9995x_get_charger_op_status(int chgnum, int *status) -{ - return ch_raw_read16(chgnum, BD9995X_CMD_CHGOP_STATUS, status, - BD9995X_EXTENDED_COMMAND); -} - -#ifdef HAS_TASK_USB_CHG -static int bc12_detected_type[CONFIG_USB_PD_PORT_MAX_COUNT]; -/* Mutex for UCD_SET registers, lock before read / mask / write. */ -static struct mutex ucd_set_mutex[BD9995X_CHARGE_PORT_COUNT]; - -static int bd9995x_get_bc12_device_type(int chgnum, int port) -{ - int rv; - int reg; - - rv = ch_raw_read16(chgnum, (port == BD9995X_CHARGE_PORT_VBUS) ? - BD9995X_CMD_VBUS_UCD_STATUS : - BD9995X_CMD_VCC_UCD_STATUS, - ®, BD9995X_EXTENDED_COMMAND); - if (rv) - return CHARGE_SUPPLIER_NONE; - - switch (reg & BD9995X_TYPE_MASK) { - case BD9995X_TYPE_CDP: - return CHARGE_SUPPLIER_BC12_CDP; - case BD9995X_TYPE_DCP: - return CHARGE_SUPPLIER_BC12_DCP; - case BD9995X_TYPE_SDP: - return CHARGE_SUPPLIER_BC12_SDP; - case BD9995X_TYPE_PUP_PORT: - case BD9995X_TYPE_OTHER: - return CHARGE_SUPPLIER_OTHER; - case BD9995X_TYPE_OPEN_PORT: - case BD9995X_TYPE_VBUS_OPEN: - default: - return CHARGE_SUPPLIER_NONE; - } -} - -/* - * Do safe read / mask / write of BD9995X_CMD_*_UCD_SET register. - * The USB charger task owns all bits of this register, except for bit 0 - * (BD9995X_CMD_UCD_SET_USB_SW), which is controlled by - * usb_charger_set_switches(). - */ -static int bd9995x_update_ucd_set_reg(int chgnum, int port, uint16_t mask, - int set) -{ - int rv; - int reg; - int port_reg = (port == BD9995X_CHARGE_PORT_VBUS) ? - BD9995X_CMD_VBUS_UCD_SET : BD9995X_CMD_VCC_UCD_SET; - - mutex_lock(&ucd_set_mutex[port]); - rv = ch_raw_read16(chgnum, port_reg, ®, BD9995X_EXTENDED_COMMAND); - if (!rv) { - if (set) - reg |= mask; - else - reg &= ~mask; - - rv = ch_raw_write16(chgnum, port_reg, reg, - BD9995X_EXTENDED_COMMAND); - } - - mutex_unlock(&ucd_set_mutex[port]); - return rv; -} - -static int bd9995x_bc12_check_type(int chgnum, int port) -{ - int bc12_type; - struct charge_port_info charge; - int vbus_provided = bd9995x_is_vbus_provided(port) && - !usb_charger_port_is_sourcing_vbus(port); - - /* - * If vbus is no longer provided, then no need to continue. Return 0 so - * that a wait event is not scheduled. - */ - if (!vbus_provided) - return 0; - - /* get device type */ - bc12_type = bd9995x_get_bc12_device_type(chgnum, port); - if (bc12_type == CHARGE_SUPPLIER_NONE) - /* - * Device type is not available, return non-zero so new wait - * will be scheduled before putting the task to sleep. - */ - return 1; - - bc12_detected_type[port] = bc12_type; - /* Update charge manager */ - charge.voltage = USB_CHARGER_VOLTAGE_MV; - charge.current = bd9995x_get_bc12_ilim(bc12_type); - charge_manager_update_charge(bc12_type, port, &charge); - - return 0; -} - -static void bd9995x_bc12_detach(int chgnum, int port, int type) -{ - /* Update charge manager */ - charge_manager_update_charge(type, port, NULL); - - /* Disable charging trigger by BC1.2 detection */ - bd9995x_bc12_enable_charging(port, 0); -} - -static int bd9995x_enable_vbus_detect_interrupts(int chgnum, int port, - int enable) -{ - int reg; - int rv; - int port_reg; - int mask_val; - - /* 1st Level Interrupt Setting */ - rv = ch_raw_read16(chgnum, BD9995X_CMD_INT0_SET, ®, - BD9995X_EXTENDED_COMMAND); - if (rv) - return rv; - - mask_val = ((port == BD9995X_CHARGE_PORT_VBUS) ? - BD9995X_CMD_INT0_SET_INT1_EN : - BD9995X_CMD_INT0_SET_INT2_EN) | - BD9995X_CMD_INT0_SET_INT0_EN; - if (enable) - reg |= mask_val; - else - reg &= ~mask_val; - - rv = ch_raw_write16(chgnum, BD9995X_CMD_INT0_SET, reg, - BD9995X_EXTENDED_COMMAND); - if (rv) - return rv; - - /* 2nd Level Interrupt Setting */ - port_reg = (port == BD9995X_CHARGE_PORT_VBUS) ? - BD9995X_CMD_INT1_SET : BD9995X_CMD_INT2_SET; - rv = ch_raw_read16(chgnum, port_reg, ®, BD9995X_EXTENDED_COMMAND); - if (rv) - return rv; - - /* Enable threshold interrupts if we need to control discharge */ -#ifdef CONFIG_USB_PD_DISCHARGE - mask_val = BD9995X_CMD_INT_VBUS_DET | BD9995X_CMD_INT_VBUS_TH; -#else - mask_val = BD9995X_CMD_INT_VBUS_DET; -#endif - if (enable) - reg |= mask_val; - else - reg &= ~mask_val; - - return ch_raw_write16(chgnum, port_reg, reg, BD9995X_EXTENDED_COMMAND); -} - -/* Read + clear active interrupt bits for a given port */ -static int bd9995x_get_interrupts(int chgnum, int port) -{ - int rv; - int reg; - int port_reg; - - port_reg = (port == BD9995X_CHARGE_PORT_VBUS) ? - BD9995X_CMD_INT1_STATUS : BD9995X_CMD_INT2_STATUS; - - rv = ch_raw_read16(chgnum, port_reg, ®, BD9995X_EXTENDED_COMMAND); - - if (rv) - return 0; - - /* Clear the interrupt status bits we just read */ - ch_raw_write16(chgnum, port_reg, reg, BD9995X_EXTENDED_COMMAND); - - return reg; -} - -/* - * Set or clear registers necessary to do one-time BC1.2 detection. - * Pass enable = 1 to trigger BC1.2 detection, and enable = 0 once - * BC1.2 detection has completed. - */ -static int bd9995x_bc12_detect(int chgnum, int port, int enable) -{ - return bd9995x_update_ucd_set_reg(chgnum, port, - BD9995X_CMD_UCD_SET_BCSRETRY | - BD9995X_CMD_UCD_SET_USBDETEN | - BD9995X_CMD_UCD_SET_USB_SW_EN, - enable); -} - -static int usb_charger_process(int chgnum, int port) -{ - int vbus_provided = bd9995x_is_vbus_provided(port) && - !usb_charger_port_is_sourcing_vbus(port); - - /* Inform other modules about VBUS level */ - usb_charger_vbus_change(port, vbus_provided); - - /* - * Do BC1.2 detection, if we have VBUS and our port is not known - * to speak PD. - */ - if (vbus_provided && !pd_capable(port)) { - bd9995x_bc12_detect(chgnum, port, 1); - /* - * Need to give the charger time (~312 mSec) before the - * bc12_type is available. The main task loop will schedule a - * task wait event which will then call bd9995x_bc12_get_type. - */ - return 1; - } - - /* Reset BC1.2 regs so we don't do auto-detection. */ - bd9995x_bc12_detect(chgnum, port, 0); - - /* - * VBUS is no longer being provided, if the bc12_type had been - * previously determined, then need to detach. - */ - if (bc12_detected_type[port] != CHARGE_SUPPLIER_NONE) { - /* Charger/sink detached */ - bd9995x_bc12_detach(chgnum, port, bc12_detected_type[port]); - bc12_detected_type[port] = CHARGE_SUPPLIER_NONE; - } - /* No need for the task to schedule a wait event */ - return 0; -} - -#ifdef CONFIG_CHARGE_RAMP_SW -static int bd9995x_ramp_allowed(int supplier) -{ - return supplier == CHARGE_SUPPLIER_BC12_DCP || - supplier == CHARGE_SUPPLIER_BC12_SDP || - supplier == CHARGE_SUPPLIER_BC12_CDP || - supplier == CHARGE_SUPPLIER_OTHER; -} - -static int bd9995x_ramp_max(int supplier, int sup_curr) -{ - return bd9995x_get_bc12_ilim(supplier); -} -#endif /* CONFIG_CHARGE_RAMP_SW */ -#endif /* HAS_TASK_USB_CHG */ - -/* chip specific interfaces */ - -static enum ec_error_list bd9995x_set_input_current_limit(int chgnum, - int input_current) -{ - int rv; - - /* Input current step 32 mA */ - input_current &= ~0x1F; - - if (input_current < bd9995x_charger_info.input_current_min) - input_current = bd9995x_charger_info.input_current_min; - - rv = ch_raw_write16(chgnum, BD9995X_CMD_IBUS_LIM_SET, input_current, - BD9995X_BAT_CHG_COMMAND); - if (rv) - return rv; - - return ch_raw_write16(chgnum, BD9995X_CMD_ICC_LIM_SET, input_current, - BD9995X_BAT_CHG_COMMAND); -} - -static enum ec_error_list bd9995x_get_input_current_limit(int chgnum, - int *input_current) -{ - return ch_raw_read16(chgnum, BD9995X_CMD_CUR_ILIM_VAL, input_current, - BD9995X_EXTENDED_COMMAND); -} - -static enum ec_error_list bd9995x_manufacturer_id(int chgnum, int *id) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -static enum ec_error_list bd9995x_device_id(int chgnum, int *id) -{ - return ch_raw_read16(chgnum, BD9995X_CMD_CHIP_ID, id, - BD9995X_EXTENDED_COMMAND); -} - -static enum ec_error_list bd9995x_get_option(int chgnum, int *option) -{ - int rv; - int reg; - - rv = ch_raw_read16(chgnum, BD9995X_CMD_CHGOP_SET1, option, - BD9995X_EXTENDED_COMMAND); - if (rv) - return rv; - - rv = ch_raw_read16(chgnum, BD9995X_CMD_CHGOP_SET2, ®, - BD9995X_EXTENDED_COMMAND); - if (rv) - return rv; - - *option |= reg << 16; - - return EC_SUCCESS; -} - -static enum ec_error_list bd9995x_set_option(int chgnum, int option) -{ - int rv; - - rv = ch_raw_write16(chgnum, BD9995X_CMD_CHGOP_SET1, option & 0xFFFF, - BD9995X_EXTENDED_COMMAND); - if (rv) - return rv; - - return ch_raw_write16(chgnum, BD9995X_CMD_CHGOP_SET2, - (option >> 16) & 0xFFFF, - BD9995X_EXTENDED_COMMAND); -} - -/* Charger interfaces */ - -static const struct charger_info *bd9995x_get_info(int chgnum) -{ - return &bd9995x_charger_info; -} - -static enum ec_error_list bd9995x_get_status(int chgnum, int *status) -{ - int rv; - int reg; - int ch_status; - - /* charger level */ - *status = CHARGER_LEVEL_2; - - /* charger enable/inhibit */ - rv = ch_raw_read16(chgnum, BD9995X_CMD_CHGOP_SET2, ®, - BD9995X_EXTENDED_COMMAND); - if (rv) - return rv; - - if (!(reg & BD9995X_CMD_CHGOP_SET2_CHG_EN)) - *status |= CHARGER_CHARGE_INHIBITED; - - /* charger alarm enable/inhibit */ - rv = ch_raw_read16(chgnum, BD9995X_CMD_PROCHOT_CTRL_SET, ®, - BD9995X_EXTENDED_COMMAND); - if (rv) - return rv; - - if (!(reg & (BD9995X_CMD_PROCHOT_CTRL_SET_PROCHOT_EN4 | - BD9995X_CMD_PROCHOT_CTRL_SET_PROCHOT_EN3 | - BD9995X_CMD_PROCHOT_CTRL_SET_PROCHOT_EN2 | - BD9995X_CMD_PROCHOT_CTRL_SET_PROCHOT_EN1 | - BD9995X_CMD_PROCHOT_CTRL_SET_PROCHOT_EN0))) - *status |= CHARGER_ALARM_INHIBITED; - - rv = bd9995x_get_charger_op_status(chgnum, ®); - if (rv) - return rv; - - /* power fail */ - if (!(reg & BD9995X_CMD_CHGOP_STATUS_RBOOST_UV)) - *status |= CHARGER_POWER_FAIL; - - /* Safety signal ranges & battery presence */ - ch_status = (reg & BD9995X_BATTTEMP_MASK) >> 8; - - *status |= CHARGER_BATTERY_PRESENT; - - switch (ch_status) { - case BD9995X_CMD_CHGOP_STATUS_BATTEMP_COLD1: - *status |= CHARGER_RES_COLD; - break; - case BD9995X_CMD_CHGOP_STATUS_BATTEMP_COLD2: - *status |= CHARGER_RES_COLD; - *status |= CHARGER_RES_UR; - break; - case BD9995X_CMD_CHGOP_STATUS_BATTEMP_HOT1: - case BD9995X_CMD_CHGOP_STATUS_BATTEMP_HOT2: - *status |= CHARGER_RES_HOT; - break; - case BD9995X_CMD_CHGOP_STATUS_BATTEMP_HOT3: - *status |= CHARGER_RES_HOT; - *status |= CHARGER_RES_OR; - break; - case BD9995X_CMD_CHGOP_STATUS_BATTEMP_BATOPEN: - *status &= ~CHARGER_BATTERY_PRESENT; - default: - break; - } - - /* source of power */ - if (bd9995x_is_vbus_provided(BD9995X_CHARGE_PORT_BOTH)) - *status |= CHARGER_AC_PRESENT; - - return EC_SUCCESS; -} - -static enum ec_error_list bd9995x_set_mode(int chgnum, int mode) -{ - int rv; - - if (mode & CHARGE_FLAG_POR_RESET) { - rv = bd9995x_por_reset(chgnum); - if (rv) - return rv; - } - - if (mode & CHARGE_FLAG_RESET_TO_ZERO) { - rv = bd9995x_reset_to_zero(chgnum); - if (rv) - return rv; - } - - return EC_SUCCESS; -} - -static enum ec_error_list bd9995x_get_current(int chgnum, int *current) -{ - return ch_raw_read16(chgnum, BD9995X_CMD_CHG_CURRENT, current, - BD9995X_BAT_CHG_COMMAND); -} - -static enum ec_error_list bd9995x_set_current(int chgnum, int current) -{ - int rv; - int chg_enable = 1; - - /* Charge current step 64 mA */ - current &= ~0x3F; - - if (current < BD9995X_NO_BATTERY_CHARGE_I_MIN && - (battery_is_present() != BP_YES || battery_is_cut_off())) - current = BD9995X_NO_BATTERY_CHARGE_I_MIN; - - /* - * Disable charger before setting charge current to 0 or when - * discharging on AC. - * If charging current is set to 0mA during charging, reference of - * the charge current feedback amp (VREF_CHG) is set to 0V. Hence - * the DCDC stops switching (because of the EA offset). - */ - if (!current || bd9995x_is_discharging_on_ac(chgnum)) { - chg_enable = 0; - rv = bd9995x_charger_enable(chgnum, 0); - if (rv) - return rv; - } - - rv = ch_raw_write16(chgnum, BD9995X_CMD_IPRECH_SET, - MIN(current, BD9995X_IPRECH_MAX), - BD9995X_EXTENDED_COMMAND); - if (rv) - return rv; - - rv = ch_raw_write16(chgnum, BD9995X_CMD_CHG_CURRENT, current, - BD9995X_BAT_CHG_COMMAND); - if (rv) - return rv; - - /* - * Enable charger if charge current is non-zero or not discharging - * on AC. - */ - return chg_enable ? bd9995x_charger_enable(chgnum, 1) : EC_SUCCESS; -} - -static enum ec_error_list bd9995x_get_voltage(int chgnum, int *voltage) -{ - if (vsys_priority) { - int batt_volt_measured; - int reg; - int rv; - - /* Get battery voltage as reported by charger */ - batt_volt_measured = bd9995x_get_battery_voltage(); - if (batt_volt_measured > (battery_get_info()->voltage_min + - BD9995X_VSYS_PRECHARGE_OFFSET_MV)) { - /* - * Battery is not deeply discharged. Clear the - * VSYS_PRIORITY bit to ensure that input current limit - * is always active. - */ - mutex_lock(&bd9995x_vin_mutex); - if (!ch_raw_read16(chgnum, BD9995X_CMD_VIN_CTRL_SET, - ®, BD9995X_EXTENDED_COMMAND)) { - reg &= ~BD9995X_CMD_VIN_CTRL_SET_VSYS_PRIORITY; - rv = ch_raw_write16(chgnum, - BD9995X_CMD_VIN_CTRL_SET, - reg, - BD9995X_EXTENDED_COMMAND); - - /* Mirror the state of this bit */ - if (!rv) - vsys_priority = 0; - } - mutex_unlock(&bd9995x_vin_mutex); - } - } - - return ch_raw_read16(chgnum, BD9995X_CMD_CHG_VOLTAGE, voltage, - BD9995X_BAT_CHG_COMMAND); -} - -static enum ec_error_list bd9995x_set_voltage(int chgnum, int voltage) -{ - const int battery_voltage_max = battery_get_info()->voltage_max; - - /* - * Regulate the system voltage to battery max if the battery - * is not present or the battery is discharging on AC. - */ - if (voltage == 0 || - bd9995x_is_discharging_on_ac(chgnum) || - battery_is_present() != BP_YES || - battery_is_cut_off() || - voltage > battery_voltage_max) - voltage = battery_voltage_max; - - /* Charge voltage step 16 mV */ - voltage &= ~0x0F; - - /* Assumes charger's voltage_min < battery's voltage_max */ - if (voltage < bd9995x_charger_info.voltage_min) - voltage = bd9995x_charger_info.voltage_min; - - return bd9995x_set_vfastchg(chgnum, voltage); -} - -static void bd9995x_battery_charging_profile_settings(int chgnum) -{ - const struct battery_info *bi = battery_get_info(); - - /* Input Current Limit Setting */ - bd9995x_set_input_current_limit(chgnum, CONFIG_CHARGER_INPUT_CURRENT); - - /* Charge Termination Current Setting */ - ch_raw_write16(chgnum, BD9995X_CMD_ITERM_SET, 0, - BD9995X_EXTENDED_COMMAND); - - /* Trickle-charge Current Setting */ - ch_raw_write16(chgnum, BD9995X_CMD_ITRICH_SET, - bi->precharge_current & 0x07C0, - BD9995X_EXTENDED_COMMAND); - - bd9995x_set_vfastchg(chgnum, bi->voltage_max); - - /* Set Pre-charge Voltage Threshold for trickle charging. */ - ch_raw_write16(chgnum, BD9995X_CMD_VPRECHG_TH_SET, - (bi->voltage_min - 1000) & 0x7FC0, - BD9995X_EXTENDED_COMMAND); - - /* Re-charge Battery Voltage Setting */ - ch_raw_write16(chgnum, BD9995X_CMD_VRECHG_SET, - bi->voltage_max & 0x7FF0, - BD9995X_EXTENDED_COMMAND); - - /* Set battery OVP to 500 + maximum battery voltage */ - ch_raw_write16(chgnum, BD9995X_CMD_VBATOVP_SET, - (bi->voltage_max + 500) & 0x7ff0, - BD9995X_EXTENDED_COMMAND); - - /* Reverse buck boost voltage Setting */ - ch_raw_write16(chgnum, BD9995X_CMD_VRBOOST_SET, 0, - BD9995X_EXTENDED_COMMAND); - - /* Disable fast/pre-charging watchdog */ - ch_raw_write16(chgnum, BD9995X_CMD_CHGWDT_SET, 0, - BD9995X_EXTENDED_COMMAND); - - /* TODO(crosbug.com/p/55626): Set VSYSVAL_THH/THL appropriately */ -} - -/* - * Note: opting not to use charger driver init here due to the different - * priority (other drivers use HOOK_PRIO_INIT_I2C + 1) - */ -static void bd9995x_init(void) -{ - int reg; - - /* - * Disable charging trigger by BC1.2 on VCC & VBUS and - * automatic limitation of the input current. - */ - if (ch_raw_read16(CHARGER_SOLO, BD9995X_CMD_CHGOP_SET1, ®, - BD9995X_EXTENDED_COMMAND)) - return; - reg |= (BD9995X_CMD_CHGOP_SET1_SDP_CHG_TRIG_EN | - BD9995X_CMD_CHGOP_SET1_SDP_CHG_TRIG | - BD9995X_CMD_CHGOP_SET1_VBUS_BC_DISEN | - BD9995X_CMD_CHGOP_SET1_VCC_BC_DISEN | - BD9995X_CMD_CHGOP_SET1_ILIM_AUTO_DISEN | - BD9995X_CMD_CHGOP_SET1_SDP_500_SEL | - BD9995X_CMD_CHGOP_SET1_DCP_2500_SEL); - ch_raw_write16(CHARGER_SOLO, BD9995X_CMD_CHGOP_SET1, reg, - BD9995X_EXTENDED_COMMAND); - - /* - * OTP setting for this register is 6.08V. Set VSYS to above battery max - * (as is done when charger is disabled) to ensure VSYSREG_SET > VBAT so - * that the charger is in Pre-Charge state and that the input current - * disable setting below will be active. - */ - bd9995x_set_vsysreg(CHARGER_SOLO, battery_get_info()->voltage_max + - BD9995X_VSYS_PRECHARGE_OFFSET_MV); - - /* Enable BC1.2 USB charging and DC/DC converter @ 1200KHz */ - if (ch_raw_read16(CHARGER_SOLO, BD9995X_CMD_CHGOP_SET2, ®, - BD9995X_EXTENDED_COMMAND)) - return; - reg &= ~(BD9995X_CMD_CHGOP_SET2_USB_SUS | - BD9995X_CMD_CHGOP_SET2_DCDC_CLK_SEL); - reg |= BD9995X_CMD_CHGOP_SET2_DCDC_CLK_SEL_1200; -#ifdef CONFIG_CHARGER_BD9995X_CHGEN - reg |= BD9995X_CMD_CHGOP_SET2_CHG_EN; -#endif - ch_raw_write16(CHARGER_SOLO, BD9995X_CMD_CHGOP_SET2, reg, - BD9995X_EXTENDED_COMMAND); - - /* - * We disable IADP (here before setting IBUS_LIM_SET and ICC_LIM_SET) - * to prevent voltage on IADP/RESET pin from affecting SEL_ILIM_VAL. - */ - if (ch_raw_read16(CHARGER_SOLO, BD9995X_CMD_VM_CTRL_SET, ®, - BD9995X_EXTENDED_COMMAND)) - return; - reg &= ~BD9995X_CMD_VM_CTRL_SET_EXTIADPEN; - ch_raw_write16(CHARGER_SOLO, BD9995X_CMD_VM_CTRL_SET, reg, - BD9995X_EXTENDED_COMMAND); - /* - * Disable the input current limit when VBAT is < VSYSREG_SET. This - * needs to be done before calling - * bd9995x_battery_charging_profile_settings() as in that function the - * input current limit is set to CONFIG_CHARGER_INPUT_CURRENT which is - * 512 mA. In deeply discharged battery cases, setting the input current - * limit this low can cause VSYS to collapse, which in turn can cause - * the EC's brownout detector to reset the EC. - */ - if (ch_raw_read16(CHARGER_SOLO, BD9995X_CMD_VIN_CTRL_SET, ®, - BD9995X_EXTENDED_COMMAND)) - return; - reg |= BD9995X_CMD_VIN_CTRL_SET_VSYS_PRIORITY; - ch_raw_write16(CHARGER_SOLO, BD9995X_CMD_VIN_CTRL_SET, reg, - BD9995X_EXTENDED_COMMAND); - /* Mirror the state of this bit */ - vsys_priority = 1; - - /* Define battery charging profile */ - bd9995x_battery_charging_profile_settings(CHARGER_SOLO); - - /* Power save mode when VBUS/VCC is removed. */ -#ifdef CONFIG_BD9995X_POWER_SAVE_MODE - bd9995x_set_power_save_mode(CONFIG_BD9995X_POWER_SAVE_MODE); -#else - bd9995x_set_power_save_mode(BD9995X_PWR_SAVE_OFF); -#endif - -#ifdef CONFIG_USB_PD_DISCHARGE - /* Set VBUS / VCC detection threshold for discharge enable */ - ch_raw_write16(CHARGER_SOLO, BD9995X_CMD_VBUS_TH_SET, - BD9995X_VBUS_DISCHARGE_TH, BD9995X_EXTENDED_COMMAND); - ch_raw_write16(CHARGER_SOLO, BD9995X_CMD_VCC_TH_SET, - BD9995X_VBUS_DISCHARGE_TH, BD9995X_EXTENDED_COMMAND); -#endif - - /* Unlock debug regs */ - ch_raw_write16(CHARGER_SOLO, BD9995X_CMD_PROTECT_SET, 0x3c, - BD9995X_EXTENDED_COMMAND); - - /* Undocumented - reverse current threshold = -50mV */ - ch_raw_write16(CHARGER_SOLO, 0x14, 0x0202, BD9995X_DEBUG_COMMAND); - /* Undocumented - internal gain = 2x */ - ch_raw_write16(CHARGER_SOLO, 0x1a, 0x80, BD9995X_DEBUG_COMMAND); - - /* Re-lock debug regs */ - ch_raw_write16(CHARGER_SOLO, BD9995X_CMD_PROTECT_SET, 0x0, - BD9995X_EXTENDED_COMMAND); -} -DECLARE_HOOK(HOOK_INIT, bd9995x_init, HOOK_PRIO_INIT_EXTPOWER); - -static enum ec_error_list bd9995x_post_init(int chgnum) -{ - return EC_SUCCESS; -} - -static enum ec_error_list bd9995x_discharge_on_ac(int chgnum, int enable) -{ - int rv; - int reg; - - rv = ch_raw_read16(chgnum, BD9995X_CMD_CHGOP_SET2, ®, - BD9995X_EXTENDED_COMMAND); - if (rv) - return rv; - - /* - * Suspend USB charging and DC/DC converter so that BATT_LEARN mode - * doesn't auto exit if VBAT < VSYSVAL_THL_SET and also it helps to - * discharge VBUS quickly when charging is not allowed and the AC - * is removed. - */ - if (enable) - reg |= BD9995X_CMD_CHGOP_SET2_BATT_LEARN | - BD9995X_CMD_CHGOP_SET2_USB_SUS; - else - reg &= ~(BD9995X_CMD_CHGOP_SET2_BATT_LEARN | - BD9995X_CMD_CHGOP_SET2_USB_SUS); - - return ch_raw_write16(chgnum, BD9995X_CMD_CHGOP_SET2, reg, - BD9995X_EXTENDED_COMMAND); -} - -static enum ec_error_list bd9995x_get_vbus_voltage(int chgnum, int port, - int *voltage) -{ - uint8_t read_reg; - - read_reg = (port == BD9995X_CHARGE_PORT_VBUS) ? BD9995X_CMD_VBUS_VAL : - BD9995X_CMD_VCC_VAL; - - return ch_raw_read16(chgnum, read_reg, voltage, - BD9995X_EXTENDED_COMMAND); -} - -/*** Non-standard interface functions ***/ - -int bd9995x_is_vbus_provided(enum bd9995x_charge_port port) -{ - int reg; - - if (ch_raw_read16(CHARGER_SOLO, BD9995X_CMD_VBUS_VCC_STATUS, ®, - BD9995X_EXTENDED_COMMAND)) - return 0; - - if (port == BD9995X_CHARGE_PORT_VBUS) - reg &= BD9995X_CMD_VBUS_VCC_STATUS_VBUS_DETECT; - else if (port == BD9995X_CHARGE_PORT_VCC) - reg &= BD9995X_CMD_VBUS_VCC_STATUS_VCC_DETECT; - else if (port == BD9995X_CHARGE_PORT_BOTH) { - /* Check VBUS on either port */ - reg &= (BD9995X_CMD_VBUS_VCC_STATUS_VCC_DETECT | - BD9995X_CMD_VBUS_VCC_STATUS_VBUS_DETECT); - } else - reg = 0; - - return !!reg; -} - -#ifdef CONFIG_BD9995X_DELAY_INPUT_PORT_SELECT -static int bd9995x_select_input_port_private(enum bd9995x_charge_port port, - int select) -#else -int bd9995x_select_input_port(enum bd9995x_charge_port port, int select) -#endif -{ - int rv; - int reg; - - mutex_lock(&bd9995x_vin_mutex); - rv = ch_raw_read16(CHARGER_SOLO, BD9995X_CMD_VIN_CTRL_SET, ®, - BD9995X_EXTENDED_COMMAND); - if (rv) - goto select_input_port_exit; - - if (select) { - if (port == BD9995X_CHARGE_PORT_VBUS) { - reg |= BD9995X_CMD_VIN_CTRL_SET_VBUS_EN; - reg &= ~BD9995X_CMD_VIN_CTRL_SET_VCC_EN; - } else if (port == BD9995X_CHARGE_PORT_VCC) { - reg |= BD9995X_CMD_VIN_CTRL_SET_VCC_EN; - reg &= ~BD9995X_CMD_VIN_CTRL_SET_VBUS_EN; - } else if (port == BD9995X_CHARGE_PORT_BOTH) { - /* Enable both the ports for PG3 */ - reg |= BD9995X_CMD_VIN_CTRL_SET_VBUS_EN | - BD9995X_CMD_VIN_CTRL_SET_VCC_EN; - } else { - /* Invalid charge port */ - panic("Invalid charge port"); - } - } else { - if (port == BD9995X_CHARGE_PORT_VBUS) - reg &= ~BD9995X_CMD_VIN_CTRL_SET_VBUS_EN; - else if (port == BD9995X_CHARGE_PORT_VCC) - reg &= ~BD9995X_CMD_VIN_CTRL_SET_VCC_EN; - else if (port == BD9995X_CHARGE_PORT_BOTH) - reg &= ~(BD9995X_CMD_VIN_CTRL_SET_VBUS_EN | - BD9995X_CMD_VIN_CTRL_SET_VCC_EN); - else - panic("Invalid charge port"); - } - - rv = ch_raw_write16(CHARGER_SOLO, BD9995X_CMD_VIN_CTRL_SET, reg, - BD9995X_EXTENDED_COMMAND); -select_input_port_exit: - mutex_unlock(&bd9995x_vin_mutex); - return rv; -} - -#ifdef CONFIG_BD9995X_DELAY_INPUT_PORT_SELECT -int bd9995x_select_input_port(enum bd9995x_charge_port port, int select) -{ - port_update = port; - select_update = select; - vbus_state = START; - select_input_port_update = 1; - task_wake(TASK_ID_USB_CHG); - - return EC_SUCCESS; -} - -static inline int bd9995x_vbus_test(int value, int limit) -{ - uint32_t hi_value = limit + VBUS_DELTA; - uint32_t lo_value = limit - VBUS_DELTA; - - return ((value > lo_value) && (value < hi_value)); -} - -static int bd9995x_vbus_debounce(int chgnum, enum bd9995x_charge_port port) -{ - int vbus_reg; - int voltage; - - vbus_reg = (port == BD9995X_CHARGE_PORT_VBUS) ? - BD9995X_CMD_VBUS_VAL : BD9995X_CMD_VCC_VAL; - if (ch_raw_read16(chgnum, vbus_reg, &voltage, BD9995X_EXTENDED_COMMAND)) - voltage = 0; - - if (!bd9995x_vbus_test(voltage, vbus_voltage)) { - vbus_voltage = voltage; - debounce_time = get_time().val + VBUS_MSEC; - } else { - if (get_time().val >= debounce_time) - return 1; - } - - return 0; -} -#endif - - -#ifdef CONFIG_CHARGER_BATTERY_TSENSE -int bd9995x_get_battery_temp(int *temp_ptr) -{ - int rv; - - rv = ch_raw_read16(CHARGER_SOLO, BD9995X_CMD_THERM_VAL, temp_ptr, - BD9995X_EXTENDED_COMMAND); - if (rv) - return rv; - - /* Degrees C = 200 - THERM_VAL, range is -55C-200C, 1C steps */ - *temp_ptr = 200 - *temp_ptr; - return EC_SUCCESS; -} -#endif - -void bd9995x_set_power_save_mode(int mode) -{ - ch_raw_write16(CHARGER_SOLO, BD9995X_CMD_SMBREG, mode, - BD9995X_EXTENDED_COMMAND); -} - -int bd9995x_get_battery_voltage(void) -{ - int vbat_val, rv; - - rv = ch_raw_read16(CHARGER_SOLO, BD9995X_CMD_VBAT_VAL, &vbat_val, - BD9995X_EXTENDED_COMMAND); - - return rv ? 0 : vbat_val; -} - -#ifdef HAS_TASK_USB_CHG -int bd9995x_bc12_enable_charging(int port, int enable) -{ - int rv; - int reg; - int mask_val; - - /* - * For BC1.2, enable VBUS/VCC_BC_DISEN charging trigger by BC1.2 - * detection and disable SDP_CHG_TRIG, SDP_CHG_TRIG_EN. Vice versa - * for USB-C. - */ - rv = ch_raw_read16(CHARGER_SOLO, BD9995X_CMD_CHGOP_SET1, ®, - BD9995X_EXTENDED_COMMAND); - if (rv) - return rv; - - mask_val = (BD9995X_CMD_CHGOP_SET1_SDP_CHG_TRIG_EN | - BD9995X_CMD_CHGOP_SET1_SDP_CHG_TRIG | - ((port == BD9995X_CHARGE_PORT_VBUS) ? - BD9995X_CMD_CHGOP_SET1_VBUS_BC_DISEN : - BD9995X_CMD_CHGOP_SET1_VCC_BC_DISEN)); - - if (enable) - reg &= ~mask_val; - else - reg |= mask_val; - - return ch_raw_write16(CHARGER_SOLO, BD9995X_CMD_CHGOP_SET1, reg, - BD9995X_EXTENDED_COMMAND); -} - -static void bd9995x_set_switches(int port, enum usb_switch setting) -{ - /* If switch is not changing then return */ - if (setting == usb_switch_state[port]) - return; - - if (setting != USB_SWITCH_RESTORE) - usb_switch_state[port] = setting; - - /* ensure we disable power saving when we are using DP/DN */ -#ifdef CONFIG_BD9995X_POWER_SAVE_MODE - bd9995x_set_power_save_mode( - (usb_switch_state[0] == USB_SWITCH_DISCONNECT && - usb_switch_state[1] == USB_SWITCH_DISCONNECT) - ? CONFIG_BD9995X_POWER_SAVE_MODE : BD9995X_PWR_SAVE_OFF); -#endif - - bd9995x_update_ucd_set_reg(CHARGER_SOLO, port, - BD9995X_CMD_UCD_SET_USB_SW, - usb_switch_state[port] == USB_SWITCH_CONNECT); -} - -void bd9995x_vbus_interrupt(enum gpio_signal signal) -{ - task_wake(TASK_ID_USB_CHG); -} - -static void bd9995x_usb_charger_task(const int unused) -{ - static int initialized; - int changed, port, interrupts; - int sleep_usec; - uint64_t bc12_det_mark[CONFIG_USB_PD_PORT_MAX_COUNT]; -#ifdef CONFIG_USB_PD_DISCHARGE - int vbus_reg, voltage; -#endif - -#ifdef CONFIG_BD9995X_DELAY_INPUT_PORT_SELECT - select_input_port_update = 0; - vbus_voltage = 0; -#endif - - for (port = 0; port < board_get_usb_pd_port_count(); port++) { - bc12_detected_type[port] = CHARGE_SUPPLIER_NONE; - bd9995x_enable_vbus_detect_interrupts(CHARGER_SOLO, port, 1); - bc12_det_mark[port] = 0; - } - - while (1) { - sleep_usec = -1; - changed = 0; - for (port = 0; port < board_get_usb_pd_port_count(); port++) { - /* Get port interrupts */ - interrupts = bd9995x_get_interrupts(CHARGER_SOLO, port); - if (interrupts & BD9995X_CMD_INT_VBUS_DET || - !initialized) { - /* - * Detect based on current state of VBUS. If - * VBUS is provided, then need to wait for - * bc12_type to be available. If VBUS is not - * provided, then disable wait for this port. - */ - bc12_det_mark[port] = - usb_charger_process(CHARGER_SOLO, port) - ? get_time().val + BC12_DETECT_US : 0; - changed = 1; - } -#ifdef CONFIG_USB_PD_DISCHARGE - if (interrupts & BD9995X_CMD_INT_VBUS_TH || - !initialized) { - /* Get VBUS voltage */ - vbus_reg = (port == BD9995X_CHARGE_PORT_VBUS) ? - BD9995X_CMD_VBUS_VAL : - BD9995X_CMD_VCC_VAL; - if (ch_raw_read16(CHARGER_SOLO, vbus_reg, - &voltage, - BD9995X_EXTENDED_COMMAND)) - voltage = 0; - - /* Set discharge accordingly */ - pd_set_vbus_discharge(port, - voltage < BD9995X_VBUS_DISCHARGE_TH); - changed = 1; - } -#endif - if (bc12_det_mark[port] && (get_time().val > - bc12_det_mark[port])) { - /* - * bc12_type result should be available. If not - * available still, then function will return - * 1. Set up additional 100 msec wait. Note that - * if VBUS is no longer provided when this call - * happens the function will return 0. - */ - bc12_det_mark[port] = - bd9995x_bc12_check_type(CHARGER_SOLO, - port) ? - get_time().val + 100 * MSEC : 0; - /* Reset BC1.2 regs to skip auto-detection. */ - bd9995x_bc12_detect(CHARGER_SOLO, port, 0); - } - - /* - * Determine if a wait for reading bc12_type needs to be - * scheduled. Use the scheduled wait for this port if - * it's less than the wait needed for a previous - * port. If previous port(s) don't need a wait, then - * sleep_usec will be -1. - */ - if (bc12_det_mark[port]) { - int bc12_wait_usec; - - bc12_wait_usec = bc12_det_mark[port] - - get_time().val; - if ((sleep_usec < 0) || - (sleep_usec > bc12_wait_usec)) - sleep_usec = bc12_wait_usec; - } - } - - initialized = 1; -#ifdef CONFIG_BD9995X_DELAY_INPUT_PORT_SELECT -/* - * When a charge port is selected and VBUS is 5V, the inrush current on some - * devices causes VBUS to droop, which could signal a sink disconnection. - * - * To mitigate the problem, charge port selection is delayed until VBUS - * is stable or one second has passed. Hopefully PD has negotiated a VBUS - * voltage of at least 9V before the one second timeout. - */ - if (select_input_port_update) { - sleep_usec = VBUS_CHECK_MSEC; - changed = 0; - - switch (vbus_state) { - case START: - vbus_timeout = get_time().val + STABLE_TIMEOUT; - vbus_state = STABLE; - break; - case STABLE: - if (get_time().val > vbus_timeout) { - vbus_state = DEBOUNCE; - vbus_timeout = get_time().val + - DEBOUNCE_TIMEOUT; - } - break; - case DEBOUNCE: - if (bd9995x_vbus_debounce(CHARGER_SOLO, port_update) || - get_time().val > vbus_timeout) { - select_input_port_update = 0; - bd9995x_select_input_port_private( - port_update, select_update); - } - break; - } - } -#endif - - /* - * Re-read interrupt registers immediately if we got an - * interrupt. We're dealing with multiple independent - * interrupt sources and the interrupt pin may have - * never deasserted if both sources were not in clear - * state simultaneously. - */ - if (!changed) - task_wait_event(sleep_usec); - } -} -#endif /* HAS_TASK_USB_CHG */ - - -/*** Console commands ***/ -#ifdef CONFIG_CMD_CHARGER_DUMP -static int read_bat(int chgnum, uint8_t cmd) -{ - int read = 0; - - ch_raw_read16(chgnum, cmd, &read, BD9995X_BAT_CHG_COMMAND); - return read; -} - -static int read_ext(int chgnum, uint8_t cmd) -{ - int read = 0; - - ch_raw_read16(chgnum, cmd, &read, BD9995X_EXTENDED_COMMAND); - return read; -} - -/* Dump all readable registers on bd9995x */ -static int console_bd9995x_dump_regs(int argc, char **argv) -{ - int i; - uint8_t regs[] = { 0x14, 0x15, 0x3c, 0x3d, 0x3e, 0x3f }; - - /* Battery group registers */ - for (i = 0; i < ARRAY_SIZE(regs); ++i) - ccprintf("BAT REG %4x: %4x\n", regs[i], read_bat(CHARGER_SOLO, - regs[i])); - - /* Extended group registers */ - for (i = 0; i < 0x7f; ++i) { - ccprintf("EXT REG %4x: %4x\n", i, read_ext(CHARGER_SOLO, i)); - cflush(); - } - - return 0; -} -DECLARE_CONSOLE_COMMAND(charger_dump, console_bd9995x_dump_regs, - NULL, - "Dump all charger registers"); -#endif /* CONFIG_CMD_CHARGER_DUMP */ - -#ifdef CONFIG_CMD_CHARGER -static int console_command_bd9995x(int argc, char **argv) -{ - int rv, reg, data, val; - char rw, *e; - enum bd9995x_command cmd; - - if (argc < 4) - return EC_ERROR_PARAM_COUNT; - - rw = argv[1][0]; - if (rw == 'w' && argc < 5) - return EC_ERROR_PARAM_COUNT; - else if (rw != 'w' && rw != 'r') - return EC_ERROR_PARAM1; - - reg = strtoi(argv[2], &e, 16); - if (*e || reg < 0) - return EC_ERROR_PARAM2; - - cmd = strtoi(argv[3], &e, 0); - if (*e || cmd < 0) - return EC_ERROR_PARAM3; - - if (rw == 'r') - rv = ch_raw_read16(CHARGER_SOLO, reg, &data, cmd); - else { - val = strtoi(argv[4], &e, 16); - if (*e || val < 0) - return EC_ERROR_PARAM4; - - rv = ch_raw_write16(CHARGER_SOLO, reg, val, cmd); - if (rv == EC_SUCCESS) - rv = ch_raw_read16(CHARGER_SOLO, reg, &data, cmd); - } - - if (rv == EC_SUCCESS) - CPRINTS("register 0x%x [%d] = 0x%x [%d]", reg, reg, data, data); - - return rv; -} -DECLARE_CONSOLE_COMMAND(bd9995x, console_command_bd9995x, - "bd9995x <r/w> <reg_hex> <cmd_type> | <val_hex>", - "Read or write a charger register"); -#endif /* CONFIG_CMD_CHARGER */ - -#ifdef CONFIG_CHARGER_PSYS_READ -static int bd9995x_psys_charger_adc(int chgnum) -{ - int i; - int reg; - uint64_t ipmon = 0; - - for (i = 0; i < BD9995X_PMON_IOUT_ADC_READ_COUNT; i++) { - if (ch_raw_read16(chgnum, BD9995X_CMD_PMON_DACIN_VAL, ®, - BD9995X_EXTENDED_COMMAND)) - return 0; - - /* Conversion Interval is 200us */ - usleep(200); - ipmon += reg; - } - - /* - * Calculate power in mW - * PSYS = VACP×IACP+VBAT×IBAT = IPMON / GPMON - */ - return (int) ((ipmon * 1000) / (BIT(BD9995X_PSYS_GAIN_SELECT) * - BD9995X_PMON_IOUT_ADC_READ_COUNT)); -} - -static int bd9995x_enable_psys(int chgnum) -{ - int rv; - int reg; - - rv = ch_raw_read16(chgnum, BD9995X_CMD_PMON_IOUT_CTRL_SET, ®, - BD9995X_EXTENDED_COMMAND); - if (rv) - return rv; - - /* Enable PSYS & Select PSYS Gain */ - reg &= ~BD9995X_CMD_PMON_IOUT_CTRL_SET_PMON_GAIN_SET_MASK; - reg |= (BD9995X_CMD_PMON_IOUT_CTRL_SET_PMON_INSEL | - BD9995X_CMD_PMON_IOUT_CTRL_SET_PMON_OUT_EN | - BD9995X_PSYS_GAIN_SELECT); - - return ch_raw_write16(chgnum, BD9995X_CMD_PMON_IOUT_CTRL_SET, reg, - BD9995X_EXTENDED_COMMAND); -} - -/** - * Get system power. - * - * TODO(b:71520677): Implement charger_get_system_power, disable psys readout - * when not needed (the code below leaves it enabled after the first access), - * update "psys" console command to use charger_get_system_power and move it - * to some common code. - */ -static int console_command_psys(int argc, char **argv) -{ - int rv; - - rv = bd9995x_enable_psys(CHARGER_SOLO); - if (rv) - return rv; - - CPRINTS("PSYS from chg_adc: %d mW", - bd9995x_psys_charger_adc(CHARGER_SOLO)); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(psys, console_command_psys, - NULL, - "Get the system power in mW"); -#endif /* CONFIG_CHARGER_PSYS_READ */ - -#ifdef CONFIG_CMD_CHARGER_ADC_AMON_BMON -static int bd9995x_amon_bmon_chg_adc(int chgnum) -{ - int i; - int reg; - int iout = 0; - - for (i = 0; i < BD9995X_PMON_IOUT_ADC_READ_COUNT; i++) { - ch_raw_read16(chgnum, BD9995X_CMD_IOUT_DACIN_VAL, ®, - BD9995X_EXTENDED_COMMAND); - iout += reg; - - /* Conversion Interval is 200us */ - usleep(200); - } - - /* - * Discharge current in mA - * IDCHG = iout * GIDCHG - * IADP = iout * GIADP - * - * VIDCHG = GIDCHG * (VSRN- VSRP) = GIDCHG * IDCHG / IDCHG_RES - * VIADP = GIADP * (VACP- VACN) = GIADP * IADP / IADP_RES - */ - return (iout * (5 << BD9995X_IOUT_GAIN_SELECT)) / - (10 * BD9995X_PMON_IOUT_ADC_READ_COUNT); -} - -static int bd9995x_amon_bmon(int chgnum, int amon_bmon) -{ - int rv; - int reg; - int imon; - int sns_res; - - rv = ch_raw_read16(chgnum, BD9995X_CMD_PMON_IOUT_CTRL_SET, ®, - BD9995X_EXTENDED_COMMAND); - if (rv) - return rv; - - /* Enable monitor */ - reg &= ~BD9995X_CMD_PMON_IOUT_CTRL_SET_IOUT_GAIN_SET_MASK; - reg |= (BD9995X_CMD_PMON_IOUT_CTRL_SET_IMON_INSEL | - BD9995X_CMD_PMON_IOUT_CTRL_SET_IOUT_OUT_EN | - (BD9995X_IOUT_GAIN_SELECT << 4)); - - if (amon_bmon) { - reg |= BD9995X_CMD_PMON_IOUT_CTRL_SET_IOUT_SOURCE_SEL; - sns_res = CONFIG_CHARGER_SENSE_RESISTOR_AC; - } else { - reg &= ~BD9995X_CMD_PMON_IOUT_CTRL_SET_IOUT_SOURCE_SEL; - sns_res = CONFIG_CHARGER_SENSE_RESISTOR; - } - - rv = ch_raw_write16(chgnum, BD9995X_CMD_PMON_IOUT_CTRL_SET, reg, - BD9995X_EXTENDED_COMMAND); - if (rv) - return rv; - - imon = bd9995x_amon_bmon_chg_adc(chgnum); - - CPRINTS("%cMON from chg_adc: %d uV, %d mA]", - amon_bmon ? 'A' : 'B', - imon * sns_res, - imon); - - return EC_SUCCESS; -} - -/** - * Get charger AMON and BMON current. - */ -static int console_command_amon_bmon(int argc, char **argv) -{ - int rv = EC_ERROR_PARAM1; - - /* Switch to AMON */ - if (argc == 1 || (argc >= 2 && argv[1][0] == 'a')) - rv = bd9995x_amon_bmon(CHARGER_SOLO, 1); - - /* Switch to BMON */ - if (argc == 1 || (argc >= 2 && argv[1][0] == 'b')) - rv = bd9995x_amon_bmon(CHARGER_SOLO, 0); - - return rv; -} -DECLARE_CONSOLE_COMMAND(amonbmon, console_command_amon_bmon, - "amonbmon [a|b]", - "Get charger AMON/BMON voltage diff, current"); -#endif /* CONFIG_CMD_CHARGER_ADC_AMON_BMON */ - -#ifdef CONFIG_CMD_I2C_STRESS_TEST_CHARGER -static int bd9995x_i2c_read(const int reg, int *data) -{ - return ch_raw_read16(CHARGER_SOLO, reg, data, BD9995X_EXTENDED_COMMAND); -} - -static int bd9995x_i2c_write(const int reg, int data) -{ - return ch_raw_write16(CHARGER_SOLO, reg, data, - BD9995X_EXTENDED_COMMAND); -} - -/* BD9995X_CMD_CHIP_ID register value may vary by chip. */ -struct i2c_stress_test_dev bd9995x_i2c_stress_test_dev = { - .reg_info = { - .read_reg = BD9995X_CMD_CHIP_ID, - .read_val = BD99956_CHIP_ID, - .write_reg = BD9995X_CMD_ITRICH_SET, - }, - .i2c_read_dev = &bd9995x_i2c_read, - .i2c_write_dev = &bd9995x_i2c_write, -}; -#endif /* CONFIG_CMD_I2C_STRESS_TEST_CHARGER */ - -const struct charger_drv bd9995x_drv = { - .post_init = &bd9995x_post_init, - .get_info = &bd9995x_get_info, - .get_status = &bd9995x_get_status, - .set_mode = &bd9995x_set_mode, - .get_current = &bd9995x_get_current, - .set_current = &bd9995x_set_current, - .get_voltage = &bd9995x_get_voltage, - .set_voltage = &bd9995x_set_voltage, - .discharge_on_ac = &bd9995x_discharge_on_ac, - .get_vbus_voltage = &bd9995x_get_vbus_voltage, - .set_input_current_limit = &bd9995x_set_input_current_limit, - .get_input_current_limit = &bd9995x_get_input_current_limit, - .manufacturer_id = &bd9995x_manufacturer_id, - .device_id = &bd9995x_device_id, - .get_option = &bd9995x_get_option, - .set_option = &bd9995x_set_option, -}; - -#ifdef CONFIG_BC12_SINGLE_DRIVER -/* provide a default bc12_ports[] for backward compatibility */ -struct bc12_config bc12_ports[BD9995X_CHARGE_PORT_COUNT] = { - { - .drv = &(const struct bc12_drv) { - .usb_charger_task = bd9995x_usb_charger_task, - .set_switches = bd9995x_set_switches, -#if defined(CONFIG_CHARGE_RAMP_SW) - .ramp_allowed = bd9995x_ramp_allowed, - .ramp_max = bd9995x_ramp_max, -#endif /* CONFIG_CHARGE_RAMP_SW */ - }, - }, - { - .drv = &(const struct bc12_drv) { - /* bd9995x uses a single task thread for both ports */ - .usb_charger_task = NULL, - .set_switches = bd9995x_set_switches, -#if defined(CONFIG_CHARGE_RAMP_SW) - .ramp_allowed = bd9995x_ramp_allowed, - .ramp_max = bd9995x_ramp_max, -#endif /* CONFIG_CHARGE_RAMP_SW */ - }, - }, -}; -BUILD_ASSERT(ARRAY_SIZE(bc12_ports) == CHARGE_PORT_COUNT); -#else -/* - * TODO: - * This driver assumes its two ports is always on number 0 and 1. - * Prohibit multiple driver for safety. - */ -#error config not supported -#endif /* CONFIG_BC12_SINGLE_DRIVER */ diff --git a/driver/charger/bd9995x.h b/driver/charger/bd9995x.h deleted file mode 100644 index a1f1bdb64f..0000000000 --- a/driver/charger/bd9995x.h +++ /dev/null @@ -1,352 +0,0 @@ -/* Copyright 2016 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. - * - * ROHM BD9995X battery charger driver. - */ - -#ifndef __CROS_EC_BD9995X_H -#define __CROS_EC_BD9995X_H - -#define BD9995X_ADDR_FLAGS 0x09 - -#define BD9995X_CHARGER_NAME "bd9995x" -#define BD99955_CHIP_ID 0x221 -#define BD99956_CHIP_ID 0x331 - -/* BD9995X commands to change the command code map */ -enum bd9995x_command { - BD9995X_BAT_CHG_COMMAND, - BD9995X_EXTENDED_COMMAND, - BD9995X_DEBUG_COMMAND, - BD9995X_INVALID_COMMAND -}; - -/* - * BD9995X has two external VBUS inputs (named VBUS and VCC) and two sets - * of registers / bits for control. This entire driver is written under the - * assumption that the physical VBUS port corresponds to PD port 0, and the - * physical VCC port corresponds to PD port 1. - */ -enum bd9995x_charge_port { - BD9995X_CHARGE_PORT_VBUS, - BD9995X_CHARGE_PORT_VCC, - BD9995X_CHARGE_PORT_BOTH, -}; - -/* Min. charge current w/ no battery to prevent collapse */ -#define BD9995X_NO_BATTERY_CHARGE_I_MIN 512 - -/* - * BC1.2 minimum voltage threshold. - * BC1.2 charging port output voltage range is 4.75V to 5.25V, - * BD9995X Anti-Collapse Threshold Voltage Accuracy is -100mV to +100mV, - * and Delta of 50mV. - */ -#define BD9995X_BC12_MIN_VOLTAGE 4600 - -/* Battery Charger Commands */ -#define BD9995X_CMD_CHG_CURRENT 0x14 -#define BD9995X_CMD_CHG_VOLTAGE 0x15 -#define BD9995X_CMD_IBUS_LIM_SET 0x3C -#define BD9995X_CMD_ICC_LIM_SET 0x3D -#define BD9995X_CMD_PROTECT_SET 0x3E -#define BD9995X_CMD_MAP_SET 0x3F - -/* Extended commands */ -#define BD9995X_CMD_CHGSTM_STATUS 0x00 -#define BD9995X_CMD_VBAT_VSYS_STATUS 0x01 -#define BD9995X_CMD_VBUS_VCC_STATUS 0x02 -#define BD9995X_CMD_VBUS_VCC_STATUS_VCC_DETECT BIT(8) -#define BD9995X_CMD_VBUS_VCC_STATUS_VBUS_DETECT BIT(0) - -#define BD9995X_CMD_CHGOP_STATUS 0x03 -#define BD9995X_CMD_CHGOP_STATUS_BATTEMP2 BIT(10) -#define BD9995X_CMD_CHGOP_STATUS_BATTEMP1 BIT(9) -#define BD9995X_CMD_CHGOP_STATUS_BATTEMP0 BIT(8) -#define BD9995X_BATTTEMP_MASK 0x700 -#define BD9995X_CMD_CHGOP_STATUS_BATTEMP_ROOMTEMP 0 -#define BD9995X_CMD_CHGOP_STATUS_BATTEMP_HOT1 1 -#define BD9995X_CMD_CHGOP_STATUS_BATTEMP_HOT2 2 -#define BD9995X_CMD_CHGOP_STATUS_BATTEMP_HOT3 3 -#define BD9995X_CMD_CHGOP_STATUS_BATTEMP_COLD1 4 -#define BD9995X_CMD_CHGOP_STATUS_BATTEMP_COLD2 5 -#define BD9995X_CMD_CHGOP_STATUS_BATTEMP_DISABLE 6 -#define BD9995X_CMD_CHGOP_STATUS_BATTEMP_BATOPEN 7 -#define BD9995X_CMD_CHGOP_STATUS_RBOOST_UV BIT(1) - -#define BD9995X_CMD_WDT_STATUS 0x04 -#define BD9995X_CMD_CUR_ILIM_VAL 0x05 -#define BD9995X_CMD_SEL_ILIM_VAL 0x06 -#define BD9995X_CMD_EXT_IBUS_LIM_SET 0x07 -#define BD9995X_CMD_EXT_ICC_LIM_SET 0x08 -#define BD9995X_CMD_IOTG_LIM_SET 0x09 -#define BD9995X_CMD_VIN_CTRL_SET 0x0A -#define BD9995X_CMD_VIN_CTRL_SET_VSYS_PRIORITY BIT(4) - -#define BD9995X_CMD_VIN_CTRL_SET_PP_BOTH_THRU BIT(11) -#define BD9995X_CMD_VIN_CTRL_SET_VBUS_PRIORITY BIT(7) -#define BD9995X_CMD_VIN_CTRL_SET_VBUS_EN BIT(6) -#define BD9995X_CMD_VIN_CTRL_SET_VCC_EN BIT(5) - -#define BD9995X_CMD_CHGOP_SET1 0x0B -#define BD9995X_CMD_CHGOP_SET1_DCP_2500_SEL BIT(15) -#define BD9995X_CMD_CHGOP_SET1_SDP_500_SEL BIT(14) -#define BD9995X_CMD_CHGOP_SET1_ILIM_AUTO_DISEN BIT(13) -#define BD9995X_CMD_CHGOP_SET1_VCC_BC_DISEN BIT(11) -#define BD9995X_CMD_CHGOP_SET1_VBUS_BC_DISEN BIT(10) -#define BD9995X_CMD_CHGOP_SET1_SDP_CHG_TRIG_EN BIT(9) -#define BD9995X_CMD_CHGOP_SET1_SDP_CHG_TRIG BIT(8) - -#define BD9995X_CMD_CHGOP_SET2 0x0C -#define BD9995X_CMD_CHGOP_SET2_BATT_LEARN BIT(8) -#define BD9995X_CMD_CHGOP_SET2_CHG_EN BIT(7) -#define BD9995X_CMD_CHGOP_SET2_USB_SUS BIT(6) -#define BD9995X_CMD_CHGOP_SET2_DCDC_CLK_SEL (3 << 2) -#define BD9995X_CMD_CHGOP_SET2_DCDC_CLK_SEL_600 (0 << 2) -#define BD9995X_CMD_CHGOP_SET2_DCDC_CLK_SEL_857 BIT(2) -#define BD9995X_CMD_CHGOP_SET2_DCDC_CLK_SEL_1000 (2 << 2) -#define BD9995X_CMD_CHGOP_SET2_DCDC_CLK_SEL_1200 (3 << 2) - -#define BD9995X_CMD_VBUSCLPS_TH_SET 0x0D -#define BD9995X_CMD_VCCCLPS_TH_SET 0x0E -#define BD9995X_CMD_CHGWDT_SET 0x0F -#define BD9995X_CMD_BATTWDT_SET 0x10 -#define BD9995X_CMD_VSYSREG_SET 0x11 -#define BD9995X_CMD_VSYSVAL_THH_SET 0x12 -#define BD9995X_CMD_VSYSVAL_THL_SET 0x13 -#define BD9995X_CMD_ITRICH_SET 0x14 - -#define BD9995X_CMD_IPRECH_SET 0x15 -#define BD9995X_IPRECH_MAX 1024 - -#define BD9995X_CMD_ICHG_SET 0x16 -#define BD9995X_CMD_ITERM_SET 0x17 -#define BD9995X_CMD_VPRECHG_TH_SET 0x18 -#define BD9995X_CMD_VRBOOST_SET 0x19 -#define BD9995X_CMD_VFASTCHG_REG_SET1 0x1A -#define BD9995X_CMD_VFASTCHG_REG_SET2 0x1B -#define BD9995X_CMD_VFASTCHG_REG_SET3 0x1C -#define BD9995X_CMD_VRECHG_SET 0x1D -#define BD9995X_CMD_VBATOVP_SET 0x1E -#define BD9995X_CMD_IBATSHORT_SET 0x1F -#define BD9995X_CMD_PROCHOT_CTRL_SET 0x20 -#define BD9995X_CMD_PROCHOT_CTRL_SET_PROCHOT_EN4 BIT(4) -#define BD9995X_CMD_PROCHOT_CTRL_SET_PROCHOT_EN3 BIT(3) -#define BD9995X_CMD_PROCHOT_CTRL_SET_PROCHOT_EN2 BIT(2) -#define BD9995X_CMD_PROCHOT_CTRL_SET_PROCHOT_EN1 BIT(1) -#define BD9995X_CMD_PROCHOT_CTRL_SET_PROCHOT_EN0 BIT(0) - -#define BD9995X_CMD_PROCHOT_ICRIT_SET 0x21 -#define BD9995X_CMD_PROCHOT_INORM_SET 0x22 -#define BD9995X_CMD_PROCHOT_IDCHG_SET 0x23 -#define BD9995X_CMD_PROCHOT_VSYS_SET 0x24 -#define BD9995X_CMD_PMON_IOUT_CTRL_SET 0x25 -#define BD9995X_CMD_PMON_IOUT_CTRL_SET_IMON_INSEL BIT(9) -#define BD9995X_CMD_PMON_IOUT_CTRL_SET_PMON_INSEL BIT(8) -#define BD9995X_CMD_PMON_IOUT_CTRL_SET_IOUT_OUT_EN BIT(7) -#define BD9995X_CMD_PMON_IOUT_CTRL_SET_IOUT_SOURCE_SEL BIT(6) -#define BD9995X_CMD_PMON_IOUT_CTRL_SET_IOUT_GAIN_SET_MASK 0x30 -#define BD9995X_CMD_PMON_IOUT_CTRL_SET_IOUT_GAIN_SET_40V 0x03 -#define BD9995X_CMD_PMON_IOUT_CTRL_SET_IOUT_GAIN_SET_20V 0x02 -#define BD9995X_CMD_PMON_IOUT_CTRL_SET_IOUT_GAIN_SET_10V 0x01 -#define BD9995X_CMD_PMON_IOUT_CTRL_SET_IOUT_GAIN_SET_05V 0x00 -#define BD9995X_CMD_PMON_IOUT_CTRL_SET_PMON_OUT_EN BIT(3) -#define BD9995X_CMD_PMON_IOUT_CTRL_SET_PMON_GAIN_SET_MASK 0x07 -#define BD9995X_CMD_PMON_IOUT_CTRL_SET_PMON_GAIN_SET_64UAW 0x06 -#define BD9995X_CMD_PMON_IOUT_CTRL_SET_PMON_GAIN_SET_32UAW 0x05 -#define BD9995X_CMD_PMON_IOUT_CTRL_SET_PMON_GAIN_SET_16UAW 0x04 -#define BD9995X_CMD_PMON_IOUT_CTRL_SET_PMON_GAIN_SET_08UAW 0x03 -#define BD9995X_CMD_PMON_IOUT_CTRL_SET_PMON_GAIN_SET_04UAW 0x02 -#define BD9995X_CMD_PMON_IOUT_CTRL_SET_PMON_GAIN_SET_02UAW 0x01 -#define BD9995X_CMD_PMON_IOUT_CTRL_SET_PMON_GAIN_SET_01UAW 0x00 -#define BD9995X_PMON_IOUT_ADC_READ_COUNT 128 - -#define BD9995X_CMD_PMON_DACIN_VAL 0x26 -#define BD9995X_CMD_IOUT_DACIN_VAL 0x27 -#define BD9995X_CMD_VCC_UCD_SET 0x28 -/* Bits for both VCC_UCD_SET and VBUS_UCD_SET regs */ -/* Retry BC1.2 detection on set */ -#define BD9995X_CMD_UCD_SET_BCSRETRY BIT(12) -/* Enable BC1.2 detection, will automatically occur on VBUS detect */ -#define BD9995X_CMD_UCD_SET_USBDETEN BIT(7) -/* USB switch state auto-control */ -#define BD9995X_CMD_UCD_SET_USB_SW_EN BIT(1) -/* USB switch state, 1 = ON, only meaningful when USB_SW_EN = 0 */ -#define BD9995X_CMD_UCD_SET_USB_SW BIT(0) - -#define BD9995X_CMD_VCC_UCD_STATUS 0x29 -/* Bits for both VCC_UCD_STATUS and VBUS_UCD_STATUS regs */ -#define BD9995X_CMD_UCD_STATUS_DCDFAIL BIT(15) -#define BD9995X_CMD_UCD_STATUS_CHGPORT1 BIT(13) -#define BD9995X_CMD_UCD_STATUS_CHGPORT0 BIT(12) -#define BD9995X_CMD_UCD_STATUS_PUPDET BIT(11) -#define BD9995X_CMD_UCD_STATUS_CHGDET BIT(6) -#define BD9995X_TYPE_MASK (BD9995X_CMD_UCD_STATUS_DCDFAIL | \ - BD9995X_CMD_UCD_STATUS_CHGPORT1 | \ - BD9995X_CMD_UCD_STATUS_CHGPORT0 | \ - BD9995X_CMD_UCD_STATUS_PUPDET | \ - BD9995X_CMD_UCD_STATUS_CHGDET) - -/* BC1.2 chargers */ -#define BD9995X_TYPE_CDP (BD9995X_CMD_UCD_STATUS_CHGPORT1 | \ - BD9995X_CMD_UCD_STATUS_CHGDET) -#define BD9995X_TYPE_DCP (BD9995X_CMD_UCD_STATUS_CHGPORT1 | \ - BD9995X_CMD_UCD_STATUS_CHGPORT0 | \ - BD9995X_CMD_UCD_STATUS_CHGDET) -#define BD9995X_TYPE_SDP (BD9995X_CMD_UCD_STATUS_CHGPORT0) -/* non-standard BC1.2 chargers */ -#define BD9995X_TYPE_OTHER (BD9995X_CMD_UCD_STATUS_DCDFAIL | \ - BD9995X_CMD_UCD_STATUS_CHGPORT1 | \ - BD9995X_CMD_UCD_STATUS_CHGPORT0 | \ - BD9995X_CMD_UCD_STATUS_CHGDET) -#define BD9995X_TYPE_PUP_PORT (BD9995X_CMD_UCD_STATUS_DCDFAIL | \ - BD9995X_CMD_UCD_STATUS_CHGPORT0 | \ - BD9995X_CMD_UCD_STATUS_PUPDET) -/* Open ports */ -#define BD9995X_TYPE_OPEN_PORT (BD9995X_CMD_UCD_STATUS_DCDFAIL | \ - BD9995X_CMD_UCD_STATUS_CHGPORT0) -#define BD9995X_TYPE_VBUS_OPEN 0 - -#define BD9995X_CMD_VCC_IDD_STATUS 0x2A -#define BD9995X_CMD_VCC_UCD_FCTRL_SET 0x2B -#define BD9995X_CMD_VCC_UCD_FCTRL_EN 0x2C -#define BD9995X_CMD_VBUS_UCD_SET 0x30 -#define BD9995X_CMD_VBUS_UCD_STATUS 0x31 -#define BD9995X_CMD_VBUS_IDD_STATUS 0x32 -#define BD9995X_CMD_VBUS_UCD_FCTRL_SET 0x33 -#define BD9995X_CMD_VBUS_UCD_FCTRL_EN 0x34 -#define BD9995X_CMD_CHIP_ID 0x38 -#define BD9995X_CMD_CHIP_REV 0x39 -#define BD9995X_CMD_IC_SET1 0x3A -#define BD9995X_CMD_IC_SET2 0x3B -#define BD9995X_CMD_SYSTEM_STATUS 0x3C -#define BD9995X_CMD_SYSTEM_STATUS_OTPLD_STATE BIT(1) -#define BD9995X_CMD_SYSTEM_STATUS_ALLRST_STATE BIT(0) - -#define BD9995X_CMD_SYSTEM_CTRL_SET 0x3D -#define BD9995X_CMD_SYSTEM_CTRL_SET_OTPLD BIT(1) -#define BD9995X_CMD_SYSTEM_CTRL_SET_ALLRST BIT(0) - -#define BD9995X_CMD_EXT_PROTECT_SET 0x3E -#define BD9995X_CMD_EXT_MAP_SET 0x3F -#define BD9995X_CMD_VM_CTRL_SET 0x40 -#define BD9995X_CMD_VM_CTRL_SET_EXTIADPEN BIT(9) -#define BD9995X_CMD_THERM_WINDOW_SET1 0x41 -#define BD9995X_CMD_THERM_WINDOW_SET2 0x42 -#define BD9995X_CMD_THERM_WINDOW_SET3 0x43 -#define BD9995X_CMD_THERM_WINDOW_SET4 0x44 -#define BD9995X_CMD_THERM_WINDOW_SET5 0x45 -#define BD9995X_CMD_IBATP_TH_SET 0x46 -#define BD9995X_CMD_IBATM_TH_SET 0x47 -#define BD9995X_CMD_VBAT_TH_SET 0x48 -#define BD9995X_CMD_THERM_TH_SET 0x49 -#define BD9995X_CMD_IACP_TH_SET 0x4A -#define BD9995X_CMD_VACP_TH_SET 0x4B - -/* Enable discharge when VBUS falls below BD9995X_VBUS_DISCHARGE_TH */ -#define BD9995X_VBUS_DISCHARGE_TH 3900 -#define BD9995X_CMD_VBUS_TH_SET 0x4C -#define BD9995X_CMD_VCC_TH_SET 0x4D - -#define BD9995X_CMD_VSYS_TH_SET 0x4E -#define BD9995X_CMD_EXTIADP_TH_SET 0x4F -#define BD9995X_CMD_IBATP_VAL 0x50 -#define BD9995X_CMD_IBATP_AVE_VAL 0x51 -#define BD9995X_CMD_IBATM_VAL 0x52 -#define BD9995X_CMD_IBATM_AVE_VAL 0x53 -#define BD9995X_CMD_VBAT_VAL 0x54 -#define BD9995X_CMD_VBAT_AVE_VAL 0x55 -#define BD9995X_CMD_THERM_VAL 0x56 -#define BD9995X_CMD_VTH_VAL 0x57 -#define BD9995X_CMD_IACP_VAL 0x58 -#define BD9995X_CMD_IACP_AVE_VAL 0x59 -#define BD9995X_CMD_VACP_VAL 0x5A -#define BD9995X_CMD_VACP_AVE_VAL 0x5B -#define BD9995X_CMD_VBUS_VAL 0x5C -#define BD9995X_CMD_VBUS_AVE_VAL 0x5D -#define BD9995X_CMD_VCC_VAL 0x5E -#define BD9995X_CMD_VCC_AVE_VAL 0x5F -#define BD9995X_CMD_VSYS_VAL 0x60 -#define BD9995X_CMD_VSYS_AVE_VAL 0x61 -#define BD9995X_CMD_EXTIADP_VAL 0x62 -#define BD9995X_CMD_EXTIADP_AVE_VAL 0x63 -#define BD9995X_CMD_VACPCLPS_TH_SET 0x64 -#define BD9995X_CMD_INT0_SET 0x68 -#define BD9995X_CMD_INT0_SET_INT2_EN BIT(2) -#define BD9995X_CMD_INT0_SET_INT1_EN BIT(1) -#define BD9995X_CMD_INT0_SET_INT0_EN BIT(0) - -#define BD9995X_CMD_INT1_SET 0x69 -/* Bits for both INT1 & INT2 reg */ -#define BD9995X_CMD_INT_SET_TH_DET BIT(9) -#define BD9995X_CMD_INT_SET_TH_RES BIT(8) -#define BD9995X_CMD_INT_SET_DET BIT(1) -#define BD9995X_CMD_INT_SET_RES BIT(0) -#define BD9995X_CMD_INT_VBUS_DET (BD9995X_CMD_INT_SET_RES | \ - BD9995X_CMD_INT_SET_DET) -#define BD9995X_CMD_INT_VBUS_TH (BD9995X_CMD_INT_SET_TH_RES | \ - BD9995X_CMD_INT_SET_TH_DET) - -#define BD9995X_CMD_INT2_SET 0x6A -#define BD9995X_CMD_INT3_SET 0x6B -#define BD9995X_CMD_INT4_SET 0x6C -#define BD9995X_CMD_INT5_SET 0x6D -#define BD9995X_CMD_INT6_SET 0x6E -#define BD9995X_CMD_INT7_SET 0x6F -#define BD9995X_CMD_INT0_STATUS 0x70 -#define BD9995X_CMD_INT1_STATUS 0x71 -/* Bits for both INT1_STATUS & INT2_STATUS reg */ -#define BD9995X_CMD_INT_STATUS_DET BIT(1) -#define BD9995X_CMD_INT_STATUS_RES BIT(0) - -#define BD9995X_CMD_INT2_STATUS 0x72 -#define BD9995X_CMD_INT3_STATUS 0x73 -#define BD9995X_CMD_INT4_STATUS 0x74 -#define BD9995X_CMD_INT5_STATUS 0x75 -#define BD9995X_CMD_INT6_STATUS 0x76 -#define BD9995X_CMD_INT7_STATUS 0x77 -#define BD9995X_CMD_REG0 0x78 -#define BD9995X_CMD_REG1 0x79 -#define BD9995X_CMD_OTPREG0 0x7A -#define BD9995X_CMD_OTPREG1 0x7B -#define BD9995X_CMD_SMBREG 0x7C -/* Normal functionality - power save mode disabled. */ -#define BD9995X_PWR_SAVE_OFF 0 -/* BGATE ON w/ PROCHOT# monitored only system voltage. */ -#define BD9995X_PWR_SAVE_LOW 0x1 -/* BGATE ON w/ PROCHOT# monitored only system voltage every 1ms. */ -#define BD9995X_PWR_SAVE_MED 0x2 -/* BGATE ON w/o PROCHOT# monitoring. */ -#define BD9995X_PWR_SAVE_HIGH 0x5 -/* BGATE OFF */ -#define BD9995X_PWR_SAVE_MAX 0x6 -#define BD9995X_CMD_DEBUG_MODE_SET 0x7F - -/* - * Non-standard interface functions - bd9995x integrates additional - * functionality not part of the standard charger interface. - */ - -/* Is VBUS provided or external power present */ -int bd9995x_is_vbus_provided(enum bd9995x_charge_port port); -/* Select or deselect input port from {VCC, VBUS, VCC&VBUS}. */ -int bd9995x_select_input_port(enum bd9995x_charge_port port, int select); -/* Enable/Disable charging triggered by BC1.2 */ -int bd9995x_bc12_enable_charging(int port, int enable); -/* Interrupt handler for USB charger VBUS */ -void bd9995x_vbus_interrupt(enum gpio_signal signal); -/* Read temperature measurement value (in Celsius) */ -int bd9995x_get_battery_temp(int *temp_ptr); -/* Set power save mode */ -void bd9995x_set_power_save_mode(int mode); -/* Get Battery Voltage Measurement Value */ -int bd9995x_get_battery_voltage(void); - -#ifdef CONFIG_CMD_I2C_STRESS_TEST_CHARGER -extern struct i2c_stress_test_dev bd9995x_i2c_stress_test_dev; -#endif - -extern const struct charger_drv bd9995x_drv; - -#endif /* __CROS_EC_BD9995X_H */ diff --git a/driver/charger/bq24715.c b/driver/charger/bq24715.c deleted file mode 100644 index d2eb0e432a..0000000000 --- a/driver/charger/bq24715.c +++ /dev/null @@ -1,252 +0,0 @@ -/* Copyright 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. - * - * TI bq24715 battery charger driver. - */ - -#include "battery_smart.h" -#include "bq24715.h" -#include "charger.h" -#include "console.h" -#include "common.h" -#include "i2c.h" -#include "util.h" - -/* Sense resistor configurations and macros */ -#define DEFAULT_SENSE_RESISTOR 10 -#define R_SNS CONFIG_CHARGER_SENSE_RESISTOR -#define R_AC CONFIG_CHARGER_SENSE_RESISTOR_AC -#define REG_TO_CURRENT(REG, RS) ((REG) * DEFAULT_SENSE_RESISTOR / (RS)) -#define CURRENT_TO_REG(CUR, RS) ((CUR) * (RS) / DEFAULT_SENSE_RESISTOR) - -/* Note: it is assumed that the sense resistors are 10mOhm. */ - -static const struct charger_info bq24715_charger_info = { - .name = "bq24715", - .voltage_max = CHARGE_V_MAX, - .voltage_min = CHARGE_V_MIN, - .voltage_step = CHARGE_V_STEP, - .current_max = REG_TO_CURRENT(CHARGE_I_MAX, R_SNS), - .current_min = REG_TO_CURRENT(CHARGE_I_MIN, R_SNS), - .current_step = REG_TO_CURRENT(CHARGE_I_STEP, R_SNS), - .input_current_max = REG_TO_CURRENT(INPUT_I_MAX, R_AC), - .input_current_min = REG_TO_CURRENT(INPUT_I_MIN, R_AC), - .input_current_step = REG_TO_CURRENT(INPUT_I_STEP, R_AC), -}; - -static inline enum ec_error_list sbc_read(int chgnum, int cmd, int *param) -{ - return i2c_read16(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, - cmd, param); -} - -static inline enum ec_error_list sbc_write(int chgnum, int cmd, int param) -{ - return i2c_write16(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, - cmd, param); -} - -static enum ec_error_list bq24715_set_input_current_limit(int chgnum, - int input_current) -{ - return sbc_write(chgnum, BQ24715_INPUT_CURRENT, - CURRENT_TO_REG(input_current, R_AC)); -} - -static enum ec_error_list bq24715_get_input_current_limit(int chgnum, - int *input_current) -{ - int rv; - int reg; - - rv = sbc_read(chgnum, BQ24715_INPUT_CURRENT, ®); - if (rv) - return rv; - - *input_current = REG_TO_CURRENT(reg, R_AC); - - return EC_SUCCESS; -} - -static enum ec_error_list bq24715_manufacturer_id(int chgnum, int *id) -{ - return sbc_read(chgnum, BQ24715_MANUFACTURER_ID, id); -} - -static enum ec_error_list bq24715_device_id(int chgnum, int *id) -{ - return sbc_read(chgnum, BQ24715_DEVICE_ID, id); -} - -static enum ec_error_list bq24715_get_option(int chgnum, int *option) -{ - return sbc_read(chgnum, BQ24715_CHARGE_OPTION, option); -} - -static enum ec_error_list bq24715_set_option(int chgnum, int option) -{ - return sbc_write(chgnum, BQ24715_CHARGE_OPTION, option); -} - -/* Charger interfaces */ - -static const struct charger_info *bq24715_get_info(int chgnum) -{ - return &bq24715_charger_info; -} - -static enum ec_error_list bq24715_get_status(int chgnum, int *status) -{ - int rv; - int option; - - rv = bq24715_get_option(chgnum, &option); - if (rv) - return rv; - - /* Default status */ - *status = CHARGER_LEVEL_2; - - if ((option & OPT_CHARGE_INHIBIT_MASK) == OPT_CHARGE_DISABLE) - *status |= CHARGER_CHARGE_INHIBITED; - - return EC_SUCCESS; -} - -static enum ec_error_list bq24715_set_mode(int chgnum, int mode) -{ - int rv; - int option; - - rv = bq24715_get_option(chgnum, &option); - if (rv) - return rv; - - option &= ~OPT_CHARGE_INHIBIT_MASK; - if (mode & CHARGE_FLAG_INHIBIT_CHARGE) - option |= OPT_CHARGE_DISABLE; - else - option |= OPT_CHARGE_ENABLE; - return bq24715_set_option(chgnum, option); -} - -static enum ec_error_list bq24715_get_current(int chgnum, int *current) -{ - int rv; - int reg; - - rv = sbc_read(chgnum, SB_CHARGING_CURRENT, ®); - if (rv) - return rv; - - *current = REG_TO_CURRENT(reg, R_SNS); - return EC_SUCCESS; -} - -static enum ec_error_list bq24715_set_current(int chgnum, int current) -{ - current = charger_closest_current(current); - - return sbc_write(chgnum, SB_CHARGING_CURRENT, - CURRENT_TO_REG(current, R_SNS)); -} - -/* The voltage setting needs to be cached to work with the current - * charging infrastructure and state machine. The reason is that - * the state machine expects to be able to set a 0V charging voltage. - * The bq24715 does not allow this in the hardware register. Therefore - * 0V is handled specially to appease the state machine. */ -static int cached_voltage; - -static enum ec_error_list bq24715_get_voltage(int chgnum, int *voltage) -{ - int ret; - - if (cached_voltage == 0) { - *voltage = cached_voltage; - return EC_SUCCESS; - } - - ret = sbc_read(chgnum, SB_CHARGING_VOLTAGE, &cached_voltage); - - if (ret == EC_SUCCESS) - *voltage = cached_voltage; - - return ret; -} - -static enum ec_error_list bq24715_set_voltage(int chgnum, int voltage) -{ - cached_voltage = voltage; - return sbc_write(chgnum, SB_CHARGING_VOLTAGE, voltage); -} - -/* Charging power state initialization */ -static enum ec_error_list bq24715_post_init(int chgnum) -{ - int rv; - int option; - - rv = bq24715_get_option(chgnum, &option); - if (rv) - return rv; - - /* Don't be noisy */ - option |= OPT_AUDIO_FREQ_40KHZ_LIMIT; - - /* Always monitor adapter current (40X multiplier). */ - option |= OPT_FIX_IOUT_ALWAYS; - option &= ~OPT_IOUT_MASK; - option &= ~OPT_LEARN_MASK; - - /* Enable dynamic power management */ - option |= OPT_IDPM_ENABLE; - - rv = bq24715_set_option(chgnum, option); - if (rv) - return rv; - - rv = bq24715_set_input_current_limit(chgnum, - CONFIG_CHARGER_INPUT_CURRENT); - return rv; -} - -static enum ec_error_list bq24715_discharge_on_ac(int chgnum, int enable) -{ - int rv; - int option; - - rv = bq24715_get_option(chgnum, &option); - if (rv) - return rv; - - option &= ~OPT_LEARN_MASK; - if (enable) - option |= OPT_LEARN_ENABLE; - else - option |= OPT_LEARN_DISABLE; - rv = bq24715_set_option(chgnum, option); - - return rv; -} - -const struct charger_drv bq24715_drv = { - .post_init = &bq24715_post_init, - .get_info = &bq24715_get_info, - .get_status = &bq24715_get_status, - .set_mode = &bq24715_set_mode, - .get_current = &bq24715_get_current, - .set_current = &bq24715_set_current, - .get_voltage = &bq24715_get_voltage, - .set_voltage = &bq24715_set_voltage, - .discharge_on_ac = &bq24715_discharge_on_ac, - .set_input_current_limit = &bq24715_set_input_current_limit, - .get_input_current_limit = &bq24715_get_input_current_limit, - .manufacturer_id = &bq24715_manufacturer_id, - .device_id = &bq24715_device_id, - .get_option = &bq24715_get_option, - .set_option = &bq24715_set_option, -}; diff --git a/driver/charger/bq24715.h b/driver/charger/bq24715.h deleted file mode 100644 index 644f995f2e..0000000000 --- a/driver/charger/bq24715.h +++ /dev/null @@ -1,132 +0,0 @@ -/* Copyright 2012 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. - * - * TI bq24715 battery charger driver. - */ - -#ifndef __CROS_EC_BQ24715_H -#define __CROS_EC_BQ24715_H - -/* NOTES: - * If battery is not present keep charge current register (0x14) at 0. - * Max charge voltage (0x15) needs to be programmed before 0x14. - */ - -/* Chip specific registers */ -#define BQ24715_CHARGE_OPTION 0x12 -#define BQ24715_CHARGE_CURRENT 0x14 -#define BQ24715_MAX_CHARGE_VOLTAGE 0x15 -#define BQ24715_MIN_SYSTEM_VOLTAGE 0x3e -#define BQ24715_INPUT_CURRENT 0x3f -#define BQ24715_MANUFACTURER_ID 0xfe -#define BQ24715_DEVICE_ID 0xff - -/* ChargeOption Register - 0x12 */ -#define OPT_LOWPOWER_MASK BIT(15) -#define OPT_LOWPOWER_DSCHRG_I_MON_ON (0 << 15) -#define OPT_LOWPOWER_DSCHRG_I_MON_OFF BIT(15) -#define OPT_WATCHDOG_MASK (3 << 13) -#define OPT_WATCHDOG_DISABLE (0 << 13) -#define OPT_WATCHDOG_44SEC BIT(13) -#define OPT_WATCHDOG_88SEC (2 << 13) -#define OPT_WATCHDOG_175SEC (3 << 13) -#define OPT_SYSOVP_MASK BIT(12) -#define OPT_SYSOVP_15P1_3SEC_10P1_2SEC (0 << 12) -#define OPT_SYSOVP_17P0_3SEC_11P3_2SEC BIT(12) -#define OPT_SYSOVP_STATUS_MASK BIT(11) -#define OPT_SYSOVP_STATUS BIT(11) -#define OPT_AUDIO_FREQ_LIMIT_MASK BIT(10) -#define OPT_AUDIO_FREQ_NO_LIMIT (0 << 10) -#define OPT_AUDIO_FREQ_40KHZ_LIMIT BIT(10) -#define OPT_SWITCH_FREQ_MASK (3 << 8) -#define OPT_SWITCH_FREQ_600KHZ (0 << 8) -#define OPT_SWITCH_FREQ_800KHZ BIT(8) -#define OPT_SWITCH_FREQ_1MHZ (2 << 8) -#define OPT_SWITCH_FREQ_800KHZ_DUP (3 << 8) -#define OPT_ACOC_MASK BIT(7) -#define OPT_ACOC_DISABLED (0 << 7) -#define OPT_ACOC_333PCT_IPDM BIT(7) -#define OPT_LSFET_OCP_MASK BIT(6) -#define OPT_LSFET_OCP_250MV (0 << 6) -#define OPT_LSFET_OCP_350MV BIT(6) -#define OPT_LEARN_MASK BIT(5) -#define OPT_LEARN_DISABLE (0 << 5) -#define OPT_LEARN_ENABLE BIT(5) -#define OPT_IOUT_MASK BIT(4) -#define OPT_IOUT_40X (0 << 4) -#define OPT_IOUT_16X BIT(4) -#define OPT_FIX_IOUT_MASK BIT(3) -#define OPT_FIX_IOUT_IDPM_EN (0 << 3) -#define OPT_FIX_IOUT_ALWAYS BIT(3) -#define OPT_LDO_MODE_MASK BIT(2) -#define OPT_LDO_DISABLE (0 << 2) -#define OPT_LDO_ENABLE BIT(2) -#define OPT_IDPM_MASK BIT(1) -#define OPT_IDPM_DISABLE (0 << 1) -#define OPT_IDPM_ENABLE BIT(1) -#define OPT_CHARGE_INHIBIT_MASK BIT(0) -#define OPT_CHARGE_ENABLE (0 << 0) -#define OPT_CHARGE_DISABLE BIT(0) - - -/* ChargeCurrent Register - 0x14 - * The ChargeCurrent register controls a DAC. Therefore - * the below definitions are cummulative. */ -#define CHARGE_I_64MA BIT(6) -#define CHARGE_I_128MA BIT(7) -#define CHARGE_I_256MA BIT(8) -#define CHARGE_I_512MA BIT(9) -#define CHARGE_I_1024MA BIT(10) -#define CHARGE_I_2048MA BIT(11) -#define CHARGE_I_4096MA BIT(12) -#define CHARGE_I_OFF (0) -#define CHARGE_I_MIN (128) -#define CHARGE_I_MAX (8128) -#define CHARGE_I_STEP (64) - -/* MaxChargeVoltage Register - 0x15 - * The MaxChargeVoltage register controls a DAC. Therefore - * the below definitions are cummulative. */ -#define CHARGE_V_16MV BIT(4) -#define CHARGE_V_32MV BIT(5) -#define CHARGE_V_64MV BIT(6) -#define CHARGE_V_128MV BIT(7) -#define CHARGE_V_256MV BIT(8) -#define CHARGE_V_512MV BIT(9) -#define CHARGE_V_1024MV BIT(10) -#define CHARGE_V_2048MV BIT(11) -#define CHARGE_V_4096MV BIT(12) -#define CHARGE_V_8192MV BIT(13) -#define CHARGE_V_MIN (4096) -#define CHARGE_V_MAX (0x3ff0) -#define CHARGE_V_STEP (16) - -/* MinSystemVoltage Register - 0x3e - * The MinSystemVoltage register controls a DAC. Therefore - * the below definitions are cummulative. */ -#define MIN_SYS_V_256MV BIT(8) -#define MIN_SYS_V_512MV BIT(9) -#define MIN_SYS_V_1024MV BIT(10) -#define MIN_SYS_V_2048MV BIT(11) -#define MIN_SYS_V_4096MV BIT(12) -#define MIN_SYS_V_8192MV BIT(13) -#define MIN_SYS_V_MIN (4096) - -/* InputCurrent Register - 0x3f - * The InputCurrent register controls a DAC. Therefore - * the below definitions are cummulative. */ -#define INPUT_I_64MA BIT(6) -#define INPUT_I_128MA BIT(7) -#define INPUT_I_256MA BIT(8) -#define INPUT_I_512MA BIT(9) -#define INPUT_I_1024MA BIT(10) -#define INPUT_I_2048MA BIT(11) -#define INPUT_I_4096MA BIT(12) -#define INPUT_I_MIN (128) -#define INPUT_I_MAX (8064) -#define INPUT_I_STEP (64) - -extern const struct charger_drv bq24715_drv; - -#endif /* __CROS_EC_BQ24715_H */ diff --git a/driver/charger/bq24773.c b/driver/charger/bq24773.c deleted file mode 100644 index d242f105c6..0000000000 --- a/driver/charger/bq24773.c +++ /dev/null @@ -1,308 +0,0 @@ -/* Copyright 2014 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. - * - * TI bq24773 battery charger driver. - */ - -#include "battery_smart.h" -#include "bq24773.h" -#include "charger.h" -#include "console.h" -#include "common.h" -#include "util.h" - -/* - * on the I2C version of the charger, - * some registers are 8-bit only (eg input current) - * and they are shifted by 6 bits compared to the SMBUS version (bq24770). - */ -#define REG8_SHIFT 6 -#define R8 (1 << (REG8_SHIFT)) -/* Sense resistor configurations and macros */ -#define DEFAULT_SENSE_RESISTOR 10 -#define R_SNS CONFIG_CHARGER_SENSE_RESISTOR -#define R_AC (CONFIG_CHARGER_SENSE_RESISTOR_AC) -#define REG_TO_CURRENT(REG, RS) ((REG) * DEFAULT_SENSE_RESISTOR / (RS)) -#define CURRENT_TO_REG(CUR, RS) ((CUR) * (RS) / DEFAULT_SENSE_RESISTOR) -#define REG8_TO_CURRENT(REG, RS) ((REG) * DEFAULT_SENSE_RESISTOR / (RS) * R8) -#define CURRENT_TO_REG8(CUR, RS) ((CUR) * (RS) / DEFAULT_SENSE_RESISTOR / R8) - -/* ChargeCurrent Register - 0x14 (mA) */ -#define CHARGE_I_OFF 0 -#define CHARGE_I_MIN 128 -#define CHARGE_I_MAX 8128 -#define CHARGE_I_STEP 64 - -/* MaxChargeVoltage Register - 0x15 (mV) */ -#define CHARGE_V_MIN 1024 -#define CHARGE_V_MAX 19200 -#define CHARGE_V_STEP 16 - -/* InputCurrent Register - 0x3f (mA) */ -#define INPUT_I_MIN 128 -#define INPUT_I_MAX 8128 -#define INPUT_I_STEP 64 - -/* Charger parameters */ -static const struct charger_info bq2477x_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, R_SNS), - .current_min = REG_TO_CURRENT(CHARGE_I_MIN, R_SNS), - .current_step = REG_TO_CURRENT(CHARGE_I_STEP, R_SNS), - .input_current_max = REG_TO_CURRENT(INPUT_I_MAX, R_AC), - .input_current_min = REG_TO_CURRENT(INPUT_I_MIN, R_AC), - .input_current_step = REG_TO_CURRENT(INPUT_I_STEP, R_AC), -}; - -#ifdef CONFIG_CHARGER_BQ24773 -static inline enum ec_error_list raw_read8(int chgnum, int offset, int *value) -{ - return i2c_read8(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, - offset, value); -} - -static inline enum ec_error_list raw_write8(int chgnum, int offset, int value) -{ - return i2c_write8(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, - offset, value); -} -#endif - -static inline enum ec_error_list raw_read16(int chgnum, int offset, int *value) -{ - return i2c_read16(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, - offset, value); -} - -static inline enum ec_error_list raw_write16(int chgnum, int offset, int value) -{ - return i2c_write16(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, - offset, value); -} - - -/* chip specific interfaces */ - -static enum ec_error_list bq2477x_set_input_current_limit(int chgnum, - int input_current) -{ -#ifdef CONFIG_CHARGER_BQ24770 - return raw_write16(chgnum, REG_INPUT_CURRENT, - CURRENT_TO_REG(input_current, R_AC)); -#elif defined(CONFIG_CHARGER_BQ24773) - return raw_write8(chgnum, REG_INPUT_CURRENT, - CURRENT_TO_REG8(input_current, R_AC)); -#endif -} - -static enum ec_error_list bq2477x_get_input_current_limit(int chgnum, - int *input_current) -{ - int rv; - int reg; - -#ifdef CONFIG_CHARGER_BQ24770 - rv = raw_read16(chgnum, REG_INPUT_CURRENT, ®); -#elif defined(CONFIG_CHARGER_BQ24773) - rv = raw_read8(chgnum, REG_INPUT_CURRENT, ®); -#endif - if (rv) - return rv; - -#ifdef CONFIG_CHARGER_BQ24770 - *input_current = REG_TO_CURRENT(reg, R_AC); -#elif defined(CONFIG_CHARGER_BQ24773) - *input_current = REG8_TO_CURRENT(reg, R_AC); -#endif - return EC_SUCCESS; -} - -static enum ec_error_list bq2477x_manufacturer_id(int chgnum, int *id) -{ -#ifdef CONFIG_CHARGER_BQ24770 - return raw_read16(chgnum, REG_MANUFACTURE_ID, id); -#elif defined(CONFIG_CHARGER_BQ24773) - *id = 0x40; /* TI */ - return EC_SUCCESS; -#endif -} - -static enum ec_error_list bq2477x_device_id(int chgnum, int *id) -{ -#ifdef CONFIG_CHARGER_BQ24770 - return raw_read16(chgnum, REG_DEVICE_ADDRESS, id); -#elif defined(CONFIG_CHARGER_BQ24773) - return raw_read8(chgnum, REG_DEVICE_ADDRESS, id); -#endif -} - -static enum ec_error_list bq2477x_get_option(int chgnum, int *option) -{ - return raw_read16(chgnum, REG_CHARGE_OPTION0, option); -} - -static enum ec_error_list bq2477x_set_option(int chgnum, int option) -{ - return raw_write16(chgnum, REG_CHARGE_OPTION0, option); -} - -/* Charger interfaces */ - -static const struct charger_info *bq2477x_get_info(int chgnum) -{ - return &bq2477x_charger_info; -} - -static enum ec_error_list bq2477x_get_status(int chgnum, int *status) -{ - int rv; - int option; - - rv = bq2477x_get_option(chgnum, &option); - if (rv) - return rv; - - /* Default status */ - *status = CHARGER_LEVEL_2; - - if (option & OPTION0_CHARGE_INHIBIT) - *status |= CHARGER_CHARGE_INHIBITED; - - return EC_SUCCESS; -} - -static enum ec_error_list bq2477x_set_mode(int chgnum, int mode) -{ - int rv; - int option; - - rv = bq2477x_get_option(chgnum, &option); - if (rv) - return rv; - - if (mode & CHARGE_FLAG_INHIBIT_CHARGE) - option |= OPTION0_CHARGE_INHIBIT; - else - option &= ~OPTION0_CHARGE_INHIBIT; - return bq2477x_set_option(chgnum, option); -} - -static enum ec_error_list bq2477x_get_current(int chgnum, int *current) -{ - int rv; - int reg; - - rv = raw_read16(chgnum, REG_CHARGE_CURRENT, ®); - - if (rv) - return rv; - - *current = REG_TO_CURRENT(reg, R_SNS); - return EC_SUCCESS; -} - -static enum ec_error_list bq2477x_set_current(int chgnum, int current) -{ - current = charger_closest_current(current); - return raw_write16(chgnum, REG_CHARGE_CURRENT, - CURRENT_TO_REG(current, R_SNS)); -} - -static enum ec_error_list bq2477x_get_voltage(int chgnum, int *voltage) -{ - return raw_read16(chgnum, REG_MAX_CHARGE_VOLTAGE, voltage); -} - -static enum ec_error_list bq2477x_set_voltage(int chgnum, int voltage) -{ - voltage = charger_closest_voltage(voltage); - return raw_write16(chgnum, REG_MAX_CHARGE_VOLTAGE, voltage); -} - -/* Charging power state initialization */ -static enum ec_error_list bq2477x_post_init(int chgnum) -{ - int rv, option; -#ifdef CONFIG_CHARGER_ILIM_PIN_DISABLED - int option2; -#endif - - rv = bq2477x_get_option(chgnum, &option); - if (rv) - return rv; - - option &= ~OPTION0_LEARN_ENABLE; - rv = bq2477x_set_option(chgnum, option); - if (rv) - return rv; - - /* Turn off PROCHOT warning */ - rv = raw_read16(chgnum, REG_PROCHOT_OPTION1, &option); - if (rv) - return rv; - - option &= ~PROCHOT_OPTION1_SELECTOR_MASK; - rv = raw_write16(chgnum, REG_PROCHOT_OPTION1, option); - - if (rv) - return rv; - -#ifdef CONFIG_CHARGER_ILIM_PIN_DISABLED - /* Read the external ILIM pin enabled flag. */ - rv = raw_read16(chgnum, REG_CHARGE_OPTION2, &option2); - if (rv) - return rv; - - /* Set ILIM pin disabled if it is currently enabled. */ - if (option2 & OPTION2_EN_EXTILIM) { - option2 &= ~OPTION2_EN_EXTILIM; - rv = raw_write16(chgnum, REG_CHARGE_OPTION2, option2); - } - return rv; -#else - return EC_SUCCESS; -#endif -} - -static enum ec_error_list bq2477x_discharge_on_ac(int chgnum, int enable) -{ - int rv; - int option; - - rv = bq2477x_get_option(chgnum, &option); - if (rv) - return rv; - - if (enable) - rv = bq2477x_set_option(chgnum, option | OPTION0_LEARN_ENABLE); - else - rv = bq2477x_set_option(chgnum, option & ~OPTION0_LEARN_ENABLE); - - return rv; -} - -const struct charger_drv bq2477x_drv = { - .post_init = &bq2477x_post_init, - .get_info = &bq2477x_get_info, - .get_status = &bq2477x_get_status, - .set_mode = &bq2477x_set_mode, - .get_current = &bq2477x_get_current, - .set_current = &bq2477x_set_current, - .get_voltage = &bq2477x_get_voltage, - .set_voltage = &bq2477x_set_voltage, - .discharge_on_ac = &bq2477x_discharge_on_ac, - .set_input_current_limit = &bq2477x_set_input_current_limit, - .get_input_current_limit = &bq2477x_get_input_current_limit, - .manufacturer_id = &bq2477x_manufacturer_id, - .device_id = &bq2477x_device_id, - .get_option = &bq2477x_get_option, - .set_option = &bq2477x_set_option, -}; diff --git a/driver/charger/bq24773.h b/driver/charger/bq24773.h deleted file mode 100644 index 46f8939036..0000000000 --- a/driver/charger/bq24773.h +++ /dev/null @@ -1,91 +0,0 @@ -/* Copyright 2014 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. - * - * TI bq24773 battery charger driver. - */ - -#ifndef __CROS_EC_BQ24773_H -#define __CROS_EC_BQ24773_H - -/* for i2c_read and i2c_write functions. */ -#include "i2c.h" - -/* I2C address */ -#define BQ24770_ADDR_FLAGS 0x09 -#define BQ24773_ADDR_FLAGS 0x6a - -/* Chip specific commands */ -#define BQ24770_CHARGE_OPTION0 0x12 -#define BQ24770_CHARGE_OPTION1 0x3B -#define BQ24770_CHARGE_OPTION2 0x38 -#define BQ24770_PROCHOT_OPTION0 0x3C -#define BQ24770_PROCHOT_OPTION1 0x3D -#define BQ24770_CHARGE_CURRENT 0x14 -#define BQ24770_MAX_CHARGE_VOLTAGE 0x15 -#define BQ24770_MIN_SYSTEM_VOLTAGE 0x3E -#define BQ24770_INPUT_CURRENT 0x3F -#define BQ24770_MANUFACTURE_ID 0xFE -#define BQ24770_DEVICE_ADDRESS 0xFF - -#define BQ24773_CHARGE_OPTION0 0x00 -#define BQ24773_CHARGE_OPTION1 0x02 -#define BQ24773_PROCHOT_OPTION0 0x04 -#define BQ24773_PROCHOT_OPTION1 0x06 -#define BQ24773_PROCHOT_STATUS 0x08 -#define BQ24773_DEVICE_ADDRESS 0x09 -#define BQ24773_CHARGE_CURRENT 0x0A -#define BQ24773_MAX_CHARGE_VOLTAGE 0x0C -#define BQ24773_MIN_SYSTEM_VOLTAGE 0x0E -#define BQ24773_INPUT_CURRENT 0x0F -#define BQ24773_CHARGE_OPTION2 0x10 - -/* Option bits */ -#define OPTION0_CHARGE_INHIBIT BIT(0) -#define OPTION0_LEARN_ENABLE BIT(5) -#define OPTION0_SWITCHING_FREQ_MASK (3 << 8) -#define OPTION0_SWITCHING_FREQ_600KHZ (0 << 8) -#define OPTION0_SWITCHING_FREQ_800KHZ BIT(8) -#define OPTION0_SWITCHING_FREQ_1000KHZ (2 << 8) -#define OPTION0_SWITCHING_FREQ_1200KHZ (3 << 8) - -#define OPTION2_EN_EXTILIM BIT(7) - -/* Prochot Option bits */ -#define PROCHOT_OPTION1_SELECTOR_MASK 0x7f /* [6:0] PROCHOT SELECTOR */ - -#ifdef CONFIG_CHARGER_BQ24770 - #define CHARGER_NAME "bq24770" - #define I2C_ADDR_CHARGER_FLAGS BQ24770_ADDR_FLAGS - - #define REG_CHARGE_OPTION0 BQ24770_CHARGE_OPTION0 - #define REG_CHARGE_OPTION1 BQ24770_CHARGE_OPTION1 - #define REG_CHARGE_OPTION2 BQ24770_CHARGE_OPTION2 - #define REG_PROCHOT_OPTION0 BQ24770_PROCHOT_OPTION0 - #define REG_PROCHOT_OPTION1 BQ24770_PROCHOT_OPTION1 - #define REG_CHARGE_CURRENT BQ24770_CHARGE_CURRENT - #define REG_MAX_CHARGE_VOLTAGE BQ24770_MAX_CHARGE_VOLTAGE - #define REG_MIN_SYSTEM_VOLTAGE BQ24770_MIN_SYSTEM_VOLTAGE - #define REG_INPUT_CURRENT BQ24770_INPUT_CURRENT - #define REG_MANUFACTURE_ID BQ24770_MANUFACTURE_ID - #define REG_DEVICE_ADDRESS BQ24770_DEVICE_ADDRESS - -#elif defined(CONFIG_CHARGER_BQ24773) - #define CHARGER_NAME "bq24773" - #define I2C_ADDR_CHARGER_FLAGS BQ24773_ADDR_FLAGS - - #define REG_CHARGE_OPTION0 BQ24773_CHARGE_OPTION0 - #define REG_CHARGE_OPTION1 BQ24773_CHARGE_OPTION1 - #define REG_CHARGE_OPTION2 BQ24773_CHARGE_OPTION2 - #define REG_PROCHOT_OPTION0 BQ24773_PROCHOT_OPTION0 - #define REG_PROCHOT_OPTION1 BQ24773_PROCHOT_OPTION1 - #define REG_CHARGE_CURRENT BQ24773_CHARGE_CURRENT - #define REG_MAX_CHARGE_VOLTAGE BQ24773_MAX_CHARGE_VOLTAGE - #define REG_MIN_SYSTEM_VOLTAGE BQ24773_MIN_SYSTEM_VOLTAGE - #define REG_INPUT_CURRENT BQ24773_INPUT_CURRENT - #define REG_DEVICE_ADDRESS BQ24773_DEVICE_ADDRESS -#endif - -extern const struct charger_drv bq2477x_drv; - -#endif /* __CROS_EC_BQ24773_H */ diff --git a/driver/charger/bq25710.c b/driver/charger/bq25710.c deleted file mode 100644 index df898467be..0000000000 --- a/driver/charger/bq25710.c +++ /dev/null @@ -1,752 +0,0 @@ -/* Copyright 2018 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. - * - * TI bq25710 battery charger driver. - */ - -#include "battery.h" -#include "battery_smart.h" -#include "bq25710.h" -#include "charge_ramp.h" -#include "charge_state_v2.h" -#include "charger.h" -#include "common.h" -#include "console.h" -#include "hooks.h" -#include "i2c.h" -#include "task.h" -#include "system.h" -#include "timer.h" -#include "util.h" - -#ifndef CONFIG_CHARGER_NARROW_VDC -#error "BQ25710 is a NVDC charger, please enable CONFIG_CHARGER_NARROW_VDC." -#endif - -/* - * Delay required from taking the bq25710 out of low power mode and having the - * correct value in register 0x3E for VSYS_MIN voltage. The length of the delay - * was determined by experiment. Less than 12 msec was not enough of delay, so - * the value here is set to 20 msec to have plenty of margin. - */ -#define BQ25710_VDDA_STARTUP_DELAY_MSEC 20 - -/* Sense resistor configurations and macros */ -#define DEFAULT_SENSE_RESISTOR 10 - -#ifdef CONFIG_CHARGER_SENSE_RESISTOR_AC_BQ25710 - #undef CONFIG_CHARGER_SENSE_RESISTOR_AC - #define CONFIG_CHARGER_SENSE_RESISTOR_AC \ - CONFIG_CHARGER_SENSE_RESISTOR_AC_BQ25710 -#endif - - -#define INPUT_RESISTOR_RATIO \ - ((CONFIG_CHARGER_SENSE_RESISTOR_AC) / DEFAULT_SENSE_RESISTOR) - -#define CHARGING_RESISTOR_RATIO \ - ((CONFIG_CHARGER_SENSE_RESISTOR) / DEFAULT_SENSE_RESISTOR) -#define REG_TO_CHARGING_CURRENT(REG) ((REG) / CHARGING_RESISTOR_RATIO) -#define CHARGING_CURRENT_TO_REG(CUR) ((CUR) * CHARGING_RESISTOR_RATIO) -#ifdef CONFIG_CHARGER_BQ25720 -#define VMIN_AP_VSYS_TH2_TO_REG(DV) ((DV) - 32) -#endif - -/* Console output macros */ -#define CPRINTF(format, args...) cprintf(CC_CHARGER, format, ## args) - -#ifdef CONFIG_CHARGER_BQ25710_IDCHG_LIMIT_MA -/* - * If this config option is defined, then the bq25710 needs to remain in - * performance mode when the AP is in S0. Performance mode is active whenever AC - * power is connected or when the EN_LWPWR bit in ChargeOption0 is clear. - */ -static uint32_t bq25710_perf_mode_req; -static struct mutex bq25710_perf_mode_mutex; -#endif - -/* Charger parameters */ -static const struct charger_info bq25710_charger_info = { - .name = "bq25710", - .voltage_max = 19200, - .voltage_min = 1024, - .voltage_step = 8, - .current_max = 8128 / CHARGING_RESISTOR_RATIO, - .current_min = 64 / CHARGING_RESISTOR_RATIO, - .current_step = 64 / CHARGING_RESISTOR_RATIO, - .input_current_max = 6400 / INPUT_RESISTOR_RATIO, - .input_current_min = 50 / INPUT_RESISTOR_RATIO, - .input_current_step = 50 / INPUT_RESISTOR_RATIO, -}; - -static enum ec_error_list bq25710_get_option(int chgnum, int *option); -static enum ec_error_list bq25710_set_option(int chgnum, int option); - -static inline int iin_dpm_reg_to_current(int reg) -{ - return (reg + 1) * BQ25710_IIN_DPM_CURRENT_STEP_MA / - INPUT_RESISTOR_RATIO; -} - -static inline int iin_host_current_to_reg(int current) -{ - return (current * INPUT_RESISTOR_RATIO / - BQ25710_IIN_HOST_CURRENT_STEP_MA) - 1; -} - -static inline enum ec_error_list raw_read16(int chgnum, int offset, int *value) -{ - return i2c_read16(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, - offset, value); -} - -static inline int min_system_voltage_to_reg(int voltage_mv) -{ - return (voltage_mv / BQ25710_MIN_SYSTEM_VOLTAGE_STEP_MV) << - BQ25710_MIN_SYSTEM_VOLTAGE_SHIFT; -} - -static inline enum ec_error_list raw_write16(int chgnum, int offset, int value) -{ - return i2c_write16(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, - offset, value); -} - -#if defined(CONFIG_CHARGE_RAMP_HW) || \ - defined(CONFIG_USB_PD_VBUS_MEASURE_CHARGER) -static int bq25710_get_low_power_mode(int chgnum, int *mode) -{ - int rv; - int reg; - - rv = raw_read16(chgnum, BQ25710_REG_CHARGE_OPTION_0, ®); - if (rv) - return rv; - - *mode = !!(reg & BQ25710_CHARGE_OPTION_0_LOW_POWER_MODE); - - return EC_SUCCESS; -} - -static int bq25710_set_low_power_mode(int chgnum, int enable) -{ - int rv; - int reg; - - rv = raw_read16(chgnum, BQ25710_REG_CHARGE_OPTION_0, ®); - if (rv) - return rv; - -#ifdef CONFIG_CHARGER_BQ25710_IDCHG_LIMIT_MA - mutex_lock(&bq25710_perf_mode_mutex); - /* - * Performance mode means not in low power mode. The bit that controls - * this is EN_LWPWR in ChargeOption0. The 'enable' param in this - * function is refeerring to low power mode, so enabling low power mode - * means disabling performance mode and vice versa. - */ - if (enable) - bq25710_perf_mode_req &= ~(1 << task_get_current()); - else - bq25710_perf_mode_req |= (1 << task_get_current()); - enable = !bq25710_perf_mode_req; -#endif - - if (enable) - reg |= BQ25710_CHARGE_OPTION_0_LOW_POWER_MODE; - else - reg &= ~BQ25710_CHARGE_OPTION_0_LOW_POWER_MODE; - - rv = raw_write16(chgnum, BQ25710_REG_CHARGE_OPTION_0, reg); -#ifdef CONFIG_CHARGER_BQ25710_IDCHG_LIMIT_MA - mutex_unlock(&bq25710_perf_mode_mutex); -#endif - if (rv) - return rv; - - return EC_SUCCESS; -} - -static int bq25710_adc_start(int chgnum, int adc_en_mask) -{ - int reg; - int mode; - int tries_left = BQ25710_ADC_OPTION_ADC_CONV_MS; - - /* Save current mode to restore same state after ADC read */ - if (bq25710_get_low_power_mode(chgnum, &mode)) - return EC_ERROR_UNKNOWN; - - /* Exit low power mode so ADC conversion takes typical time */ - if (bq25710_set_low_power_mode(chgnum, 0)) - return EC_ERROR_UNKNOWN; - - /* - * Turn on the ADC for one reading. Note that adc_en_mask - * maps to bit[7:0] in ADCOption register. - */ - reg = (adc_en_mask & BQ25710_ADC_OPTION_EN_ADC_ALL) | - BQ25710_ADC_OPTION_ADC_START; - if (raw_write16(chgnum, BQ25710_REG_ADC_OPTION, reg)) - return EC_ERROR_UNKNOWN; - - /* - * Wait until the ADC operation completes. The spec says typical - * conversion time is 10 msec (25 msec on bq25720). If low power - * mode isn't exited first, then the conversion time jumps to - * ~60 msec. - */ - do { - /* sleep 2 ms so we time out after 2x the expected time */ - msleep(2); - raw_read16(chgnum, BQ25710_REG_ADC_OPTION, ®); - } while (--tries_left && (reg & BQ25710_ADC_OPTION_ADC_START)); - - /* ADC reading attempt complete, go back to low power mode */ - if (bq25710_set_low_power_mode(chgnum, mode)) - return EC_ERROR_UNKNOWN; - - /* Could not complete read */ - if (reg & BQ25710_ADC_OPTION_ADC_START) - return EC_ERROR_TIMEOUT; - - return EC_SUCCESS; -} -#endif - -static void bq25710_init(int chgnum) -{ - int reg; - int vsys; - int rv; - - /* - * Reset registers to their default settings. There is no reset pin for - * this chip so without a full power cycle, some registers may not be at - * their default values. Note, need to save the POR value of - * MIN_SYSTEM_VOLTAGE register prior to setting the reset so that the - * correct value is preserved. In order to have the correct value read, - * the bq25710 must not be in low power mode, otherwise the VDDA rail - * may not be powered if AC is not connected. Note, this reset is only - * required when running out of RO and not following sysjump to RW. - */ - if (!system_jumped_late()) { - rv = bq25710_set_low_power_mode(chgnum, 0); - /* Allow enough time for VDDA to be powered */ - msleep(BQ25710_VDDA_STARTUP_DELAY_MSEC); - rv |= raw_read16(chgnum, BQ25710_REG_MIN_SYSTEM_VOLTAGE, &vsys); - rv |= raw_read16(chgnum, BQ25710_REG_CHARGE_OPTION_3, ®); - if (!rv) { - reg |= BQ25710_CHARGE_OPTION_3_RESET_REG; - /* Set all registers to default values */ - raw_write16(chgnum, BQ25710_REG_CHARGE_OPTION_3, reg); - /* Restore VSYS_MIN voltage to POR reset value */ - raw_write16(chgnum, BQ25710_REG_MIN_SYSTEM_VOLTAGE, - vsys); - } - /* Reenable low power mode */ - bq25710_set_low_power_mode(chgnum, 1); - } - - if (!raw_read16(chgnum, BQ25710_REG_PROCHOT_OPTION_1, ®)) { - /* Disable VDPM prochot profile at initialization */ - reg &= ~BQ25710_PROCHOT_PROFILE_VDPM; - /* - * Enable PROCHOT to be asserted with VSYS min detection. Note - * that when no battery is present, then VSYS will be set to the - * value in register 0x3E (MinSysVoltage) which means that when - * no battery is present prochot will continuosly be asserted. - */ - reg |= BQ25710_PROCHOT_PROFILE_VSYS; -#ifdef CONFIG_CHARGER_BQ25710_IDCHG_LIMIT_MA - /* - * Set the IDCHG limit who's value is defined in the config - * option in mA. Also, enable IDCHG trigger for prochot. - */ - reg &= ~BQ25710_PROCHOT_IDCHG_VTH_MASK; - /* - * IDCHG limit is in 512 mA steps. Note there is a 128 mA offset - * so the actual IDCHG limit will be the value stored in bits - * 15:10 + 128 mA. - */ - reg |= ((CONFIG_CHARGER_BQ25710_IDCHG_LIMIT_MA << 1) & - BQ25710_PROCHOT_IDCHG_VTH_MASK); - reg |= BQ25710_PROCHOT_PROFILE_IDCHG; -#endif - raw_write16(chgnum, BQ25710_REG_PROCHOT_OPTION_1, reg); -#ifdef CONFIG_CHARGER_BQ25720_VSYS_TH2_DV - /* - * The default VSYS_TH2 is 5.9v for a 2S config. Boards - * may need to increase this for stability. PROCHOT is - * asserted when the threshold is reached. - */ - if (!raw_read16(chgnum, BQ25720_REG_VMIN_ACTIVE_PROTECTION, - ®)) { - reg &= ~BQ25720_VMIN_AP_VSYS_TH2_MASK; - reg |= VMIN_AP_VSYS_TH2_TO_REG( - CONFIG_CHARGER_BQ25720_VSYS_TH2_DV) << - BQ25720_VMIN_AP_VSYS_TH2_SHIFT; - raw_write16(chgnum, BQ25720_REG_VMIN_ACTIVE_PROTECTION, - reg); - } -#endif - } - - /* Reduce ILIM from default of 150% to 105% */ - if (!raw_read16(chgnum, BQ25710_REG_PROCHOT_OPTION_0, ®)) { - reg &= ~BQ25710_PROCHOT0_ILIM_VTH_MASK; - raw_write16(chgnum, BQ25710_REG_PROCHOT_OPTION_0, reg); - } - - /* - * Reduce peak power mode overload and relax cycle time from default 20 - * msec to the minimum of 5 msec. - */ - if (!raw_read16(chgnum, BQ25710_REG_CHARGE_OPTION_2, ®)) { - reg &= ~BQ25710_CHARGE_OPTION_2_TMAX_MASK; - raw_write16(chgnum, BQ25710_REG_CHARGE_OPTION_2, reg); - } -} - -/* Charger interfaces */ -static const struct charger_info *bq25710_get_info(int chgnum) -{ - return &bq25710_charger_info; -} - -static enum ec_error_list bq25710_post_init(int chgnum) -{ - /* - * Note: bq25710 power on reset state is: - * watch dog timer = 175 sec - * input current limit = ~1/2 maximum setting - * charging voltage = 0 mV - * charging current = 0 mA - * discharge on AC = disabled - */ - - return EC_SUCCESS; -} - -static enum ec_error_list bq25710_get_status(int chgnum, int *status) -{ - int rv; - int option; - - rv = bq25710_get_option(chgnum, &option); - if (rv) - return rv; - - /* Default status */ - *status = CHARGER_LEVEL_2; - - if (option & BQ25710_CHARGE_OPTION_0_CHRG_INHIBIT) - *status |= CHARGER_CHARGE_INHIBITED; - - return EC_SUCCESS; -} - -static enum ec_error_list bq25710_set_mode(int chgnum, int mode) -{ - int rv; - int option; - - rv = bq25710_get_option(chgnum, &option); - if (rv) - return rv; - - if (mode & CHARGER_CHARGE_INHIBITED) - option |= BQ25710_CHARGE_OPTION_0_CHRG_INHIBIT; - else - option &= ~BQ25710_CHARGE_OPTION_0_CHRG_INHIBIT; - - return bq25710_set_option(chgnum, option); -} - -static enum ec_error_list bq25710_enable_otg_power(int chgnum, int enabled) -{ - /* This is controlled with the EN_OTG pin. Support not added yet. */ - return EC_ERROR_UNIMPLEMENTED; -} - -static enum ec_error_list bq25710_set_otg_current_voltage(int chgum, - int output_current, - int output_voltage) -{ - /* Add when needed. */ - return EC_ERROR_UNIMPLEMENTED; -} - -static enum ec_error_list bq25710_get_current(int chgnum, int *current) -{ - int rv, reg; - - rv = raw_read16(chgnum, BQ25710_REG_CHARGE_CURRENT, ®); - if (!rv) - *current = REG_TO_CHARGING_CURRENT(reg); - - return rv; -} - -static enum ec_error_list bq25710_set_current(int chgnum, int current) -{ - return raw_write16(chgnum, BQ25710_REG_CHARGE_CURRENT, - CHARGING_CURRENT_TO_REG(current)); -} - -/* Get/set charge voltage limit in mV */ -static enum ec_error_list bq25710_get_voltage(int chgnum, int *voltage) -{ - return raw_read16(chgnum, BQ25710_REG_MAX_CHARGE_VOLTAGE, voltage); -} - -static enum ec_error_list bq25710_set_voltage(int chgnum, int voltage) -{ - return raw_write16(chgnum, BQ25710_REG_MAX_CHARGE_VOLTAGE, voltage); -} - -/* Discharge battery when on AC power. */ -static enum ec_error_list bq25710_discharge_on_ac(int chgnum, int enable) -{ - int rv, option; - - rv = bq25710_get_option(chgnum, &option); - if (rv) - return rv; - - if (enable) - option |= BQ25710_CHARGE_OPTION_0_EN_LEARN; - else - option &= ~BQ25710_CHARGE_OPTION_0_EN_LEARN; - - return bq25710_set_option(chgnum, option); -} - -static enum ec_error_list bq25710_set_input_current_limit(int chgnum, - int input_current) -{ - int num_steps = iin_host_current_to_reg(input_current); - - return raw_write16(chgnum, BQ25710_REG_IIN_HOST, - num_steps << BQ25710_IIN_HOST_CURRENT_SHIFT); -} - -static enum ec_error_list bq25710_get_input_current_limit(int chgnum, - int *input_current) -{ - int rv, reg; - - /* - * IIN_DPM register reflects the actual input current limit programmed - * in the register, either from host or from ICO. After ICO, the - * current limit used by DPM regulation may differ from the IIN_HOST - * register settings. - */ - rv = raw_read16(chgnum, BQ25710_REG_IIN_DPM, ®); - if (!rv) - *input_current = - iin_dpm_reg_to_current(reg >> - BQ25710_IIN_DPM_CURRENT_SHIFT); - - return rv; -} - -static enum ec_error_list bq25710_manufacturer_id(int chgnum, int *id) -{ - return raw_read16(chgnum, BQ25710_REG_MANUFACTURER_ID, id); -} - -static enum ec_error_list bq25710_device_id(int chgnum, int *id) -{ - return raw_read16(chgnum, BQ25710_REG_DEVICE_ADDRESS, id); -} - -#ifdef CONFIG_USB_PD_VBUS_MEASURE_CHARGER - -#if defined(CONFIG_CHARGER_BQ25720) - -static int reg_adc_vbus_to_mv(int reg) -{ - /* - * LSB => 96mV, no DC offset. - */ - return reg * BQ25720_ADC_VBUS_STEP_MV; -} - -#elif defined(CONFIG_CHARGER_BQ25710) - -static int reg_adc_vbus_to_mv(int reg) -{ - /* - * LSB => 64mV. - * Return 0 when VBUS <= 3.2V as ADC can't measure it. - */ - return reg ? - (reg * BQ25710_ADC_VBUS_STEP_MV + BQ25710_ADC_VBUS_BASE_MV) : 0; -} - -#else -#error Only the BQ25720 and BQ25710 are supported by bq25710 driver. -#endif - -static enum ec_error_list bq25710_get_vbus_voltage(int chgnum, int port, - int *voltage) -{ - int reg, rv; - - rv = bq25710_adc_start(chgnum, BQ25710_ADC_OPTION_EN_ADC_VBUS); - if (rv) - goto error; - - /* Read ADC value */ - rv = raw_read16(chgnum, BQ25710_REG_ADC_VBUS_PSYS, ®); - if (rv) - goto error; - - reg >>= BQ25710_ADC_VBUS_STEP_BIT_OFFSET; - *voltage = reg_adc_vbus_to_mv(reg); - -error: - if (rv) - CPRINTF("Could not read VBUS ADC! Error: %d\n", rv); - return rv; -} -#endif - -static enum ec_error_list bq25710_get_option(int chgnum, int *option) -{ - /* There are 4 option registers, but we only need the first for now. */ - return raw_read16(chgnum, BQ25710_REG_CHARGE_OPTION_0, option); -} - -static enum ec_error_list bq25710_set_option(int chgnum, int option) -{ - /* There are 4 option registers, but we only need the first for now. */ - return raw_write16(chgnum, BQ25710_REG_CHARGE_OPTION_0, option); -} - -int bq25710_set_min_system_voltage(int chgnum, int mv) -{ - int reg; - - reg = min_system_voltage_to_reg(mv); - return raw_write16(chgnum, BQ25710_REG_MIN_SYSTEM_VOLTAGE, reg); -} - -#ifdef CONFIG_CHARGE_RAMP_HW - -static void bq25710_chg_ramp_handle(void) -{ - int ramp_curr; - int chgnum = 0; - - if (IS_ENABLED(CONFIG_OCPC)) - chgnum = charge_get_active_chg_chip(); - - /* - * Once the charge ramp is stable write back the stable ramp - * current to the host input current limit register - */ - ramp_curr = chg_ramp_get_current_limit(); - if (chg_ramp_is_stable()) { - if (ramp_curr && - !charger_set_input_current_limit(chgnum, ramp_curr)) - CPRINTF("bq25710: stable ramp current=%d\n", ramp_curr); - } else { - CPRINTF("bq25710: ICO stall, ramp current=%d\n", ramp_curr); - } - /* - * Disable ICO mode. When ICO mode is active the input current limit is - * given by the value in register IIN_DPM (0x22) - */ - charger_set_hw_ramp(0); -} -DECLARE_DEFERRED(bq25710_chg_ramp_handle); - -static enum ec_error_list bq25710_set_hw_ramp(int chgnum, int enable) -{ - int option3_reg, option2_reg, rv; - - rv = raw_read16(chgnum, BQ25710_REG_CHARGE_OPTION_3, &option3_reg); - if (rv) - return rv; - rv = raw_read16(chgnum, BQ25710_REG_CHARGE_OPTION_2, &option2_reg); - if (rv) - return rv; - - if (enable) { - /* - * ICO mode can only be used when a battery is present. If there - * is no battery, or if the battery has not recovered yet from - * cutoff, then enabling ICO mode will lead to VSYS - * dropping out. - */ - if (!battery_is_present() || (battery_get_disconnect_state() != - BATTERY_NOT_DISCONNECTED)) { - CPRINTF("bq25710: no battery, skip ICO enable\n"); - return EC_ERROR_UNKNOWN; - } - - /* Set InputVoltage register to BC1.2 minimum ramp voltage */ - rv = raw_write16(chgnum, BQ25710_REG_INPUT_VOLTAGE, - BQ25710_BC12_MIN_VOLTAGE_MV); - if (rv) - return rv; - - /* Enable ICO algorithm */ - option3_reg |= BQ25710_CHARGE_OPTION_3_EN_ICO_MODE; - - /* 0b: Input current limit is set by BQ25710_REG_IIN_HOST */ - option2_reg &= ~BQ25710_CHARGE_OPTION_2_EN_EXTILIM; - - /* Charge ramp may take up to 2s to settle down */ - hook_call_deferred(&bq25710_chg_ramp_handle_data, (4 * SECOND)); - } else { - /* Disable ICO algorithm */ - option3_reg &= ~BQ25710_CHARGE_OPTION_3_EN_ICO_MODE; - - /* - * 1b: Input current limit is set by the lower value of - * ILIM_HIZ pin and BQ25710_REG_IIN_HOST - */ - option2_reg |= BQ25710_CHARGE_OPTION_2_EN_EXTILIM; - } - - rv = raw_write16(chgnum, BQ25710_REG_CHARGE_OPTION_2, option2_reg); - if (rv) - return rv; - return raw_write16(chgnum, BQ25710_REG_CHARGE_OPTION_3, option3_reg); -} - -static int bq25710_ramp_is_stable(int chgnum) -{ - int reg; - - if (raw_read16(chgnum, BQ25710_REG_CHARGER_STATUS, ®)) - return 0; - - return reg & BQ25710_CHARGE_STATUS_ICO_DONE; -} - -static int bq25710_ramp_get_current_limit(int chgnum) -{ - int reg, rv; - - rv = raw_read16(chgnum, BQ25710_REG_IIN_DPM, ®); - if (rv) { - CPRINTF("Could not read iin_dpm current limit! Error: %d\n", - rv); - return 0; - } - - return iin_dpm_reg_to_current(reg >> BQ25710_IIN_DPM_CURRENT_SHIFT); -} -#endif /* CONFIG_CHARGE_RAMP_HW */ - -#ifdef CONFIG_CHARGER_BQ25710_IDCHG_LIMIT_MA -/* Called on AP S5 -> S3 and S3/S0iX -> S0 transition */ -static void bq25710_chipset_startup(void) -{ - bq25710_set_low_power_mode(CHARGER_SOLO, 0); -} -DECLARE_HOOK(HOOK_CHIPSET_STARTUP, bq25710_chipset_startup, HOOK_PRIO_DEFAULT); -DECLARE_HOOK(HOOK_CHIPSET_RESUME, bq25710_chipset_startup, HOOK_PRIO_DEFAULT); - - -/* Called on AP S0 -> S0iX/S3 or S3 -> S5 transition */ -static void bq25710_chipset_suspend(void) -{ - bq25710_set_low_power_mode(CHARGER_SOLO, 1); -} -DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, bq25710_chipset_suspend, HOOK_PRIO_DEFAULT); -DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, bq25710_chipset_suspend, HOOK_PRIO_DEFAULT); -#endif - -#ifdef CONFIG_CMD_CHARGER_DUMP -static int console_bq25710_dump_regs(int argc, char **argv) -{ - int i; - int val; - int chgnum = 0; - char *e; - - /* Dump all readable registers on bq25710. */ - static const uint8_t regs[] = { - BQ25710_REG_CHARGE_OPTION_0, - BQ25710_REG_CHARGE_CURRENT, - BQ25710_REG_MAX_CHARGE_VOLTAGE, - BQ25710_REG_CHARGER_STATUS, - BQ25710_REG_PROCHOT_STATUS, - BQ25710_REG_IIN_DPM, - BQ25710_REG_ADC_VBUS_PSYS, - BQ25710_REG_ADC_IBAT, - BQ25710_REG_ADC_CMPIN_IIN, - BQ25710_REG_ADC_VSYS_VBAT, - BQ25710_REG_CHARGE_OPTION_1, - BQ25710_REG_CHARGE_OPTION_2, - BQ25710_REG_CHARGE_OPTION_3, - BQ25710_REG_PROCHOT_OPTION_0, - BQ25710_REG_PROCHOT_OPTION_1, - BQ25710_REG_ADC_OPTION, -#ifdef CONFIG_CHARGER_BQ25720 - BQ25720_REG_CHARGE_OPTION_4, - BQ25720_REG_VMIN_ACTIVE_PROTECTION, -#endif - BQ25710_REG_OTG_VOLTAGE, - BQ25710_REG_OTG_CURRENT, - BQ25710_REG_INPUT_VOLTAGE, - BQ25710_REG_MIN_SYSTEM_VOLTAGE, - BQ25710_REG_IIN_HOST, - BQ25710_REG_MANUFACTURER_ID, - BQ25710_REG_DEVICE_ADDRESS, - }; - if (argc >= 2) { - chgnum = strtoi(argv[1], &e, 10); - if (*e) - return EC_ERROR_PARAM1; - } - - for (i = 0; i < ARRAY_SIZE(regs); ++i) { - if (raw_read16(chgnum, regs[i], &val)) - continue; - ccprintf("BQ25710 REG 0x%02x: 0x%04x\n", regs[i], val); - } - - - return 0; -} -DECLARE_CONSOLE_COMMAND(charger_dump, console_bq25710_dump_regs, - "charger_dump <chgnum>", - "Dump all charger registers"); - -#endif /* CONFIG_CMD_CHARGER_DUMP */ - -const struct charger_drv bq25710_drv = { - .init = &bq25710_init, - .post_init = &bq25710_post_init, - .get_info = &bq25710_get_info, - .get_status = &bq25710_get_status, - .set_mode = &bq25710_set_mode, - .enable_otg_power = &bq25710_enable_otg_power, - .set_otg_current_voltage = &bq25710_set_otg_current_voltage, - .get_current = &bq25710_get_current, - .set_current = &bq25710_set_current, - .get_voltage = &bq25710_get_voltage, - .set_voltage = &bq25710_set_voltage, - .discharge_on_ac = &bq25710_discharge_on_ac, - .get_vbus_voltage = &bq25710_get_vbus_voltage, - .set_input_current_limit = &bq25710_set_input_current_limit, - .get_input_current_limit = &bq25710_get_input_current_limit, - .manufacturer_id = &bq25710_manufacturer_id, - .device_id = &bq25710_device_id, - .get_option = &bq25710_get_option, - .set_option = &bq25710_set_option, -#ifdef CONFIG_CHARGE_RAMP_HW - .set_hw_ramp = &bq25710_set_hw_ramp, - .ramp_is_stable = &bq25710_ramp_is_stable, - .ramp_get_current_limit = &bq25710_ramp_get_current_limit, -#endif /* CONFIG_CHARGE_RAMP_HW */ -}; diff --git a/driver/charger/bq25710.h b/driver/charger/bq25710.h deleted file mode 100644 index 68c7619ceb..0000000000 --- a/driver/charger/bq25710.h +++ /dev/null @@ -1,143 +0,0 @@ -/* Copyright 2018 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. - * - * TI bq25710 battery charger driver. - */ - -#ifndef __CROS_EC_BQ25710_H -#define __CROS_EC_BQ25710_H - -/* SMBUS Interface */ -#define BQ25710_SMBUS_ADDR1_FLAGS 0x09 - -#define BQ25710_BC12_MIN_VOLTAGE_MV 1408 - -/* Registers */ -#define BQ25710_REG_CHARGE_OPTION_0 0x12 -#define BQ25710_REG_CHARGE_CURRENT 0x14 -#define BQ25710_REG_MAX_CHARGE_VOLTAGE 0x15 -#define BQ25710_REG_CHARGER_STATUS 0x20 -#define BQ25710_REG_PROCHOT_STATUS 0x21 -#define BQ25710_REG_IIN_DPM 0x22 -#define BQ25710_REG_ADC_VBUS_PSYS 0x23 -#define BQ25710_REG_ADC_IBAT 0x24 -#define BQ25710_REG_ADC_CMPIN_IIN 0x25 -#define BQ25710_REG_ADC_VSYS_VBAT 0x26 -#define BQ25710_REG_CHARGE_OPTION_1 0x30 -#define BQ25710_REG_CHARGE_OPTION_2 0x31 -#define BQ25710_REG_CHARGE_OPTION_3 0x32 -#define BQ25710_REG_PROCHOT_OPTION_0 0x33 -#define BQ25710_REG_PROCHOT_OPTION_1 0x34 -#define BQ25710_REG_ADC_OPTION 0x35 -#ifdef CONFIG_CHARGER_BQ25720 -#define BQ25720_REG_CHARGE_OPTION_4 0x36 -#define BQ25720_REG_VMIN_ACTIVE_PROTECTION 0x37 -#endif -#define BQ25710_REG_OTG_VOLTAGE 0x3B -#define BQ25710_REG_OTG_CURRENT 0x3C -#define BQ25710_REG_INPUT_VOLTAGE 0x3D -#define BQ25710_REG_MIN_SYSTEM_VOLTAGE 0x3E -#define BQ25710_REG_IIN_HOST 0x3F -#define BQ25710_REG_MANUFACTURER_ID 0xFE -#define BQ25710_REG_DEVICE_ADDRESS 0xFF - -/* ChargeOption0 Register */ -#define BQ25710_CHARGE_OPTION_0_LOW_POWER_MODE BIT(15) -#define BQ25710_CHARGE_OPTION_0_IDPM_AUTO_DIS BIT(12) -#define BQ25710_CHARGE_OPTION_0_EN_LEARN BIT(5) -#define BQ25710_CHARGE_OPTION_0_IADP_GAIN BIT(4) -#define BQ25710_CHARGE_OPTION_0_EN_IDPM BIT(1) -#define BQ25710_CHARGE_OPTION_0_CHRG_INHIBIT BIT(0) - -/* ChargeOption2 Register */ -#define BQ25710_CHARGE_OPTION_2_EN_EXTILIM BIT(7) -#define BQ25710_CHARGE_OPTION_2_TMAX_SHIFT 8 -#define BQ25710_CHARGE_OPTION_2_TMAX_MASK (0x3 << \ - BQ25710_CHARGE_OPTION_2_TMAX_SHIFT) - -/* ChargeOption3 Register */ -#define BQ25710_CHARGE_OPTION_3_RESET_REG BIT(14) -#define BQ25710_CHARGE_OPTION_3_EN_ICO_MODE BIT(11) - -/* ChargeStatus Register */ -#define BQ25710_CHARGE_STATUS_ICO_DONE BIT(14) - -/* IIN_DPM Register */ -#define BQ25710_IIN_DPM_CURRENT_SHIFT 8 -#define BQ25710_IIN_DPM_CURRENT_STEP_MA 50 - -/* ADCOption Register */ -#define BQ25710_ADC_OPTION_ADC_START BIT(14) -#define BQ25710_ADC_OPTION_EN_ADC_VBUS BIT(6) -#define BQ25710_ADC_OPTION_EN_ADC_IIN BIT(4) -#define BQ25710_ADC_OPTION_EN_ADC_ALL 0xFF - -/* ADC conversion time ins ms */ -#if defined(CONFIG_CHARGER_BQ25720) -#define BQ25710_ADC_OPTION_ADC_CONV_MS 25 -#elif defined(CONFIG_CHARGER_BQ25710) -#define BQ25710_ADC_OPTION_ADC_CONV_MS 10 -#else -#error Only the BQ25720 and BQ25710 are supported by bq25710 driver. -#endif - -/* ADCVBUS/PSYS Register */ -#if defined(CONFIG_CHARGER_BQ25720) -#define BQ25720_ADC_VBUS_STEP_MV 96 -#elif defined(CONFIG_CHARGER_BQ25710) -#define BQ25710_ADC_VBUS_STEP_MV 64 -#define BQ25710_ADC_VBUS_BASE_MV 3200 -#else -#error Only the BQ25720 and BQ25710 are supported by bq25710 driver. -#endif -#define BQ25710_ADC_VBUS_STEP_BIT_OFFSET 8 - -/* ADCIIN Register */ -#define BQ25710_ADC_IIN_STEP_MA 50 -#define BQ25710_ADC_IIN_STEP_BIT_OFFSET 8 - -/* ProchotOption0 Register */ -#define BQ25710_PROCHOT0_ILIM_VTH_SHIFT 11 -#define BQ25710_PROCHOT0_ILIM_VTH_MASK (0x1f << \ - BQ25710_PROCHOT0_ILIM_VTH_SHIFT) - -/* ProchotOption1 Register */ -#define BQ25710_PROCHOT_PROFILE_VDPM BIT(7) -#define BQ25710_PROCHOT_PROFILE_IDCHG BIT(3) -#define BQ25710_PROCHOT_PROFILE_VSYS BIT(2) -#define BQ25710_PROCHOT_IDCHG_VTH_MASK 0xFC00 - -/* IIN_HOST Register */ -#define BQ25710_IIN_HOST_CURRENT_SHIFT 8 -#define BQ25710_IIN_HOST_CURRENT_STEP_MA 50 - -#if defined(CONFIG_CHARGER_BQ25720) -/* Vmin Active Protection Register */ -#define BQ25720_VMIN_AP_VSYS_TH2_SHIFT 2 -#define BQ25720_VMIN_AP_VSYS_TH2_MASK GENMASK(7, \ - BQ25720_VMIN_AP_VSYS_TH2_SHIFT) -#endif - -/* Min System Voltage Register */ -#if defined(CONFIG_CHARGER_BQ25720) -#define BQ25710_MIN_SYSTEM_VOLTAGE_STEP_MV 100 -#elif defined(CONFIG_CHARGER_BQ25710) -#define BQ25710_MIN_SYSTEM_VOLTAGE_STEP_MV 256 -#else -#error Only the BQ25720 and BQ25710 are supported by bq25710 driver. -#endif -#define BQ25710_MIN_SYSTEM_VOLTAGE_SHIFT 8 - -extern const struct charger_drv bq25710_drv; - -/** - * Set VSYS_MIN - * - * @param chgnum: Index into charger chips - * @param mv: min system voltage in mV - * @return EC_SUCCESS or error - */ -int bq25710_set_min_system_voltage(int chgnum, int mv); - -#endif /* __CROS_EC_BQ25710_H */ diff --git a/driver/charger/isl923x.c b/driver/charger/isl923x.c deleted file mode 100644 index 9e3284c29f..0000000000 --- a/driver/charger/isl923x.c +++ /dev/null @@ -1,1471 +0,0 @@ -/* 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 ISL-9237/8 battery charger driver. - */ - -#include "adc.h" -#include "battery.h" -#include "battery_smart.h" -#include "charge_state_v2.h" -#include "charger.h" -#include "compile_time_macros.h" -#include "console.h" -#include "common.h" -#include "hooks.h" -#include "i2c.h" -#include "isl923x.h" -#include "ocpc.h" -#include "system.h" -#include "task.h" -#include "timer.h" -#include "usb_pd_tcpm.h" -#include "util.h" - -#ifndef CONFIG_CHARGER_NARROW_VDC -#error "ISL9237/8 is a NVDC charger, please enable CONFIG_CHARGER_NARROW_VDC." -#endif - -#if defined(CONFIG_CHARGER_ISL9238) || defined(CONFIG_CHARGER_ISL9238C) -#define CHARGER_ISL9238X -#endif - -#ifdef CONFIG_CHARGER_SENSE_RESISTOR_AC_ISL9238 - #undef CONFIG_CHARGER_SENSE_RESISTOR_AC - #define CONFIG_CHARGER_SENSE_RESISTOR_AC \ - CONFIG_CHARGER_SENSE_RESISTOR_AC_ISL9238 -#endif - - -#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) - -#if defined(CONFIG_CHARGER_ISL9237) -#define CHARGER_NAME "isl9237" -#define CHARGE_V_MAX ISL9237_SYS_VOLTAGE_REG_MAX -#define CHARGE_V_MIN ISL923X_SYS_VOLTAGE_REG_MIN -#define CHARGE_V_STEP 8 -#elif defined(CONFIG_CHARGER_ISL9238) -#define CHARGER_NAME "isl9238" -#define CHARGE_V_MAX ISL9238_SYS_VOLTAGE_REG_MAX -#define CHARGE_V_MIN ISL923X_SYS_VOLTAGE_REG_MIN -#define CHARGE_V_STEP 8 -#elif defined(CONFIG_CHARGER_ISL9238C) -#define CHARGER_NAME "isl9238c" -#define CHARGE_V_MAX ISL9238_SYS_VOLTAGE_REG_MAX -#define CHARGE_V_MIN ISL923X_SYS_VOLTAGE_REG_MIN -#define CHARGE_V_STEP 8 -#elif defined(CONFIG_CHARGER_RAA489000) -#define CHARGER_NAME "raa489000" -#define CHARGE_V_MAX RAA489000_SYS_VOLTAGE_REG_MAX -#define CHARGE_V_MIN RAA489000_SYS_VOLTAGE_REG_MIN -#define CHARGE_V_STEP 8 -#endif - -#ifdef CONFIG_CHARGER_RAA489000 -#define CHARGE_I_MAX RAA489000_CURRENT_REG_MAX -#else -#define CHARGE_I_MAX ISL923X_CURRENT_REG_MAX -#endif /* CONFIG_CHARGER_RAA489000 */ -#define CHARGE_I_MIN 4 -#define CHARGE_I_OFF 0 -#define CHARGE_I_STEP 4 -#ifdef CONFIG_CHARGER_RAA489000 -#define INPUT_I_MAX RAA489000_CURRENT_REG_MAX -#else -#define INPUT_I_MAX ISL923X_CURRENT_REG_MAX -#endif /* CONFIG_CHARGER_RAA489000 */ -#define INPUT_I_MIN 4 -#define INPUT_I_STEP 4 - -/* Console output macros */ -#define CPRINTF(format, args...) cprintf(CC_CHARGER, format, ## args) -#define CPRINTS(format, args...) cprints(CC_CHARGER, format, ## args) - -enum isl923x_amon_bmon { AMON, BMON }; -enum isl923x_mon_dir { MON_CHARGE = 0, MON_DISCHARGE = 1 }; - -static int learn_mode; - -/* Mutex for CONTROL1 register, that can be updated from multiple tasks. */ -K_MUTEX_DEFINE(control1_mutex); - -static enum ec_error_list isl923x_discharge_on_ac(int chgnum, int enable); - -/* 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 enum ec_error_list raw_read8(int chgnum, int offset, int *value) -{ - return i2c_read8(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, - offset, value); -} - -static inline enum ec_error_list raw_read16(int chgnum, int offset, int *value) -{ - return i2c_read16(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, - offset, value); -} - -static inline enum ec_error_list raw_write16(int chgnum, int offset, int value) -{ - return i2c_write16(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, - offset, value); -} - -static inline enum ec_error_list raw_update16(int chgnum, int offset, int mask, - enum mask_update_action action) -{ - return i2c_update16(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, - offset, mask, action); -} - -static enum ec_error_list isl9237_set_current(int chgnum, uint16_t current) -{ - return raw_write16(chgnum, ISL923X_REG_CHG_CURRENT, - CURRENT_TO_REG(current)); -} - -static enum ec_error_list isl9237_set_voltage(int chgnum, uint16_t voltage) -{ - return raw_write16(chgnum, ISL923X_REG_SYS_VOLTAGE_MAX, voltage); -} - -/* chip specific interfaces */ - -static enum ec_error_list isl923x_set_input_current_limit(int chgnum, - int input_current) -{ - int rv; - uint16_t reg = AC_CURRENT_TO_REG(input_current); - - rv = raw_write16(chgnum, ISL923X_REG_ADAPTER_CURRENT_LIMIT1, reg); - if (rv) - return rv; - - return raw_write16(chgnum, ISL923X_REG_ADAPTER_CURRENT_LIMIT2, reg); -} - -#ifdef CONFIG_CMD_CHARGER_ADC_AMON_BMON -static int get_amon_bmon(int chgnum, enum isl923x_amon_bmon amon, - enum isl923x_mon_dir direction, int *adc) -{ - int reg, ret; - - if (IS_ENABLED(CHARGER_ISL9238X)) { - ret = raw_read16(chgnum, ISL9238_REG_CONTROL3, ®); - if (ret) - return ret; - - /* Switch direction */ - if (direction) - reg |= ISL9238_C3_AMON_BMON_DIRECTION; - else - reg &= ~ISL9238_C3_AMON_BMON_DIRECTION; - ret = raw_write16(chgnum, ISL9238_REG_CONTROL3, reg); - if (ret) - return ret; - } - - mutex_lock(&control1_mutex); - - ret = raw_read16(chgnum, ISL923X_REG_CONTROL1, ®); - if (!ret) { - /* Switch between AMON/BMON */ - if (amon == AMON) - reg &= ~ISL923X_C1_SELECT_BMON; - else - reg |= ISL923X_C1_SELECT_BMON; - - /* Enable monitor */ - reg &= ~ISL923X_C1_DISABLE_MON; - ret = raw_write16(chgnum, ISL923X_REG_CONTROL1, reg); - } - - mutex_unlock(&control1_mutex); - - if (ret) - return ret; - - *adc = adc_read_channel(ADC_AMON_BMON); - - return ret; -} -#endif - -static enum ec_error_list isl923x_get_input_current_limit(int chgnum, - int *input_current) -{ - int rv; - int regval; - - rv = raw_read16(chgnum, ISL923X_REG_ADAPTER_CURRENT_LIMIT1, ®val); - if (rv) - return rv; - - *input_current = AC_REG_TO_CURRENT(regval); - return EC_SUCCESS; -} - -#ifdef CONFIG_CHARGER_RAA489000 -static enum ec_error_list raa489000_get_input_current(int chgnum, - int *input_current) -{ - int rv; - int regval; - int reg; - - reg = RAA489000_REG_ADC_INPUT_CURRENT; - - rv = raw_read16(chgnum, reg, ®val); - if (rv) - return rv; - - /* The value is in 22.2mA increments. */ - regval *= 222; - regval /= 10; - - *input_current = AC_REG_TO_CURRENT(regval); - return EC_SUCCESS; -} -#elif defined(CONFIG_CMD_CHARGER_ADC_AMON_BMON) -static enum ec_error_list isl923x_get_input_current(int chgnum, - int *input_current) -{ - int rv, adc; - - rv = get_amon_bmon(chgnum, AMON, MON_CHARGE, &adc); - if (rv) - return rv; - - *input_current = adc / CONFIG_CHARGER_SENSE_RESISTOR_AC; - - return EC_SUCCESS; -} -#endif /* CONFIG_CHARGER_RAA489000 */ - -#if defined(CONFIG_CHARGER_OTG) && defined(CHARGER_ISL9238X) -static enum ec_error_list isl923x_enable_otg_power(int chgnum, int enabled) -{ - int rv, control1; - - mutex_lock(&control1_mutex); - - rv = raw_read16(chgnum, ISL923X_REG_CONTROL1, &control1); - if (rv) - goto out; - - if (enabled) - control1 |= ISL923X_C1_OTG; - else - control1 &= ~ISL923X_C1_OTG; - - rv = raw_write16(chgnum, ISL923X_REG_CONTROL1, control1); - -out: - mutex_unlock(&control1_mutex); - - return rv; -} - -/* - * TODO(b:67920792): OTG is not implemented for ISL9237 that has different - * register scale and range. - */ -static enum ec_error_list isl923x_set_otg_current_voltage(int chgnum, - int output_current, - int output_voltage) -{ - int rv; - uint16_t volt_reg = (output_voltage / ISL9238_OTG_VOLTAGE_STEP) - << ISL9238_OTG_VOLTAGE_SHIFT; - uint16_t current_reg = - DIV_ROUND_UP(output_current, ISL923X_OTG_CURRENT_STEP) - << ISL923X_OTG_CURRENT_SHIFT; - - if (output_current < 0 || output_current > ISL923X_OTG_CURRENT_MAX || - output_voltage > ISL9238_OTG_VOLTAGE_MAX) - return EC_ERROR_INVAL; - - /* Set voltage. */ - rv = raw_write16(chgnum, ISL923X_REG_OTG_VOLTAGE, volt_reg); - if (rv) - return rv; - - /* Set current. */ - return raw_write16(chgnum, ISL923X_REG_OTG_CURRENT, current_reg); -} -#endif /* CONFIG_CHARGER_OTG && CHARGER_ISL9238X */ - -static enum ec_error_list isl923x_manufacturer_id(int chgnum, int *id) -{ - int rv; - int reg; - - rv = raw_read16(chgnum, ISL923X_REG_MANUFACTURER_ID, ®); - if (rv) - return rv; - - *id = reg; - return EC_SUCCESS; -} - -static enum ec_error_list isl923x_device_id(int chgnum, int *id) -{ - int rv; - int reg; - - rv = raw_read16(chgnum, ISL923X_REG_DEVICE_ID, ®); - if (rv) - return rv; - - *id = reg; - return EC_SUCCESS; -} - -static enum ec_error_list isl923x_get_option(int chgnum, int *option) -{ - int rv; - uint32_t controls; - int reg; - - rv = raw_read16(chgnum, ISL923X_REG_CONTROL0, ®); - if (rv) - return rv; - - controls = reg; - rv = raw_read16(chgnum, ISL923X_REG_CONTROL1, ®); - if (rv) - return rv; - - controls |= reg << 16; - *option = controls; - return EC_SUCCESS; -} - -static enum ec_error_list isl923x_set_option(int chgnum, int option) -{ - int rv; - uint16_t reg; - - reg = option & 0xffff; - rv = raw_write16(chgnum, ISL923X_REG_CONTROL0, reg); - - if (rv) - return rv; - - reg = (option >> 16) & 0xffff; - return raw_write16(chgnum, ISL923X_REG_CONTROL1, reg); -} - -/* Charger interfaces */ - -static const struct charger_info *isl923x_get_info(int chgnum) -{ - return &isl9237_charger_info; -} - -static enum ec_error_list isl923x_get_status(int chgnum, int *status) -{ - *status = CHARGER_LEVEL_2; - - return EC_SUCCESS; -} - -static enum ec_error_list isl923x_set_mode(int chgnum, int mode) -{ - int rv = EC_SUCCESS; - - /* - * See crosbug.com/p/51196. Always disable learn mode unless it was set - * explicitly. - */ - if (!learn_mode) - rv = isl923x_discharge_on_ac(chgnum, 0); - - /* ISL923X does not support inhibit mode setting. */ - return rv; -} - -#ifdef CONFIG_CHARGER_RAA489000 -static enum ec_error_list raa489000_get_actual_current(int chgnum, int *current) -{ - int rv; - int reg; - - rv = raw_read16(chgnum, RAA489000_REG_ADC_CHARGE_CURRENT, ®); - /* The value is in 22.2mA increments. */ - reg *= 222; - reg /= 10; - - *current = REG_TO_CURRENT(reg); - return rv; -} -#endif /* CONFIG_CHARGER_RAA489000 */ - -static enum ec_error_list isl923x_get_current(int chgnum, int *current) -{ - int rv; - int reg; - - rv = raw_read16(chgnum, ISL923X_REG_CHG_CURRENT, ®); - if (rv) - return rv; - - *current = REG_TO_CURRENT(reg); - return EC_SUCCESS; -} - -static enum ec_error_list isl923x_set_current(int chgnum, int current) -{ - return isl9237_set_current(chgnum, current); -} - -#ifdef CONFIG_CHARGER_RAA489000 -static enum ec_error_list raa489000_get_actual_voltage(int chgnum, int *voltage) -{ - int rv; - int reg; - - rv = raw_read16(chgnum, RAA489000_REG_ADC_VSYS, ®); - if (rv) - return rv; - - /* The voltage is returned in bits 13:6. LSB is 96mV. */ - reg &= GENMASK(13, 6); - reg >>= 6; - reg *= 96; - - *voltage = reg; - return EC_SUCCESS; -} -#endif /* CONFIG_CHARGER_RAA489000 */ - -static enum ec_error_list isl923x_get_voltage(int chgnum, int *voltage) -{ - return raw_read16(chgnum, ISL923X_REG_SYS_VOLTAGE_MAX, voltage); -} - -static enum ec_error_list isl923x_set_voltage(int chgnum, int voltage) -{ - /* The ISL923X 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 ISL923X - * 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(chgnum, voltage); -} - -static enum ec_error_list isl923x_post_init(int chgnum) -{ - /* - * charger_post_init() is called every time AC becomes present in the - * system. It's called this frequently because there are some charger - * ICs which become unpowered when AC is not present. Therefore, upon - * AC becoming present again, the chargers need to be reinitialized. - * The ISL9237/8 can be powered from VSYS and therefore do not need to - * be reinitialized everytime. This is why isl923x_init() is called - * once at HOOK_INIT time. - */ - return EC_SUCCESS; -} - -int isl923x_set_ac_prochot(int chgnum, uint16_t ma) -{ - int rv; - - if (ma > ISL923X_AC_PROCHOT_CURRENT_MAX) { - CPRINTS("%s: invalid current (%d mA)", CHARGER_NAME, ma); - return EC_ERROR_INVAL; - } - - rv = raw_write16(chgnum, ISL923X_REG_PROCHOT_AC, AC_CURRENT_TO_REG(ma)); - if (rv) - CPRINTS("%s set_ac_prochot failed (%d)", CHARGER_NAME, rv); - return rv; -} - -int isl923x_set_dc_prochot(int chgnum, uint16_t ma) -{ - int rv; - - if (ma > ISL923X_DC_PROCHOT_CURRENT_MAX) { - CPRINTS("%s: invalid current (%d mA)", CHARGER_NAME, ma); - return EC_ERROR_INVAL; - } - - rv = raw_write16(chgnum, ISL923X_REG_PROCHOT_DC, CURRENT_TO_REG(ma)); - if (rv) - CPRINTS("%s set_dc_prochot failed (%d)", CHARGER_NAME, rv); - return rv; -} - -int isl923x_set_comparator_inversion(int chgnum, int invert) -{ - int rv; - int regval; - - rv = i2c_read16(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, - ISL923X_REG_CONTROL2, ®val); - if (invert) - regval |= ISL923X_C2_INVERT_CMOUT; - else - regval &= ~ISL923X_C2_INVERT_CMOUT; - - if (!rv) - rv |= i2c_write16(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, - ISL923X_REG_CONTROL2, regval); - - if (rv) - CPRINTS("%s (%d) set_comparator_inversion failed (rv: %d)", - CHARGER_NAME, chgnum, rv); - - return rv; -} - -static void isl923x_init(int chgnum) -{ - int reg; - const struct battery_info *bi = battery_get_info(); - int precharge_voltage = bi->precharge_voltage ? - bi->precharge_voltage : bi->voltage_min; - - if (IS_ENABLED(CONFIG_CHARGER_RAA489000)) { - if (CONFIG_CHARGER_SENSE_RESISTOR == - CONFIG_CHARGER_SENSE_RESISTOR_AC) { - /* - * A 1:1 ratio for Rs1:Rs2 is allowed, but Control4 - * register Bit<11> must be set. - */ - if (raw_read16(chgnum, ISL9238_REG_CONTROL4, ®)) - goto init_fail; - - if (raw_write16(chgnum, ISL9238_REG_CONTROL4, - reg | - RAA489000_C4_PSYS_RSNS_RATIO_1_TO_1)) - goto init_fail; - } - - /* - * Enable hysteresis for CCM/DCM boundary to help with ripple. - */ - if (raw_read16(chgnum, ISL9238_REG_CONTROL3, ®)) - goto init_fail; - - if (raw_write16(chgnum, ISL9238_REG_CONTROL3, - reg | - RAA489000_C3_DCM_CCM_HYSTERESIS_ENABLE)) - goto init_fail; - - /* Set switching frequency to 600KHz to help with ripple. */ - if (raw_read16(chgnum, ISL923X_REG_CONTROL1, ®)) - goto init_fail; - - reg &= ~ISL923X_C1_SWITCH_FREQ_MASK; - - if (raw_write16(chgnum, ISL923X_REG_CONTROL1, - reg | - ISL9237_C1_SWITCH_FREQ_599K)) - goto init_fail; - } - - if (IS_ENABLED(CONFIG_TRICKLE_CHARGING)) - if (raw_write16(chgnum, ISL923X_REG_SYS_VOLTAGE_MIN, - precharge_voltage)) - goto init_fail; - - /* - * [10:9]: Prochot# Debounce time - * 11b: 1ms - */ - if (raw_read16(chgnum, ISL923X_REG_CONTROL2, ®)) - goto init_fail; - - if (!IS_ENABLED(CONFIG_CHARGER_RAA489000)) - reg |= ISL923X_C2_OTG_DEBOUNCE_150; - - if (IS_ENABLED(CONFIG_CHARGER_RAA489000)) - reg |= ISL923X_C2_PROCHOT_DEBOUNCE_500; - else - reg |= ISL923X_C2_PROCHOT_DEBOUNCE_1000; - - if (raw_write16(chgnum, ISL923X_REG_CONTROL2, - reg | - ISL923X_C2_ADAPTER_DEBOUNCE_150)) - goto init_fail; - - if (IS_ENABLED(CONFIG_CHARGE_RAMP_HW)) { - if (IS_ENABLED(CONFIG_CHARGER_ISL9237)) { - if (raw_read16(chgnum, ISL923X_REG_CONTROL0, ®)) - goto init_fail; - - /* - * Set input voltage regulation reference voltage for - * charge ramp. - */ - reg &= ~ISL9237_C0_VREG_REF_MASK; - reg |= ISL9237_C0_VREG_REF_4200; - - if (raw_write16(chgnum, ISL923X_REG_CONTROL0, reg)) - goto init_fail; - } else { - /* - * For the ISL9238, set the input voltage regulation to - * 4.439V. Note, the voltage is set in 341.3 mV steps. - * - * For the RAA489000, set the input voltage regulation - * to 4.437V. Note, that the voltage is set in 85.33 mV - * steps. - */ - if (IS_ENABLED(CONFIG_CHARGER_RAA489000)) - reg = (4437 / RAA489000_INPUT_VOLTAGE_REF_STEP) - << RAA489000_INPUT_VOLTAGE_REF_SHIFT; - else - reg = (4439 / ISL9238_INPUT_VOLTAGE_REF_STEP) - << ISL9238_INPUT_VOLTAGE_REF_SHIFT; - - if (raw_write16(chgnum, ISL9238_REG_INPUT_VOLTAGE, reg)) - goto init_fail; - } - } else { - if (raw_read16(chgnum, ISL923X_REG_CONTROL0, ®)) - goto init_fail; - - /* Disable voltage regulation loop to disable charge ramp */ - reg |= ISL923X_C0_DISABLE_VREG; - - if (raw_write16(chgnum, ISL923X_REG_CONTROL0, reg)) - goto init_fail; - } - - if (IS_ENABLED(CONFIG_CHARGER_ISL9238C)) { - /* b/155366741: enable slew rate control */ - if (raw_read16(chgnum, ISL9238C_REG_CONTROL6, ®)) - goto init_fail; - - reg |= ISL9238C_C6_SLEW_RATE_CONTROL; - - if (raw_write16(chgnum, ISL9238C_REG_CONTROL6, reg)) - goto init_fail; - } - - if (IS_ENABLED(CONFIG_CHARGER_RAA489000)) { - /* - * Return the BFET to normal operation as it may have been - * turned off when entering hibernate. - */ - if (raw_read16(chgnum, ISL923X_REG_CONTROL1, ®)) - goto init_fail; - reg &= ~RAA489000_C1_BGATE_FORCE_OFF; - if (raw_write16(chgnum, ISL923X_REG_CONTROL1, reg)) - goto init_fail; - } - - /* Revert all changes done by isl9238c_hibernate(). */ - if (IS_ENABLED(CONFIG_CHARGER_ISL9238C) && isl9238c_resume(chgnum)) - goto init_fail; - - if (IS_ENABLED(CHARGER_ISL9238X) || - IS_ENABLED(CONFIG_CHARGER_RAA489000)) { - /* - * Don't reread the prog pin and don't reload the ILIM on ACIN. - * For the RAA489000, just don't reload ACLIM. - */ - if (raw_read16(chgnum, ISL9238_REG_CONTROL3, ®)) - goto init_fail; - reg |= ISL9238_C3_NO_RELOAD_ACLIM_ON_ACIN; - if (!IS_ENABLED(CONFIG_CHARGER_RAA489000)) - reg |= ISL9238_C3_NO_REREAD_PROG_PIN; - - /* - * Disable autonomous charging initially since 1) it causes boot - * loop issues with 2S batteries, and 2) it will automatically - * get disabled as soon as we manually set the current limit - * anyway. - * - * Note: This bit is inverted on the RAA489000. - */ - if (IS_ENABLED(CONFIG_CHARGER_RAA489000)) - reg &= ~ISL9238_C3_DISABLE_AUTO_CHARING; - else - reg |= ISL9238_C3_DISABLE_AUTO_CHARING; - if (raw_write16(chgnum, ISL9238_REG_CONTROL3, reg)) - goto init_fail; - - /* - * No need to proceed with the rest of init if we sysjump'd to - * this image as the input current limit has already been set. - */ - if (system_jumped_late()) - return; - - /* - * Initialize the input current limit to the board's default. - */ - if (isl923x_set_input_current_limit( - chgnum, CONFIG_CHARGER_INPUT_CURRENT)) - goto init_fail; - } - -#ifdef CONFIG_OCPC - if (IS_ENABLED(CONFIG_CHARGER_RAA489000)) { - /* - * Ignore BATGONE on auxiliary charger ICs as it's not connected - * there. - * Clear DISABLE_GP_CMP & MCU_LDO_BAT_STATE_DISABLE to - * enable ALERT_B with control the power of sub-board - */ - if (chgnum != CHARGER_PRIMARY) { - if (raw_read16(chgnum, ISL9238_REG_CONTROL4, ®)) - goto init_fail; - - reg |= RAA489000_C4_BATGONE_DISABLE; - reg &= ~RAA489000_C4_DISABLE_GP_CMP; - - if (raw_write16(chgnum, ISL9238_REG_CONTROL4, reg)) - goto init_fail; - - if (raw_read16(chgnum, RAA489000_REG_CONTROL8, ®)) - goto init_fail; - - reg &= ~RAA489000_C8_MCU_LDO_BAT_STATE_DISABLE; - - if (raw_write16(chgnum, RAA489000_REG_CONTROL8, reg)) - goto init_fail; - } - } -#endif /* CONFIG_OCPC */ - - return; -init_fail: - CPRINTS("%s init failed!", CHARGER_NAME); -} - -static enum ec_error_list isl923x_discharge_on_ac(int chgnum, int enable) -{ - int rv; - int control1; - - mutex_lock(&control1_mutex); - - rv = raw_read16(chgnum, ISL923X_REG_CONTROL1, &control1); - if (rv) - goto out; - - control1 &= ~ISL923X_C1_LEARN_MODE_AUTOEXIT; - if (enable) - control1 |= ISL923X_C1_LEARN_MODE_ENABLE; - else - control1 &= ~ISL923X_C1_LEARN_MODE_ENABLE; - - rv = raw_write16(chgnum, ISL923X_REG_CONTROL1, control1); - - learn_mode = !rv && enable; - -out: - mutex_unlock(&control1_mutex); - return rv; -} - -#ifdef CONFIG_CHARGER_RAA489000 -enum ec_error_list raa489000_is_acok(int chgnum, bool *acok) -{ - int regval, rv; - - if ((chgnum < 0) || (chgnum > board_get_charger_chip_count())) { - CPRINTS("%s: Invalid chgnum! (%d)", __func__, chgnum); - return EC_ERROR_INVAL; - } - - rv = raw_read16(chgnum, ISL9238_REG_INFO2, ®val); - if (rv != EC_SUCCESS) - return rv; - *acok = (regval & RAA489000_INFO2_ACOK); - - return EC_SUCCESS; -} - -int raa489000_enable_asgate(int chgnum, bool enable) -{ - enum mask_update_action action = enable ? MASK_SET : MASK_CLR; - - return raw_update16(chgnum, RAA489000_REG_CONTROL8, - RAA489000_C8_ASGATE_ON_READY, action); -} - -void raa489000_hibernate(int chgnum, bool disable_adc) -{ - int rv, regval; - - if ((chgnum < 0) || (chgnum > board_get_charger_chip_count())) { - CPRINTS("%s: Invalid chgnum! (%d)", __func__, chgnum); - return; - } - - rv = raw_read16(chgnum, ISL923X_REG_CONTROL0, ®val); - if (!rv) { - /* set BGATE to normal operation */ - regval &= ~RAA489000_C0_BGATE_FORCE_ON; - - /* set normal charge pump operation */ - regval &= ~RAA489000_C0_EN_CHG_PUMPS_TO_100PCT; - - rv = raw_write16(chgnum, ISL923X_REG_CONTROL0, regval); - } - if (rv) - CPRINTS("%s(%d): Failed to set Control0!", __func__, chgnum); - - rv = raw_read16(chgnum, ISL923X_REG_CONTROL1, ®val); - if (!rv) { - /* Disable Supplemental support */ - regval &= ~RAA489000_C1_ENABLE_SUPP_SUPPORT_MODE; - - /* - * Force BGATE off. For devices that utilize the Z-state, the - * LDO will be powered through the BFET's body diode. - */ - regval |= RAA489000_C1_BGATE_FORCE_OFF; - - /* Disable AMON/BMON */ - regval |= ISL923X_C1_DISABLE_MON; - - /* Disable PSYS */ - regval &= ~ISL923X_C1_ENABLE_PSYS; - - rv = raw_write16(chgnum, ISL923X_REG_CONTROL1, regval); - } - if (rv) - CPRINTS("%s(%d): Failed to set Control1!", __func__, chgnum); - - rv = raw_read16(chgnum, ISL9238_REG_CONTROL3, ®val); - if (!rv) { - if (disable_adc) - /* ADC is active only when adapter plugged in */ - regval &= ~RAA489000_ENABLE_ADC; - else - regval |= RAA489000_ENABLE_ADC; - - rv = raw_write16(chgnum, ISL9238_REG_CONTROL3, regval); - } - if (rv) - CPRINTS("%s(%d): Failed to set Control3!", __func__, chgnum); - - rv = raw_read16(chgnum, ISL9238_REG_CONTROL4, ®val); - if (!rv) { - /* Disable GP comparator for battery only mode */ - regval |= RAA489000_C4_DISABLE_GP_CMP; - - rv = raw_write16(chgnum, ISL9238_REG_CONTROL4, regval); - } - if (rv) - CPRINTS("%s(%d):Failed to set Control4!", __func__, chgnum); - -#ifdef CONFIG_OCPC - /* The LDO is needed in the Z-state on the primary charger */ - if (chgnum != CHARGER_PRIMARY) { - rv = raw_read16(chgnum, RAA489000_REG_CONTROL8, ®val); - if (!rv) { - /* Disable MCU LDO in battery state */ - regval |= RAA489000_C8_MCU_LDO_BAT_STATE_DISABLE; - - rv = raw_write16(chgnum, RAA489000_REG_CONTROL8, - regval); - } - if (rv) - CPRINTS("%s(%d):Failed to set Control8!", __func__, - chgnum); - } - - /* Disable DVC on the main charger to reduce power consumption. */ - if (chgnum == CHARGER_PRIMARY) { - rv = raw_write16(chgnum, RAA489000_REG_CONTROL10, 0); - if (rv) - CPRINTS("%s(%d):Failed to set Control10!", __func__, - chgnum); - } -#endif - - cflush(); -} -#endif /* CONFIG_CHARGER_RAA489000 */ - -#ifdef CONFIG_CHARGER_ISL9238C -enum ec_error_list isl9238c_hibernate(int chgnum) -{ - /* Disable IMON */ - RETURN_ERROR(raw_update16(chgnum, ISL923X_REG_CONTROL1, - ISL923X_C1_DISABLE_MON, MASK_SET)); - - /* Disable PSYS */ - RETURN_ERROR(raw_update16(chgnum, ISL923X_REG_CONTROL1, - ISL923X_C1_ENABLE_PSYS, MASK_CLR)); - - /* Disable GP comparator */ - RETURN_ERROR(raw_update16(chgnum, ISL923X_REG_CONTROL2, - ISL923X_C2_COMPARATOR, MASK_SET)); - - /* Force BGATE off */ - RETURN_ERROR(raw_update16(chgnum, ISL9238_REG_CONTROL3, - ISL9238_C3_BGATE_OFF, MASK_SET)); - - - return EC_SUCCESS; -} - -enum ec_error_list isl9238c_resume(int chgnum) -{ - /* Revert everything in isl9238c_hibernate() */ - RETURN_ERROR(raw_update16(chgnum, ISL923X_REG_CONTROL1, - ISL923X_C1_DISABLE_MON, MASK_CLR)); - - RETURN_ERROR(raw_update16(chgnum, ISL923X_REG_CONTROL1, - ISL923X_C1_ENABLE_PSYS, MASK_SET)); - - RETURN_ERROR(raw_update16(chgnum, ISL923X_REG_CONTROL2, - ISL923X_C2_COMPARATOR, MASK_CLR)); - - RETURN_ERROR(raw_update16(chgnum, ISL9238_REG_CONTROL3, - ISL9238_C3_BGATE_OFF, MASK_CLR)); - - return EC_SUCCESS; -} -#endif /* CONFIG_CHARGER_ISL9238C */ - - -/*****************************************************************************/ -/* Hardware current ramping */ - -#ifdef CONFIG_CHARGE_RAMP_HW -static enum ec_error_list isl923x_set_hw_ramp(int chgnum, int enable) -{ - int rv, reg; - - rv = raw_read16(chgnum, ISL923X_REG_CONTROL0, ®); - if (rv) - return rv; - - /* HW ramp is controlled by input voltage regulation reference bits */ - if (enable) - reg &= ~ISL923X_C0_DISABLE_VREG; - else - reg |= ISL923X_C0_DISABLE_VREG; - - return raw_write16(chgnum, ISL923X_REG_CONTROL0, reg); -} - -static int isl923x_ramp_is_stable(int chgnum) -{ - /* - * Since ISL cannot read the current limit that the ramp has settled - * on, then we can never consider the ramp stable, because we never - * know what the stable limit is. - */ - return 0; -} - -static int isl923x_ramp_is_detected(int chgnum) -{ - return 1; -} - -static int isl923x_ramp_get_current_limit(int chgnum) -{ - /* - * ISL doesn't have a way to get this info, so return the nominal - * current limit as an estimate. - */ - int input_current; - - if (isl923x_get_input_current_limit(chgnum, &input_current)) - return 0; - return input_current; -} -#endif /* CONFIG_CHARGE_RAMP_HW */ - - -#ifdef CONFIG_CHARGER_PSYS -static int psys_enabled; -/* - * TODO(b/147440290): Set to appropriate charger with multiple charger support, - * hardcode to 0 for now - */ -static void charger_enable_psys(void) -{ - int val; - - mutex_lock(&control1_mutex); - - /* - * enable system power monitor PSYS function - */ - if (raw_read16(CHARGER_SOLO, ISL923X_REG_CONTROL1, &val)) - goto out; - - val |= ISL923X_C1_ENABLE_PSYS; - - if (raw_write16(CHARGER_SOLO, ISL923X_REG_CONTROL1, val)) - goto out; - - psys_enabled = 1; - -out: - mutex_unlock(&control1_mutex); -} -DECLARE_HOOK(HOOK_CHIPSET_RESUME, charger_enable_psys, HOOK_PRIO_DEFAULT); - -static void charger_disable_psys(void) -{ - int val; - - mutex_lock(&control1_mutex); - - /* - * disable system power monitor PSYS function - */ - if (raw_read16(CHARGER_SOLO, ISL923X_REG_CONTROL1, &val)) - goto out; - - val &= ~ISL923X_C1_ENABLE_PSYS; - - if (raw_write16(CHARGER_SOLO, ISL923X_REG_CONTROL1, val)) - goto out; - - psys_enabled = 0; - -out: - mutex_unlock(&control1_mutex); -} -DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, charger_disable_psys, HOOK_PRIO_DEFAULT); - -#ifdef CONFIG_CHARGER_PSYS_READ -int charger_get_system_power(void) -{ - int adc; - - /* - * If PSYS is not enabled, AP is probably off, and the value is usually - * too small to be measured acurately anyway. - */ - if (!psys_enabled) - return -1; - - /* - * We assume that the output gain is always left to the default - * 1.44 uA/W, and that the ADC scaling values are setup accordingly in - * board file, so that the value is indicated in uW. - */ - adc = adc_read_channel(ADC_PSYS); - - return adc; -} - -static int console_command_psys(int argc, char **argv) -{ - ccprintf("PSYS = %d uW\n", charger_get_system_power()); - return 0; -} -DECLARE_CONSOLE_COMMAND(psys, console_command_psys, - NULL, - "Get the system power in mW"); -#endif /* CONFIG_CHARGER_PSYS_READ */ -#endif /* CONFIG_CHARGER_PSYS */ - -#ifdef CONFIG_CMD_CHARGER_ADC_AMON_BMON -static int print_amon_bmon(int chgnum, enum isl923x_amon_bmon amon, - enum isl923x_mon_dir direction, int resistor) -{ - int ret, adc, curr; - - ret = get_amon_bmon(chgnum, amon, direction, &adc); - if (ret) - return ret; - - curr = adc / resistor; - ccprintf("%cMON(%sharging): %d uV, %d mA\n", amon == AMON ? 'A' : 'B', - direction == MON_DISCHARGE ? "Disc" : "C", adc, curr); - - return ret; -} - -/** - * Get charger AMON and BMON current. - */ -static int console_command_amon_bmon(int argc, char **argv) -{ - int ret = EC_SUCCESS; - int print_ac = 1; - int print_battery = 1; - int print_charge = 1; - int print_discharge = 1; - int chgnum = 0; - char *e; - - if (argc >= 2) { - print_ac = (argv[1][0] == 'a'); - print_battery = (argv[1][0] == 'b'); - if (IS_ENABLED(CHARGER_ISL9238X) && argv[1][1] != '\0') { - print_charge = (argv[1][1] == 'c'); - print_discharge = (argv[1][1] == 'd'); - } - if (argc >= 3) { - chgnum = strtoi(argv[2], &e, 10); - if (*e) - return EC_ERROR_PARAM2; - } - } - - if (print_ac) { - if (print_charge) - ret |= print_amon_bmon(chgnum, AMON, MON_CHARGE, - CONFIG_CHARGER_SENSE_RESISTOR_AC); - if (IS_ENABLED(CHARGER_ISL9238X) && print_discharge) - ret |= print_amon_bmon(chgnum, AMON, MON_DISCHARGE, - CONFIG_CHARGER_SENSE_RESISTOR_AC); - } - - if (print_battery) { - if (IS_ENABLED(CHARGER_ISL9238X) && print_charge) - ret |= print_amon_bmon(chgnum, BMON, MON_CHARGE, - /* - * charging current monitor has - * 2x amplification factor - */ - 2 * CONFIG_CHARGER_SENSE_RESISTOR); - if (print_discharge) - ret |= print_amon_bmon(chgnum, BMON, MON_DISCHARGE, - CONFIG_CHARGER_SENSE_RESISTOR); - } - - return ret; -} -DECLARE_CONSOLE_COMMAND(amonbmon, console_command_amon_bmon, -#ifdef CONFIG_CHARGER_ISL9237 - "amonbmon [a|b] <chgnum>", -#else - "amonbmon [a[c|d]|b[c|d]] <chgnum>", -#endif - "Get charger AMON/BMON voltage diff, current"); -#endif /* CONFIG_CMD_CHARGER_ADC_AMON_BMON */ - -#ifdef CONFIG_CMD_CHARGER_DUMP -static void dump_reg_range(int chgnum, int low, int high) -{ - int reg; - int regval; - int rv; - - for (reg = low; reg <= high; reg++) { - CPRINTF("[%Xh] = ", reg); - rv = i2c_read16(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, - reg, ®val); - if (!rv) - CPRINTF("0x%04x\n", regval); - else - CPRINTF("ERR (%d)\n", rv); - cflush(); - } -} - -static int command_isl923x_dump(int argc, char **argv) -{ - int chgnum = 0; - char *e; - - if (argc >= 2) { - chgnum = strtoi(argv[1], &e, 10); - if (*e) - return EC_ERROR_PARAM1; - } - - dump_reg_range(chgnum, 0x14, 0x15); - if (IS_ENABLED(CONFIG_CHARGER_ISL9238C)) - dump_reg_range(chgnum, 0x37, 0x37); - dump_reg_range(chgnum, 0x38, 0x3F); - dump_reg_range(chgnum, 0x47, 0x4A); - if (IS_ENABLED(CHARGER_ISL9238X) || - IS_ENABLED(CONFIG_CHARGER_RAA489000)) - dump_reg_range(chgnum, 0x4B, 0x4E); - dump_reg_range(chgnum, 0xFE, 0xFF); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(charger_dump, command_isl923x_dump, - "charger_dump <chgnum>", "Dumps ISL923x registers"); -#endif /* CONFIG_CMD_CHARGER_DUMP */ - -static enum ec_error_list isl923x_get_vbus_voltage(int chgnum, int port, - int *voltage) -{ - int val; - int rv; - - rv = raw_read16(chgnum, RAA489000_REG_ADC_VBUS, &val); - if (rv) - return rv; - - /* The VBUS voltage is returned in bits 13:6. The LSB is 96mV. */ - val &= GENMASK(13, 6); - val = val >> 6; - val *= 96; - *voltage = val; - - return EC_SUCCESS; -} - -#if defined(CONFIG_CHARGER_RAA489000) && defined(CONFIG_OCPC) -static enum ec_error_list raa489000_enable_linear_charge(int chgnum, - bool enable) -{ - const struct battery_info *batt_info; - int trickle_regval; - int precharge_current; - int regval; - enum ec_error_list rv; - int act_chg = charge_get_active_chg_chip(); - - batt_info = battery_get_info(); - - if (enable) { - /* Set the auxiliary max VSYS to 300mV + min VSYS. */ - rv = isl9237_set_voltage(act_chg, batt_info->voltage_min + 300); - - /* Disable charge current loop for the aux charger. */ - rv |= raw_update16(act_chg, RAA489000_REG_CONTROL10, - RAA489000_C10_DISABLE_DVC_CC_LOOP, - MASK_SET); - - /* - * Set primary charger charge current to the desired precharge - * current. - */ - rv |= isl9237_set_current(CHARGER_PRIMARY, - batt_info->precharge_current); - - /* - * Set primary charger max VSYS to the max of the battery. - */ - rv |= isl9237_set_voltage(CHARGER_PRIMARY, - batt_info->voltage_max); - - /* - * Set trickle charging level. - * - * 64mA is the minimum current level we must set. - */ - precharge_current = MAX(64, batt_info->precharge_current); - trickle_regval = precharge_current / 32; - trickle_regval--; /* convert to 0-based field */ - rv |= raw_read16(CHARGER_PRIMARY, ISL923X_REG_CONTROL2, - ®val); - regval &= ~(GENMASK(15, 13)); - regval |= trickle_regval << 13; - rv |= raw_write16(CHARGER_PRIMARY, ISL923X_REG_CONTROL2, - regval); - - /* Enable DVC trickle charge and DVC charge mode. */ - rv |= raw_update16(CHARGER_PRIMARY, RAA489000_REG_CONTROL10, - RAA489000_C10_ENABLE_DVC_MODE | - RAA489000_C10_ENABLE_DVC_TRICKLE_CHARGE, - MASK_SET); - - if (rv) - return EC_ERROR_UNKNOWN; - - } else { - /* Disable DVC trickle charge. */ - rv = raw_update16(CHARGER_PRIMARY, RAA489000_REG_CONTROL10, - RAA489000_C10_ENABLE_DVC_TRICKLE_CHARGE, - MASK_CLR); - } - - return rv; -} - -static enum ec_error_list raa489000_set_vsys_compensation(int chgnum, - struct ocpc_data *o, - int current_ma, - int voltage_mv) -{ - int device_id = 0; - int rv; - int rp1; - int rp2; - int regval; - - /* This should never be called against the primary charger. */ - ASSERT(chgnum != CHARGER_PRIMARY); - - /* Only B0+ silicon supports VSYS compensation. */ - rv = isl923x_device_id(chgnum, &device_id); - if (rv) - return EC_ERROR_UNKNOWN; - - /* - * Note: this makes the assumption that this charger IC is used on the - * primary port as well. - */ - - if (device_id < RAA489000_DEV_ID_B0) - return EC_ERROR_UNIMPLEMENTED; - - /* - * Need to set board resistance values: Rp1 and Rp2. These are expected - * to be fairly constant once we are able to calculate their values. - * - * Rp1 is the total resistance from the right-hand side of the - * auxiliary sense resistor to the actual VSYS node. It should include: - * a. resistance of sub board sense resistor - * b. connector/cable resistance - * c. sub board PCB resistance to the actual VSYS node - * - * Rp2 is the total resistance from the actual VSYS node to the battery. - * It should include: - * a. resistance of primary charger sense resistor (battery side) - * b. Rds(on) of BGATE FET - * c. main board PCB resistance to the battery - * d. battery internal resistance - */ - - /* - * Rp1 is set between 36-156mOhms in 4mOhm increments. This must be - * non-zero in order for compensation to work. - * - * To get Rp1, we need to look at the delta between VSYS measured by the - * auxiliary charger IC and the primary charger IC where the actual VSYS - * node is as well as the current provided by the auxiliary charger IC. - * The system keeps track of combined resistance; therefore, Rp2 is the - * difference between the combined resistance and Rp1 that we calculate. - * If Rp1 is less than 36mOhms, then the compensation is disabled. - */ - - rp1 = MIN(o->rsys_mo, RAA489000_RP1_MAX); - rp1 -= RAA489000_RP1_MIN; - if (rp1 < 0) { - if (o->last_vsys == OCPC_UNINIT) - CPRINTS("RAA489000(%d): Disabling DVC (Rp1 < 36mOhms)", - chgnum); - rp1 = 0; - } else { - rp1 /= 4; - rp1++; /* Rp1 min starts at register value 1 */ - } - - /* Rp2 is set between 0-124mOhms in 4mOhm increments. */ - rp2 = o->rbatt_mo; - rp2 = CLAMP(rp2, RAA489000_RP2_MIN, RAA489000_RP2_MAX); - rp2 /= 4; - - rv |= raw_read16(chgnum, RAA489000_REG_CONTROL10, ®val); - if (!rv) { - /* Set Rp1 and Rp2 */ - regval &= ~RAA489000_C10_RP1_MASK; - regval &= ~RAA489000_C10_RP2_MASK; - regval |= rp2; - regval |= (rp1 << RAA489000_C10_RP1_SHIFT); - - /* Enable DVC mode */ - regval |= RAA489000_C10_ENABLE_DVC_MODE; - - /* Disable charge current loop */ - regval |= RAA489000_C10_DISABLE_DVC_CC_LOOP; - - rv |= raw_write16(chgnum, RAA489000_REG_CONTROL10, regval); - } - - if (rv) { - CPRINTS("%s(%d) Failed to enable DVC!", __func__, chgnum); - return EC_ERROR_UNKNOWN; - } - - /* Lastly, enable DVC fast charge mode for the primary charger IC. */ - rv = raw_read16(CHARGER_PRIMARY, RAA489000_REG_CONTROL10, ®val); - regval |= RAA489000_C10_ENABLE_DVC_CHARGE_MODE; - rv |= raw_write16(CHARGER_PRIMARY, RAA489000_REG_CONTROL10, regval); - if (rv) { - CPRINTS("%s Failed to enable DVC on primary charger!", - __func__); - return EC_ERROR_UNKNOWN; - } - - /* - * We'll need to use the PID loop in order to properly set VSYS such - * such that we get the desired charge current. - */ - return EC_ERROR_UNIMPLEMENTED; -} -#endif /* CONFIG_CHARGER_RAA489000 && CONFIG_OCPC */ - -const struct charger_drv isl923x_drv = { - .init = &isl923x_init, - .post_init = &isl923x_post_init, - .get_info = &isl923x_get_info, - .get_status = &isl923x_get_status, - .set_mode = &isl923x_set_mode, -#if defined(CONFIG_CHARGER_OTG) && defined(CHARGER_ISL9238X) - .enable_otg_power = &isl923x_enable_otg_power, - .set_otg_current_voltage = &isl923x_set_otg_current_voltage, -#endif -#ifdef CONFIG_CHARGER_RAA489000 - .get_actual_current = &raa489000_get_actual_current, -#endif - .get_current = &isl923x_get_current, - .set_current = &isl923x_set_current, -#ifdef CONFIG_CHARGER_RAA489000 - .get_actual_voltage = &raa489000_get_actual_voltage, -#endif - .get_voltage = &isl923x_get_voltage, - .set_voltage = &isl923x_set_voltage, - .discharge_on_ac = &isl923x_discharge_on_ac, - .get_vbus_voltage = &isl923x_get_vbus_voltage, - .set_input_current_limit = &isl923x_set_input_current_limit, - .get_input_current_limit = &isl923x_get_input_current_limit, -#ifdef CONFIG_CHARGER_RAA489000 - .get_input_current = &raa489000_get_input_current, -#elif defined(CONFIG_CMD_CHARGER_ADC_AMON_BMON) - .get_input_current = &isl923x_get_input_current, -#endif - .manufacturer_id = &isl923x_manufacturer_id, - .device_id = &isl923x_device_id, - .get_option = &isl923x_get_option, - .set_option = &isl923x_set_option, -#ifdef CONFIG_CHARGE_RAMP_HW - .set_hw_ramp = &isl923x_set_hw_ramp, - .ramp_is_stable = &isl923x_ramp_is_stable, - .ramp_is_detected = &isl923x_ramp_is_detected, - .ramp_get_current_limit = &isl923x_ramp_get_current_limit, -#endif -#if defined(CONFIG_CHARGER_RAA489000) && defined(CONFIG_OCPC) - .enable_linear_charge = &raa489000_enable_linear_charge, - .set_vsys_compensation = &raa489000_set_vsys_compensation, -#endif -}; diff --git a/driver/charger/isl923x.h b/driver/charger/isl923x.h deleted file mode 100644 index 558c17f971..0000000000 --- a/driver/charger/isl923x.h +++ /dev/null @@ -1,352 +0,0 @@ -/* 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 ISL-9237/8 battery charger driver. - * Also supports Renesas RAA489000 battery charger. - */ - -#ifndef __CROS_EC_ISL923X_H -#define __CROS_EC_ISL923X_H - -#include "driver/charger/isl923x_public.h" - -/* Registers */ -#define ISL923X_REG_CHG_CURRENT 0x14 -#define ISL923X_REG_ADAPTER_CURRENT_LIMIT1 0x3f -#define ISL923X_REG_ADAPTER_CURRENT_LIMIT2 0x3b -#define ISL923X_REG_SYS_VOLTAGE_MAX 0x15 -#define ISL923X_REG_SYS_VOLTAGE_MIN 0x3e -#define ISL923X_REG_PROCHOT_AC 0x47 -#define ISL923X_REG_PROCHOT_DC 0x48 -#define ISL923X_REG_T1_T2 0x38 -#define ISL923X_REG_CONTROL0 0x39 -#define ISL923X_REG_CONTROL1 0x3c -#define ISL923X_REG_CONTROL2 0x3d -#define ISL9238_REG_CONTROL3 0x4c -#define ISL9238_REG_CONTROL4 0x4e -#define ISL9238C_REG_CONTROL6 0x37 -#define ISL923X_REG_INFO 0x3a -#define ISL9238_REG_INFO2 0x4d -#define ISL923X_REG_OTG_VOLTAGE 0x49 -#define ISL923X_REG_OTG_CURRENT 0x4a -#define ISL9238_REG_INPUT_VOLTAGE 0x4b -#define ISL923X_REG_MANUFACTURER_ID 0xfe -#define ISL923X_REG_DEVICE_ID 0xff -#define RAA489000_REG_CONTROL8 0x37 -#define RAA489000_REG_CONTROL10 0x35 - -/* Sense resistor default values in mOhm */ -#define ISL923X_DEFAULT_SENSE_RESISTOR_AC 20 -#define ISL923X_DEFAULT_SENSE_RESISTOR 10 - -/* Maximum charging current register value */ -#define ISL923X_CURRENT_REG_MAX 0x17c0 /* bit<12:2> 10111110000 */ -#define RAA489000_CURRENT_REG_MAX 0x1ffc - -/* 2-level adpater current limit duration T1 & T2 in micro seconds */ -#define ISL923X_T1_10000 0x00 -#define ISL923X_T1_20000 0x01 -#define ISL923X_T1_15000 0x02 -#define ISL923X_T1_5000 0x03 -#define ISL923X_T1_1000 0x04 -#define ISL923X_T1_500 0x05 -#define ISL923X_T1_100 0x06 -#define ISL923X_T1_0 0x07 -#define ISL923X_T2_10 (0x00 << 8) -#define ISL923X_T2_100 (0x01 << 8) -#define ISL923X_T2_500 (0x02 << 8) -#define ISL923X_T2_1000 (0x03 << 8) -#define ISL923X_T2_300 (0x04 << 8) -#define ISL923X_T2_750 (0x05 << 8) -#define ISL923X_T2_2000 (0x06 << 8) -#define ISL923X_T2_10000 (0x07 << 8) - -#define ISL9237_SYS_VOLTAGE_REG_MAX 13824 -#define ISL9238_SYS_VOLTAGE_REG_MAX 18304 -#define ISL923X_SYS_VOLTAGE_REG_MIN 2048 -#define RAA489000_SYS_VOLTAGE_REG_MAX 18304 -#define RAA489000_SYS_VOLTAGE_REG_MIN 64 - -/* PROCHOT# debounce time and duration time in micro seconds */ -#define ISL923X_PROCHOT_DURATION_10000 (0 << 6) -#define ISL923X_PROCHOT_DURATION_20000 BIT(6) -#define ISL923X_PROCHOT_DURATION_15000 (2 << 6) -#define ISL923X_PROCHOT_DURATION_5000 (3 << 6) -#define ISL923X_PROCHOT_DURATION_1000 (4 << 6) -#define ISL923X_PROCHOT_DURATION_500 (5 << 6) -#define ISL923X_PROCHOT_DURATION_100000 (6 << 6) -#define ISL923X_PROCHOT_DURATION_0 (7 << 6) -#define ISL923X_PROCHOT_DURATION_MASK (7 << 6) - -#define ISL923X_PROCHOT_DEBOUNCE_10 (0 << 9) -#define ISL923X_PROCHOT_DEBOUNCE_100 BIT(9) -#define ISL923X_PROCHOT_DEBOUNCE_500 (2 << 9) -#define ISL923X_PROCHOT_DEBOUNCE_1000 (3 << 9) -#define ISL923X_PROCHOT_DEBOUNCE_MASK (3 << 9) - -/* Maximum PROCHOT register value */ -#define ISL923X_PROCHOT_AC_REG_MAX 6400 -#define ISL923X_PROCHOT_DC_REG_MAX 12800 - -/* Control0: adapter voltage regulation reference */ -#define ISL9237_C0_VREG_REF_3900 0 -#define ISL9237_C0_VREG_REF_4200 1 -#define ISL9237_C0_VREG_REF_4500 2 -#define ISL9237_C0_VREG_REF_4800 3 -#define ISL9237_C0_VREG_REF_MASK 0x03 - -/* Control0: disable adapter voltaqe regulation */ -#define ISL923X_C0_DISABLE_VREG BIT(2) - -/* Control0: battery DCHOT reference for RS2 == 20mOhm */ -#define ISL923X_C0_DCHOT_6A (0 << 3) -#define ISL923X_C0_DCHOT_5A BIT(3) -#define ISL923X_C0_DCHOT_4A (2 << 3) -#define ISL923X_C0_DCHOT_3A (3 << 3) -#define ISL923X_C0_DCHOT_MASK (3 << 3) - -/* Control0: BGATE force on */ -#define RAA489000_C0_BGATE_FORCE_ON BIT(10) -#define RAA489000_C0_EN_CHG_PUMPS_TO_100PCT BIT(6) - -/* Control1: general purpose comparator debounce time in micro second */ -#define ISL923X_C1_GP_DEBOUNCE_2 (0 << 14) -#define ISL923X_C1_GP_DEBOUNCE_12 BIT(14) -#define ISL923X_C1_GP_DEBOUNCE_2000 (2 << 14) -#define ISL923X_C1_GP_DEBOUNCE_5000000 (3 << 14) -#define ISL923X_C1_GP_DEBOUNCE_MASK (3 << 14) - -/* Control1: learn mode */ -#define ISL923X_C1_LEARN_MODE_AUTOEXIT BIT(13) -#define ISL923X_C1_LEARN_MODE_ENABLE BIT(12) - -/* Control1: OTG enable */ -#define ISL923X_C1_OTG BIT(11) - -/* Control1: audio filter */ -#define ISL923X_C1_AUDIO_FILTER BIT(10) - -/* Control1: switch frequency, ISL9238 defines bit 7 as unused */ -#define ISL923X_C1_SWITCH_FREQ_PROG (0 << 7) /* 1000kHz or PROG */ -#define ISL9237_C1_SWITCH_FREQ_913K BIT(7) -#define ISL923X_C1_SWITCH_FREQ_839K (2 << 7) -#define ISL9237_C1_SWITCH_FREQ_777K (3 << 7) -#define ISL923X_C1_SWITCH_FREQ_723K (4 << 7) -#define ISL9237_C1_SWITCH_FREQ_676K (5 << 7) -#define ISL923X_C1_SWITCH_FREQ_635K (6 << 7) -#define ISL9237_C1_SWITCH_FREQ_599K (7 << 7) -#define ISL923X_C1_SWITCH_FREQ_MASK (7 << 7) - -/* Control1: turbo mode */ -#define ISL923X_C1_TURBO_MODE BIT(6) - -/* Control1: AMON & BMON */ -#define ISL923X_C1_DISABLE_MON BIT(5) -#define ISL923X_C1_SELECT_BMON BIT(4) - -/* Control1: PSYS, VSYS, VSYSLO */ -#define ISL923X_C1_ENABLE_PSYS BIT(3) -#define ISL923X_C1_ENABLE_VSYS BIT(2) -#define ISL923X_C1_VSYSLO_REF_6000 0 -#define ISL923X_C1_VSYSLO_REF_6300 1 -#define ISL923X_C1_VSYSLO_REF_6600 2 -#define ISL923X_C1_VSYSLO_REF_6900 3 -#define ISL923X_C1_VSYSLO_REF_MASK 3 - -/* Control1: Supplemental mode support */ -#define RAA489000_C1_ENABLE_SUPP_SUPPORT_MODE BIT(10) - -/* Control1: BGATE Force Off */ -#define RAA489000_C1_BGATE_FORCE_OFF BIT(6) - -/* Control2: trickle charging current in mA */ -#define ISL923X_C2_TRICKLE_256 (0 << 14) -#define ISL923X_C2_TRICKLE_128 BIT(14) -#define ISL923X_C2_TRICKLE_64 (2 << 14) -#define ISL923X_C2_TRICKLE_512 (3 << 14) -#define ISL923X_C2_TRICKLE_MASK (3 << 14) - -/* Control2: OTGEN debounce time in ms */ -#define ISL923X_C2_OTG_DEBOUNCE_1300 (0 << 13) -#define ISL923X_C2_OTG_DEBOUNCE_150 BIT(13) -#define ISL923X_C2_OTG_DEBOUNCE_MASK BIT(13) - -/* Control2: 2-level adapter over current */ -#define ISL923X_C2_2LVL_OVERCURRENT BIT(12) - -/* Control2: adapter insertion debounce time in ms */ -#define ISL923X_C2_ADAPTER_DEBOUNCE_1300 (0 << 11) -#define ISL923X_C2_ADAPTER_DEBOUNCE_150 BIT(11) -#define ISL923X_C2_ADAPTER_DEBOUNCE_MASK BIT(11) - -/* Control2: PROCHOT debounce time in uS */ -#define ISL9238_C2_PROCHOT_DEBOUNCE_7 (0 << 9) -#define ISL9237_C2_PROCHOT_DEBOUNCE_10 (0 << 9) -#define ISL923X_C2_PROCHOT_DEBOUNCE_100 BIT(9) -#define ISL923X_C2_PROCHOT_DEBOUNCE_500 (2 << 9) -#define ISL923X_C2_PROCHOT_DEBOUNCE_1000 (3 << 9) -#define ISL923X_C2_PROCHOT_DEBOUNCE_MASK (3 << 9) - -/* Control2: min PROCHOT duration in uS */ -#define ISL923X_C2_PROCHOT_DURATION_10000 (0 << 6) -#define ISL923X_C2_PROCHOT_DURATION_20000 BIT(6) -#define ISL923X_C2_PROCHOT_DURATION_15000 (2 << 6) -#define ISL923X_C2_PROCHOT_DURATION_5000 (3 << 6) -#define ISL923X_C2_PROCHOT_DURATION_1000 (4 << 6) -#define ISL923X_C2_PROCHOT_DURATION_500 (5 << 6) -#define ISL923X_C2_PROCHOT_DURATION_100 (6 << 6) -#define ISL923X_C2_PROCHOT_DURATION_0 (7 << 6) -#define ISL923X_C2_PROCHOT_DURATION_MASK (7 << 6) - -/* Control2: turn off ASGATE in OTG mode */ -#define ISL923X_C2_ASGATE_OFF BIT(5) - -/* Control2: CMIN, general purpose comparator reference in mV */ -#define ISL923X_C2_CMIN_2000 (0 << 4) -#define ISL923X_C2_CMIN_1200 BIT(4) - -/* Control2: general purpose comparator enable */ -#define ISL923X_C2_COMPARATOR BIT(3) - -/* Control2: invert CMOUT, general purpose comparator output, polarity */ -#define ISL923X_C2_INVERT_CMOUT BIT(2) - -/* Control2: disable WOC, way over current */ -#define ISL923X_C2_WOC_OFF BIT(1) - -/* Control2: PSYS gain in uA/W (ISL9237 only) */ -#define ISL9237_C2_PSYS_GAIN BIT(0) - -/* Control3: Enable ADC for all modes */ -#define RAA489000_ENABLE_ADC BIT(0) - -/* - * Control3: Buck-Boost switching period - * 0: x1 frequency, 1: half frequency. - */ -#define ISL9238_C3_BB_SWITCHING_PERIOD BIT(1) - -/* - * Control3: AMON/BMON direction. - * 0: adapter/charging, 1:OTG/discharging (ISL9238 only) - */ -#define ISL9238_C3_AMON_BMON_DIRECTION BIT(3) - -/* - * Control3: Disables Autonomous Charing - * - * Note: This is disabled automatically when ever we set the current limit - * manually (which we always do). - */ -#define ISL9238_C3_DISABLE_AUTO_CHARING BIT(7) - -/* Control3: PSYS gain in uA/W (ISL9238 only) */ -#define ISL9238_C3_PSYS_GAIN BIT(9) - -/* Control3: Enables or disables Battery Ship mode */ -#define ISL9238_C3_BGATE_OFF BIT(10) - -/* Control3: Enable or disable DCM/CCM Hysteresis */ -#define RAA489000_C3_DCM_CCM_HYSTERESIS_ENABLE BIT(10) - -/* Control3: Don't reload ACLIM on ACIN. */ -#define ISL9238_C3_NO_RELOAD_ACLIM_ON_ACIN BIT(14) - -/* Control3: Don't reread PROG pin. */ -#define ISL9238_C3_NO_REREAD_PROG_PIN BIT(15) - -/* Control4: PSYS Rsense ratio. */ -#define RAA489000_C4_PSYS_RSNS_RATIO_1_TO_1 BIT(11) - -/* Control4: GP comparator control bit */ -#define RAA489000_C4_DISABLE_GP_CMP BIT(12) - -/* Control4: Ignores BATGONE input */ -#define RAA489000_C4_BATGONE_DISABLE BIT(15) - -/* Control6: charger current and maximum system voltage slew rate control. */ -#define ISL9238C_C6_SLEW_RATE_CONTROL BIT(6) - -/* Control8: MCU_LDO - BAT state disable */ -#define RAA489000_C8_MCU_LDO_BAT_STATE_DISABLE BIT(14) -#define RAA489000_C8_ASGATE_ON_READY BIT(13) - -/* OTG voltage limit in mV, current limit in mA */ -#define ISL9237_OTG_VOLTAGE_MIN 4864 -#define ISL9237_OTG_VOLTAGE_MAX 5376 -#define ISL9238_OTG_VOLTAGE_MAX 27456 -#define ISL923X_OTG_CURRENT_MAX 4096 - -#define ISL9238_OTG_VOLTAGE_STEP 12 -#define ISL9238_OTG_VOLTAGE_SHIFT 3 -#define ISL923X_OTG_CURRENT_STEP 128 -#define ISL923X_OTG_CURRENT_SHIFT 7 - -/* Input voltage regulation voltage reference */ -#define ISL9238_INPUT_VOLTAGE_REF_STEP 341 -#define ISL9238_INPUT_VOLTAGE_REF_SHIFT 8 -#define RAA489000_INPUT_VOLTAGE_REF_STEP 85 -#define RAA489000_INPUT_VOLTAGE_REF_SHIFT 6 - -/* Info register fields */ -#define ISL9237_INFO_PROG_RESISTOR_MASK 0xf -#define ISL923X_INFO_TRICKLE_ACTIVE_MASK BIT(4) -#define ISL9237_INFO_PSTATE_SHIFT 5 -#define ISL9237_INFO_PSTATE_MASK 3 -#define RAA489000_INFO2_ACOK BIT(14) - -/* ADC registers */ -#define RAA489000_REG_ADC_INPUT_CURRENT 0x83 -#define RAA489000_REG_ADC_CHARGE_CURRENT 0x85 -#define RAA489000_REG_ADC_VSYS 0x86 -#define RAA489000_REG_ADC_VBUS 0x89 - -enum isl9237_power_stage { - BUCK_MODE, - BOOST_MODE, - BUCK_BOOST_MODE, - REVERSE_BUCK_MODE -}; - -#define ISL9237_INFO_FSM_STATE_SHIFT 7 -#define ISL9237_INFO_FSM_STATE_MASK 7 - -enum isl9237_fsm_state { - FSM_OFF, - FSM_BAT, - FSM_ADPT, - FSM_ACOK, - FSM_VSYS, - FSM_CHRG, - FSM_ENTOG, - FSM_OTG -}; - -#define ISL923X_INFO_VSYSLO BIT(10) -#define ISL923X_INFO_DCHOT BIT(11) -#define ISL9237_INFO_ACHOT BIT(12) - -#define RAA489000_DEV_ID_B0 0x11 - -/* DVC - Dynamic Voltage Compensation */ -#define RAA489000_RP1_MAX 156 -#define RAA489000_RP1_MIN 36 -#define RAA489000_RP2_MAX 124 -#define RAA489000_RP2_MIN 0 - -#define RAA489000_C10_RP2_MASK GENMASK(4, 0) -#define RAA489000_C10_DISABLE_DVC_AUTO_ZERO BIT(5) -#define RAA489000_C10_ENABLE_DVC_TRICKLE_CHARGE BIT(6) -#define RAA489000_C10_DISABLE_DVC_CC_LOOP BIT(8) -#define RAA489000_C10_ENABLE_DVC_CHARGE_MODE BIT(9) -#define RAA489000_C10_RP1_MASK GENMASK(14, 10) -#define RAA489000_C10_RP1_SHIFT 10 -#define RAA489000_C10_ENABLE_DVC_MODE BIT(15) - -#define I2C_ADDR_CHARGER_FLAGS ISL923X_ADDR_FLAGS - -#define ISL923X_AC_PROCHOT_CURRENT_MAX 6400 /* mA */ -#define ISL923X_DC_PROCHOT_CURRENT_MAX 12800 /* mA */ - -#endif /* __CROS_EC_ISL923X_H */ diff --git a/driver/charger/isl9241.c b/driver/charger/isl9241.c deleted file mode 100644 index 794ea0b342..0000000000 --- a/driver/charger/isl9241.c +++ /dev/null @@ -1,599 +0,0 @@ -/* Copyright 2019 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. - * - * Renesas (Intersil) ISL-9241 battery charger driver. - */ - -/* TODO(b/175881324) */ -#ifndef CONFIG_ZEPHYR -#include "adc.h" -#endif -#include "battery.h" -#include "battery_smart.h" -#include "charger.h" -#include "charge_state.h" -#include "console.h" -#include "common.h" -#include "hooks.h" -#include "i2c.h" -#include "isl9241.h" -#include "system.h" -#include "task.h" -#include "timer.h" -#include "util.h" - -#ifndef CONFIG_CHARGER_NARROW_VDC -#error "ISL9241 is a NVDC charger, please enable CONFIG_CHARGER_NARROW_VDC." -#endif - -/* Sense resistor default values in milli Ohm */ -#define ISL9241_DEFAULT_RS1 20 /* Input current sense resistor */ -#define ISL9241_DEFAULT_RS2 10 /* Battery charge current sense resistor */ - -#define BOARD_RS1 CONFIG_CHARGER_SENSE_RESISTOR_AC -#define BOARD_RS2 CONFIG_CHARGER_SENSE_RESISTOR - -#define BC_REG_TO_CURRENT(REG) (((REG) * ISL9241_DEFAULT_RS2) / BOARD_RS2) -#define BC_CURRENT_TO_REG(CUR) (((CUR) * BOARD_RS2) / ISL9241_DEFAULT_RS2) - -#define AC_REG_TO_CURRENT(REG) (((REG) * ISL9241_DEFAULT_RS1) / BOARD_RS1) -#define AC_CURRENT_TO_REG(CUR) (((CUR) * BOARD_RS1) / ISL9241_DEFAULT_RS1) - -/* Console output macros */ -#define CPRINTF(format, args...) cprintf(CC_CHARGER, format, ## args) - -static int learn_mode; - -/* Mutex for CONTROL1 register, that can be updated from multiple tasks. */ -K_MUTEX_DEFINE(control1_mutex); - -/* Charger parameters */ -static const struct charger_info isl9241_charger_info = { - .name = CHARGER_NAME, - .voltage_max = CHARGE_V_MAX, - .voltage_min = CHARGE_V_MIN, - .voltage_step = CHARGE_V_STEP, - .current_max = CHARGE_I_MAX, - .current_min = CHARGE_I_MIN, - .current_step = CHARGE_I_STEP, - .input_current_max = INPUT_I_MAX, - .input_current_min = INPUT_I_MIN, - .input_current_step = INPUT_I_STEP, -}; - -static enum ec_error_list isl9241_discharge_on_ac(int chgnum, int enable); - -static inline enum ec_error_list isl9241_read(int chgnum, int offset, - int *value) -{ - return i2c_read16(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, - offset, value); -} - -static inline enum ec_error_list isl9241_write(int chgnum, int offset, - int value) -{ - return i2c_write16(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, - offset, value); -} - -static inline enum ec_error_list isl9241_update(int chgnum, int offset, - uint16_t mask, - enum mask_update_action action) -{ - return i2c_update16(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, - offset, mask, action); -} - -/* chip specific interfaces */ - -/*****************************************************************************/ -/* Charger interfaces */ -static enum ec_error_list isl9241_set_input_current_limit(int chgnum, - int input_current) -{ - int rv; - uint16_t reg = AC_CURRENT_TO_REG(input_current); - - rv = isl9241_write(chgnum, ISL9241_REG_ADAPTER_CUR_LIMIT1, reg); - if (rv) - return rv; - - return isl9241_write(chgnum, ISL9241_REG_ADAPTER_CUR_LIMIT2, reg); -} - -static enum ec_error_list isl9241_get_input_current_limit(int chgnum, - int *input_current) -{ - int rv; - - rv = isl9241_read(chgnum, ISL9241_REG_ADAPTER_CUR_LIMIT1, - input_current); - if (rv) - return rv; - - *input_current = AC_REG_TO_CURRENT(*input_current); - return EC_SUCCESS; -} - -static enum ec_error_list isl9241_manufacturer_id(int chgnum, int *id) -{ - return isl9241_read(chgnum, ISL9241_REG_MANUFACTURER_ID, id); -} - -static enum ec_error_list isl9241_device_id(int chgnum, int *id) -{ - return isl9241_read(chgnum, ISL9241_REG_DEVICE_ID, id); -} - -static enum ec_error_list isl9241_get_option(int chgnum, int *option) -{ - int rv; - uint32_t controls; - int reg; - - rv = isl9241_read(chgnum, ISL9241_REG_CONTROL0, ®); - if (rv) - return rv; - - controls = reg; - rv = isl9241_read(chgnum, ISL9241_REG_CONTROL1, ®); - if (rv) - return rv; - - controls |= reg << 16; - *option = controls; - return EC_SUCCESS; -} - -static enum ec_error_list isl9241_set_option(int chgnum, int option) -{ - int rv; - - rv = isl9241_write(chgnum, ISL9241_REG_CONTROL0, option & 0xFFFF); - if (rv) - return rv; - - return isl9241_write(chgnum, ISL9241_REG_CONTROL1, - (option >> 16) & 0xFFFF); -} - -static const struct charger_info *isl9241_get_info(int chgnum) -{ - return &isl9241_charger_info; -} - -static enum ec_error_list isl9241_get_status(int chgnum, int *status) -{ - int rv; - int reg; - - /* Level 2 charger */ - *status = CHARGER_LEVEL_2; - - /* Charge inhibit status */ - rv = isl9241_read(chgnum, ISL9241_REG_MIN_SYSTEM_VOLTAGE, ®); - if (rv) - return rv; - if (!reg) - *status |= CHARGER_CHARGE_INHIBITED; - - /* Battery present & AC present status */ - rv = isl9241_read(chgnum, ISL9241_REG_INFORMATION2, ®); - if (rv) - return rv; - if (!(reg & ISL9241_INFORMATION2_BATGONE_PIN)) - *status |= CHARGER_BATTERY_PRESENT; - if (reg & ISL9241_INFORMATION2_ACOK_PIN) - *status |= CHARGER_AC_PRESENT; - - return EC_SUCCESS; -} - -static enum ec_error_list isl9241_set_mode(int chgnum, int mode) -{ - int rv; - - /* - * See crosbug.com/p/51196. Always disable learn mode unless it was set - * explicitly. - */ - if (!learn_mode) { - rv = isl9241_discharge_on_ac(chgnum, 0); - if (rv) - return rv; - } - - /* - * Charger inhibit - * MinSystemVoltage 0x00h = disables all battery charging - */ - rv = isl9241_write(chgnum, ISL9241_REG_MIN_SYSTEM_VOLTAGE, - mode & CHARGE_FLAG_INHIBIT_CHARGE ? - 0 : battery_get_info()->voltage_min); - if (rv) - return rv; - - /* POR reset */ - if (mode & CHARGE_FLAG_POR_RESET) { - rv = isl9241_write(chgnum, ISL9241_REG_CONTROL3, - ISL9241_CONTROL3_DIGITAL_RESET); - } - - return rv; -} - -static enum ec_error_list isl9241_get_current(int chgnum, int *current) -{ - int rv; - - rv = isl9241_read(chgnum, ISL9241_REG_CHG_CURRENT_LIMIT, current); - if (rv) - return rv; - - *current = BC_REG_TO_CURRENT(*current); - return EC_SUCCESS; -} - -static enum ec_error_list isl9241_set_current(int chgnum, int current) -{ - return isl9241_write(chgnum, ISL9241_REG_CHG_CURRENT_LIMIT, - BC_CURRENT_TO_REG(current)); -} - -static enum ec_error_list isl9241_get_voltage(int chgnum, int *voltage) -{ - return isl9241_read(chgnum, ISL9241_REG_MAX_SYSTEM_VOLTAGE, voltage); -} - -static enum ec_error_list isl9241_set_voltage(int chgnum, int voltage) -{ - return isl9241_write(chgnum, ISL9241_REG_MAX_SYSTEM_VOLTAGE, voltage); -} - -static enum ec_error_list isl9241_get_vbus_voltage(int chgnum, int port, - int *voltage) -{ - int adc_val = 0; - int ctl3_val; - int rv; - - /* Get current Control3 value */ - rv = isl9241_read(chgnum, ISL9241_REG_CONTROL3, &ctl3_val); - if (rv) - goto error; - - /* Enable ADC */ - if (!(ctl3_val & ISL9241_CONTROL3_ENABLE_ADC)) { - rv = isl9241_write(chgnum, ISL9241_REG_CONTROL3, - ctl3_val | ISL9241_CONTROL3_ENABLE_ADC); - if (rv) - goto error; - } - - /* Read voltage ADC value */ - rv = isl9241_read(chgnum, ISL9241_REG_VIN_ADC_RESULTS, &adc_val); - if (rv) - goto error_restore_ctl3; - - /* - * Adjust adc_val - * - * raw adc_val has VIN_ADC in bits [13:6], so shift this down - * this puts adc_val in the range of 0..255, which maps to 0..24.48V - * each step in adc_val is 96mv - */ - adc_val >>= ISL9241_VIN_ADC_BIT_OFFSET; - adc_val *= ISL9241_VIN_ADC_STEP_MV; - *voltage = adc_val; - -error_restore_ctl3: - /* Restore Control3 value */ - if (!(ctl3_val & ISL9241_CONTROL3_ENABLE_ADC)) - (void)isl9241_write(chgnum, ISL9241_REG_CONTROL3, ctl3_val); - -error: - if (rv) - CPRINTF("Could not read VBUS ADC! Error: %d\n", rv); - - return rv; -} - -static enum ec_error_list isl9241_post_init(int chgnum) -{ - return EC_SUCCESS; -} - -static enum ec_error_list isl9241_discharge_on_ac(int chgnum, int enable) -{ - int rv; - - mutex_lock(&control1_mutex); - - rv = isl9241_update(chgnum, ISL9241_REG_CONTROL1, - ISL9241_CONTROL1_LEARN_MODE, - (enable) ? MASK_SET : MASK_CLR); - if (!rv) - learn_mode = enable; - - mutex_unlock(&control1_mutex); - return rv; -} - -int isl9241_set_ac_prochot(int chgnum, int ma) -{ - int rv; - uint16_t reg; - - /* - * The register reserves bits [6:0] and bits [15:13]. - * This routine should ensure these bits are not set - * before writing the register. - */ - if (ma > AC_REG_TO_CURRENT(ISL9241_AC_PROCHOT_CURRENT_MAX)) - reg = ISL9241_AC_PROCHOT_CURRENT_MAX; - else if (ma < AC_REG_TO_CURRENT(ISL9241_AC_PROCHOT_CURRENT_MIN)) - reg = ISL9241_AC_PROCHOT_CURRENT_MIN; - else - reg = AC_CURRENT_TO_REG(ma); - - rv = isl9241_write(chgnum, ISL9241_REG_AC_PROCHOT, reg); - if (rv) - CPRINTF("set_ac_prochot failed (%d)\n", rv); - - return rv; -} - -int isl9241_set_dc_prochot(int chgnum, int ma) -{ - int rv; - - /* - * The register reserves bits [7:0] and bits [15:14]. - * This routine should ensure these bits are not set - * before writing the register. - */ - if (ma > ISL9241_DC_PROCHOT_CURRENT_MAX) - ma = ISL9241_DC_PROCHOT_CURRENT_MAX; - else if (ma < ISL9241_DC_PROCHOT_CURRENT_MIN) - ma = ISL9241_DC_PROCHOT_CURRENT_MIN; - - rv = isl9241_write(chgnum, ISL9241_REG_DC_PROCHOT, ma); - if (rv) - CPRINTF("set_dc_prochot failed (%d)\n", rv); - - return rv; -} - -/*****************************************************************************/ -/* ISL-9241 initialization */ -static void isl9241_init(int chgnum) -{ -#ifdef CONFIG_ISL9241_SWITCHING_FREQ - int ctl_val; -#endif - - const struct battery_info *bi = battery_get_info(); - - /* - * Set the MaxSystemVoltage to battery maximum, - * 0x00=disables switching charger states - */ - if (isl9241_write(chgnum, ISL9241_REG_MAX_SYSTEM_VOLTAGE, - bi->voltage_max)) - goto init_fail; - - /* - * Set the MinSystemVoltage to battery minimum, - * 0x00=disables all battery charging - */ - if (isl9241_write(chgnum, ISL9241_REG_MIN_SYSTEM_VOLTAGE, - bi->voltage_min)) - goto init_fail; - - /* - * Set control2 register to - * [15:13]: Trickle Charging Current (battery pre-charge current) - * [10:9] : Prochot# Debounce time (1000us) - */ - if (isl9241_update(chgnum, ISL9241_REG_CONTROL2, - (ISL9241_CONTROL2_TRICKLE_CHG_CURR( - bi->precharge_current) | - ISL9241_CONTROL2_PROCHOT_DEBOUNCE_1000), - MASK_SET)) - goto init_fail; - - /* - * Set control3 register to - * [14]: ACLIM Reload (Do not reload) - */ - if (isl9241_update(chgnum, ISL9241_REG_CONTROL3, - ISL9241_CONTROL3_ACLIM_RELOAD, - MASK_SET)) - goto init_fail; - - /* - * Set control4 register to - * [13]: Slew rate control enable (sets VSYS ramp to 8mV/us) - */ - if (isl9241_update(chgnum, ISL9241_REG_CONTROL4, - ISL9241_CONTROL4_SLEW_RATE_CTRL, - MASK_SET)) - goto init_fail; - -#ifndef CONFIG_CHARGE_RAMP_HW - if (isl9241_update(chgnum, ISL9241_REG_CONTROL0, - ISL9241_CONTROL0_INPUT_VTG_REGULATION, - MASK_SET)) - goto init_fail; -#endif - -#ifdef CONFIG_ISL9241_SWITCHING_FREQ - if (isl9241_read(chgnum, ISL9241_REG_CONTROL1, &ctl_val)) - goto init_fail; - ctl_val &= ~ISL9241_CONTROL1_SWITCHING_FREQ_MASK; - ctl_val |= ((CONFIG_ISL9241_SWITCHING_FREQ << 7) & - ISL9241_CONTROL1_SWITCHING_FREQ_MASK); - if (isl9241_write(chgnum, ISL9241_REG_CONTROL1, ctl_val)) - goto init_fail; -#endif - - /* - * No need to proceed with the rest of init if we sysjump'd to this - * image as the input current limit has already been set. - */ - if (system_jumped_late()) - return; - - /* Initialize the input current limit to the board's default. */ - if (isl9241_set_input_current_limit(chgnum, - CONFIG_CHARGER_INPUT_CURRENT)) - goto init_fail; - - return; - -init_fail: - CPRINTF("ISL9241_init failed!\n"); -} - -/*****************************************************************************/ -/* Hardware current ramping */ - -#ifdef CONFIG_CHARGE_RAMP_HW -static enum ec_error_list isl9241_set_hw_ramp(int chgnum, int enable) -{ - /* HW ramp is controlled by input voltage regulation reference bits */ - return isl9241_update(chgnum, ISL9241_REG_CONTROL0, - ISL9241_CONTROL0_INPUT_VTG_REGULATION, - (enable) ? MASK_CLR : MASK_SET); -} - -static int isl9241_ramp_is_stable(int chgnum) -{ - /* - * Since ISL cannot read the current limit that the ramp has settled - * on, then we can never consider the ramp stable, because we never - * know what the stable limit is. - */ - return 0; -} - -static int isl9241_ramp_is_detected(int chgnum) -{ - return 1; -} - -static int isl9241_ramp_get_current_limit(int chgnum) -{ - int reg; - - if (isl9241_read(chgnum, ISL9241_REG_IADP_ADC_RESULTS, ®)) - return 0; - - /* LSB value of register = 22.2mA */ - return (reg * 222) / 10; -} -#endif /* CONFIG_CHARGE_RAMP_HW */ - -/* - * When fully charged in a low-power state, the ISL9241 may get stuck - * in CCM. Toggle learning mode for 50 ms to enter DCM and save power. - * This is a workaround provided by Renesas. See b/183771327. - * Note: the charger_get_state() returns the last known charge value, - * so need to check the battery is not disconnected when the system - * comes from the battery cutoff. - */ -static void isl9241_restart_charge_voltage_when_full(void) -{ - if (!chipset_in_or_transitioning_to_state(CHIPSET_STATE_ON) - && charge_get_state() == PWR_STATE_CHARGE_NEAR_FULL - && battery_get_disconnect_state() == BATTERY_NOT_DISCONNECTED) { - charger_discharge_on_ac(1); - msleep(50); - charger_discharge_on_ac(0); - } -} -DECLARE_HOOK(HOOK_BATTERY_SOC_CHANGE, - isl9241_restart_charge_voltage_when_full, - HOOK_PRIO_DEFAULT); -DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, - isl9241_restart_charge_voltage_when_full, - HOOK_PRIO_DEFAULT); -DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, - isl9241_restart_charge_voltage_when_full, - HOOK_PRIO_DEFAULT); - -/*****************************************************************************/ -#ifdef CONFIG_CMD_CHARGER_DUMP -static void dump_reg_range(int chgnum, int low, int high) -{ - int reg; - int regval; - int rv; - - for (reg = low; reg <= high; reg++) { - CPRINTF("[%Xh] = ", reg); - rv = isl9241_read(chgnum, reg, ®val); - if (!rv) - CPRINTF("0x%04x\n", regval); - else - CPRINTF("ERR (%d)\n", rv); - cflush(); - } -} - -static int command_isl9241_dump(int argc, char **argv) -{ - char *e; - int chgnum = 0; - - if (argc >= 2) { - chgnum = strtoi(argv[1], &e, 10); - if (*e) - return EC_ERROR_PARAM1; - } - - dump_reg_range(chgnum, 0x14, 0x15); - dump_reg_range(chgnum, 0x38, 0x40); - dump_reg_range(chgnum, 0x43, 0x43); - dump_reg_range(chgnum, 0x47, 0x4F); - dump_reg_range(chgnum, 0x80, 0x87); - dump_reg_range(chgnum, 0x90, 0x91); - dump_reg_range(chgnum, 0xFE, 0xFF); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(charger_dump, command_isl9241_dump, - "charger_dump <chgnum>", - "Dumps ISL9241 registers"); -#endif /* CONFIG_CMD_CHARGER_DUMP */ - -const struct charger_drv isl9241_drv = { - .init = &isl9241_init, - .post_init = &isl9241_post_init, - .get_info = &isl9241_get_info, - .get_status = &isl9241_get_status, - .set_mode = &isl9241_set_mode, - .get_current = &isl9241_get_current, - .set_current = &isl9241_set_current, - .get_voltage = &isl9241_get_voltage, - .set_voltage = &isl9241_set_voltage, - .discharge_on_ac = &isl9241_discharge_on_ac, - .get_vbus_voltage = &isl9241_get_vbus_voltage, - .set_input_current_limit = &isl9241_set_input_current_limit, - .get_input_current_limit = &isl9241_get_input_current_limit, - .manufacturer_id = &isl9241_manufacturer_id, - .device_id = &isl9241_device_id, - .get_option = &isl9241_get_option, - .set_option = &isl9241_set_option, -#ifdef CONFIG_CHARGE_RAMP_HW - .set_hw_ramp = &isl9241_set_hw_ramp, - .ramp_is_stable = &isl9241_ramp_is_stable, - .ramp_is_detected = &isl9241_ramp_is_detected, - .ramp_get_current_limit = &isl9241_ramp_get_current_limit, -#endif -}; diff --git a/driver/charger/isl9241.h b/driver/charger/isl9241.h deleted file mode 100644 index 0e5acd09df..0000000000 --- a/driver/charger/isl9241.h +++ /dev/null @@ -1,140 +0,0 @@ -/* Copyright 2019 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. - * - * Renesas (Intersil) ISL-9241 battery charger driver header. - */ - -#ifndef __CROS_EC_ISL9241_H -#define __CROS_EC_ISL9241_H - -#include "driver/charger/isl9241_public.h" - -#define CHARGER_NAME "ISL9241" -#define CHARGE_V_MAX 18304 -#define CHARGE_V_MIN 64 -#define CHARGE_V_STEP 8 -#define CHARGE_I_MAX 6140 -#define CHARGE_I_MIN 4 -#define CHARGE_I_STEP 4 -#define INPUT_I_MAX 6140 -#define INPUT_I_MIN 4 -#define INPUT_I_STEP 4 - -/* Registers */ - -/* - * ChargeCurrentLimit [12:2] 11-bit (0x0000h = disables fast charging, - * trickle charging is allowed) - */ -#define ISL9241_REG_CHG_CURRENT_LIMIT 0x14 - -/* MaxSystemVoltage [14:3] 12-bit, (0x0000h = disables switching) */ -#define ISL9241_REG_MAX_SYSTEM_VOLTAGE 0x15 - -#define ISL9241_REG_CONTROL7 0x38 - -/* Configures various charger options */ -#define ISL9241_REG_CONTROL0 0x39 -/* 2: Input Voltage Regulation (0 = Enable (default), 1 = Disable) */ -#define ISL9241_CONTROL0_INPUT_VTG_REGULATION BIT(2) - - -#define ISL9241_REG_INFORMATION1 0x3A -#define ISL9241_REG_ADAPTER_CUR_LIMIT2 0x3B - -/* Configures various charger options */ -#define ISL9241_REG_CONTROL1 0x3C -#define ISL9241_CONTROL1_PSYS BIT(3) -#define ISL9241_CONTROL1_LEARN_MODE BIT(12) -/* - * 9:7 - Switching Frequency - */ -#define ISL9241_CONTROL1_SWITCHING_FREQ_MASK 0x380 -#define ISL9241_CONTROL1_SWITCHING_FREQ_1420KHZ 0 -#define ISL9241_CONTROL1_SWITCHING_FREQ_1180KHZ 1 -#define ISL9241_CONTROL1_SWITCHING_FREQ_1020KHZ 2 -#define ISL9241_CONTROL1_SWITCHING_FREQ_890KHZ 3 -#define ISL9241_CONTROL1_SWITCHING_FREQ_808KHZ 4 -#define ISL9241_CONTROL1_SWITCHING_FREQ_724KHZ 5 -#define ISL9241_CONTROL1_SWITCHING_FREQ_656KHZ 6 -#define ISL9241_CONTROL1_SWITCHING_FREQ_600KHZ 7 - -/* Configures various charger options */ -#define ISL9241_REG_CONTROL2 0x3D -/* - * 15:13 - Trickle Charging Current - * <000> 32mA (do not use) - * <001> 64mA - * <010> 96mA - * <011> 128mA (default) - * <100> 160mA - * <101> 192mA - * <110> 224mA - * <111> 256mA - */ -#define ISL9241_CONTROL2_TRICKLE_CHG_CURR(curr) ((((curr) >> 5) - 1) << 13) -/* 12 - Two-Level Adapter Current Limit */ -#define ISL9241_CONTROL2_TWO_LEVEL_ADP_CURR BIT(12) -/* 10:9 PROCHOT# debounce time in uS */ -#define ISL9241_CONTROL2_PROCHOT_DEBOUNCE_MASK GENMASK(10, 9) -#define ISL9241_CONTROL2_PROCHOT_DEBOUNCE_500 (2 << 9) -#define ISL9241_CONTROL2_PROCHOT_DEBOUNCE_1000 (3 << 9) - -/* MinSystemVoltage [13:6] 8-bit (0x0000h = disables all battery charging) */ -#define ISL9241_REG_MIN_SYSTEM_VOLTAGE 0x3E - -#define ISL9241_REG_ADAPTER_CUR_LIMIT1 0x3F -#define ISL9241_REG_ACOK_REFERENCE 0x40 -#define ISL9241_REG_CONTROL6 0x43 -#define ISL9241_REG_AC_PROCHOT 0x47 -#define ISL9241_REG_DC_PROCHOT 0x48 -#define ISL9241_REG_OTG_VOLTAGE 0x49 -#define ISL9241_REG_OTG_CURRENT 0x4A - -/* VIN Voltage (ADP Min Voltage) (default 4.096V) */ -#define ISL9241_REG_VIN_VOLTAGE 0x4B - -/* Configures various charger options */ -#define ISL9241_REG_CONTROL3 0x4C -/* 14: ACLIM Reload (0 - reload, 1 - Do not reload */ -#define ISL9241_CONTROL3_ACLIM_RELOAD BIT(14) -/* 2: Digital Reset (0 - Idle, 1 - Reset */ -#define ISL9241_CONTROL3_DIGITAL_RESET BIT(2) -/* 0: Enable ADC (0 - Active when charging, 1 - Active always) */ -#define ISL9241_CONTROL3_ENABLE_ADC BIT(0) - -/* Indicates various charger status */ -#define ISL9241_REG_INFORMATION2 0x4D -/* 12: BATGONE pin status (0 = Battery is present, 1 = No battery) */ -#define ISL9241_INFORMATION2_BATGONE_PIN BIT(12) -/* 14: ACOK pin status (0 = No adapter, 1 = Adapter is present) */ -#define ISL9241_INFORMATION2_ACOK_PIN BIT(14) - -#define ISL9241_REG_CONTROL4 0x4E -/* 11: Rsense (Rs1:Rs2) ratio for PSYS (0 - 2:1, 1 - 1:1) */ -#define ISL9241_CONTROL4_PSYS_RSENSE_RATIO BIT(11) -/* 13: Enable VSYS slew rate control (0 - disable, 1 - enable) */ -#define ISL9241_CONTROL4_SLEW_RATE_CTRL BIT(13) - -#define ISL9241_REG_CONTROL5 0x4F -#define ISL9241_REG_NTC_ADC_RESULTS 0x80 -#define ISL9241_REG_VBAT_ADC_RESULTS 0x81 -#define ISL9241_REG_TJ_ADC_RESULTS 0x82 - -/* ADC result for adapter current measurements, LSB = 22.2mA */ -#define ISL9241_REG_IADP_ADC_RESULTS 0x83 - -#define ISL9241_REG_DC_ADC_RESULTS 0x84 -#define ISL9241_REG_CC_ADC_RESULTS 0x85 -#define ISL9241_REG_VSYS_ADC_RESULTS 0x86 -#define ISL9241_REG_VIN_ADC_RESULTS 0x87 -#define ISL9241_REG_INFORMATION3 0x90 -#define ISL9241_REG_INFORMATION4 0x91 -#define ISL9241_REG_MANUFACTURER_ID 0xFE -#define ISL9241_REG_DEVICE_ID 0xFF - -#define ISL9241_VIN_ADC_BIT_OFFSET 6 -#define ISL9241_VIN_ADC_STEP_MV 96 - -#endif /* __CROS_EC_ISL9241_H */ diff --git a/driver/charger/rt946x.c b/driver/charger/rt946x.c deleted file mode 100644 index a4cfa5d2eb..0000000000 --- a/driver/charger/rt946x.c +++ /dev/null @@ -1,1927 +0,0 @@ -/* Copyright 2017 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. - * - * Richtek rt946x, Mediatek mt6370 battery charger driver. - */ - -#include "battery.h" -#include "battery_smart.h" -#include "charger.h" -#include "charge_manager.h" -#include "common.h" -#include "compile_time_macros.h" -#include "config.h" -#include "console.h" -#include "extpower.h" -#include "hooks.h" -#include "i2c.h" -#include "printf.h" -#include "driver/wpc/p9221.h" -#include "rt946x.h" -#include "task.h" -#include "tcpm/tcpm.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_CHARGER, "%s " format, "RT946X", ## args) - -/* Charger parameters */ -#define CHARGER_NAME RT946X_CHARGER_NAME -#define CHARGE_V_MAX 4710 -#define CHARGE_V_MIN 3900 -#define CHARGE_V_STEP 10 -#define CHARGE_I_MAX 5000 -#define CHARGE_I_MIN 100 -#define CHARGE_I_OFF 0 -#define CHARGE_I_STEP 100 -#define INPUT_I_MAX 3250 -#define INPUT_I_MIN 100 -#define INPUT_I_STEP 50 - -/* Charger parameters */ -static const struct charger_info rt946x_charger_info = { - .name = CHARGER_NAME, - .voltage_max = CHARGE_V_MAX, - .voltage_min = CHARGE_V_MIN, - .voltage_step = CHARGE_V_STEP, - .current_max = CHARGE_I_MAX, - .current_min = CHARGE_I_MIN, - .current_step = CHARGE_I_STEP, - .input_current_max = INPUT_I_MAX, - .input_current_min = INPUT_I_MIN, - .input_current_step = INPUT_I_STEP, -}; - -static const struct rt946x_init_setting default_init_setting = { - .eoc_current = 400, - .mivr = 4000, - .ircmp_vclamp = 32, - .ircmp_res = 25, - .boost_voltage = 5050, - .boost_current = 1500, -}; - -__attribute__((weak)) -const struct rt946x_init_setting *board_rt946x_init_setting(void) -{ - return &default_init_setting; -} - -enum rt946x_ilmtsel { - RT946X_ILMTSEL_PSEL_OTG, - RT946X_ILMTSEL_AICR = 2, - RT946X_ILMTSEL_LOWER_LEVEL, /* lower of above two */ -}; - -enum rt946x_chg_stat { - RT946X_CHGSTAT_READY = 0, - RT946X_CHGSTAT_IN_PROGRESS, - RT946X_CHGSTAT_DONE, - RT946X_CHGSTAT_FAULT, -}; - -static struct mutex adc_access_lock; - -#ifdef CONFIG_CHARGER_MT6370 -/* - * Unit for each ADC parameter - * 0 stands for reserved - */ -static const int mt6370_adc_unit[MT6370_ADC_MAX] = { - 0, - MT6370_ADC_UNIT_VBUS_DIV5, - MT6370_ADC_UNIT_VBUS_DIV2, - MT6370_ADC_UNIT_VSYS, - MT6370_ADC_UNIT_VBAT, - 0, - MT6370_ADC_UNIT_TS_BAT, - 0, - MT6370_ADC_UNIT_IBUS, - MT6370_ADC_UNIT_IBAT, - 0, - MT6370_ADC_UNIT_CHG_VDDP, - MT6370_ADC_UNIT_TEMP_JC, -}; - -static const int mt6370_adc_offset[MT6370_ADC_MAX] = { - 0, - MT6370_ADC_OFFSET_VBUS_DIV5, - MT6370_ADC_OFFSET_VBUS_DIV2, - MT6370_ADC_OFFSET_VSYS, - MT6370_ADC_OFFSET_VBAT, - 0, - MT6370_ADC_OFFSET_TS_BAT, - 0, - MT6370_ADC_OFFSET_IBUS, - MT6370_ADC_OFFSET_IBAT, - 0, - MT6370_ADC_OFFSET_CHG_VDDP, - MT6370_ADC_OFFSET_TEMP_JC, -}; - -static int hidden_mode_cnt = 0; -static struct mutex hidden_mode_lock; -static const unsigned char mt6370_reg_en_hidden_mode[] = { - MT6370_REG_HIDDENPASCODE1, - MT6370_REG_HIDDENPASCODE2, - MT6370_REG_HIDDENPASCODE3, - MT6370_REG_HIDDENPASCODE4, -}; - -static const unsigned char mt6370_val_en_hidden_mode[] = { - 0x96, 0x69, 0xC3, 0x3C, -}; - -static const unsigned char mt6370_val_en_test_mode[] = { - 0x69, 0x96, 0x63, 0x70, -}; -#endif /* CONFIG_CHARGER_MT6370 */ - -#if defined(CONFIG_CHARGER_RT9466) || defined(CONFIG_CHARGER_RT9467) -enum rt946x_irq { - RT946X_IRQ_CHGSTATC = 0, - RT946X_IRQ_CHGFAULT, - RT946X_IRQ_TSSTATC, - RT946X_IRQ_CHGIRQ1, - RT946X_IRQ_CHGIRQ2, - RT946X_IRQ_CHGIRQ3, -#ifdef CONFIG_CHARGER_RT9467 - RT946X_IRQ_DPDMIRQ, -#endif - RT946X_IRQ_COUNT, -}; - -static uint8_t rt946x_irqmask[RT946X_IRQ_COUNT] = { - 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, -#ifdef CONFIG_CHARGER_RT9467 - 0xFC, -#endif -}; - -static const uint8_t rt946x_irq_maskall[RT946X_IRQ_COUNT] = { - 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, -#ifdef CONFIG_CHARGER_RT9467 - 0xFF, -#endif -}; -#elif defined(CONFIG_CHARGER_MT6370) -enum rt946x_irq { - MT6370_IRQ_CHGSTAT1 = 0, - MT6370_IRQ_CHGSTAT2, - MT6370_IRQ_CHGSTAT3, - MT6370_IRQ_CHGSTAT4, - MT6370_IRQ_CHGSTAT5, - MT6370_IRQ_CHGSTAT6, - MT6370_IRQ_DPDMSTAT, - MT6370_IRQ_DICHGSTAT, - MT6370_IRQ_OVPCTRLSTAT, - MT6370_IRQ_FLEDSTAT1, - MT6370_IRQ_FLEDSTAT2, - MT6370_IRQ_BASESTAT, - MT6370_IRQ_LDOSTAT, - MT6370_IRQ_RGBSTAT, - MT6370_IRQ_BLSTAT, - MT6370_IRQ_DBSTAT, - RT946X_IRQ_COUNT, -}; - -static uint8_t rt946x_irqmask[RT946X_IRQ_COUNT] = { - 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, -}; - -static const uint8_t rt946x_irq_maskall[RT946X_IRQ_COUNT] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, -}; -#endif - -static enum ec_error_list rt946x_set_current(int chgnum, int current); -static enum ec_error_list rt946x_get_current(int chgnum, int *current); -static enum ec_error_list rt946x_set_voltage(int chgnum, int voltage); -static enum ec_error_list rt946x_enable_otg_power(int chgnum, int enabled); -static const struct charger_info *rt946x_get_info(int chgnum); - -/* Must be in ascending order */ -static const uint16_t rt946x_boost_current[] = { - 500, 700, 1100, 1300, 1800, 2100, 2400, -}; - -static enum ec_error_list rt946x_read8(int chgnum, int reg, int *val) -{ - return i2c_read8(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, reg, val); -} - -static enum ec_error_list rt946x_write8(int chgnum, int reg, int val) -{ - return i2c_write8(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, reg, val); -} - -static enum ec_error_list rt946x_block_write(int chgnum, int reg, - const uint8_t *val, int len) -{ - return i2c_write_block(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, - reg, val, len); -} - -static int rt946x_update_bits(int chgnum, int reg, int mask, int val) -{ - int rv; - int reg_val = 0; - - rv = rt946x_read8(chgnum, reg, ®_val); - if (rv) - return rv; - reg_val &= ~mask; - reg_val |= (mask & val); - rv = rt946x_write8(chgnum, reg, reg_val); - return rv; -} - -static inline int rt946x_set_bit(int chgnum, int reg, int mask) -{ - return rt946x_update_bits(chgnum, reg, mask, mask); -} - -static inline int rt946x_clr_bit(int chgnum, int reg, int mask) -{ - return rt946x_update_bits(chgnum, reg, mask, 0x00); -} - -static inline int mt6370_pmu_reg_test_bit(int chgnum, int cmd, int shift, - int *is_one) -{ - int rv, data; - - rv = rt946x_read8(chgnum, cmd, &data); - if (rv) { - *is_one = 0; - return rv; - } - - *is_one = !!(data & BIT(shift)); - return rv; -} - -static inline uint8_t rt946x_closest_reg(uint16_t min, uint16_t max, - uint16_t step, uint16_t target) -{ - if (target < min) - return 0; - if (target >= max) - return ((max - min) / step); - return (target - min) / step; -} - -static int rt946x_get_ieoc(int chgnum, uint32_t *ieoc) -{ - int ret, reg_ieoc; - - ret = rt946x_read8(chgnum, RT946X_REG_CHGCTRL9, ®_ieoc); - if (ret) - return ret; - - *ieoc = RT946X_IEOC_MIN + - RT946X_IEOC_STEP * - ((reg_ieoc & RT946X_MASK_IEOC) >> RT946X_SHIFT_IEOC); - - return EC_SUCCESS; -} - -#ifdef CONFIG_CHARGER_MT6370 -static int mt6370_enable_hidden_mode(int chgnum, int en) -{ - int rv = 0; - - if (in_interrupt_context()) { - CPRINTS("Err: use hidden mode in IRQ"); - return EC_ERROR_INVAL; - } - - mutex_lock(&hidden_mode_lock); - if (en) { - if (hidden_mode_cnt == 0) { - rv = rt946x_block_write(chgnum, - mt6370_reg_en_hidden_mode[0], - mt6370_val_en_hidden_mode, - ARRAY_SIZE(mt6370_val_en_hidden_mode)); - if (rv) - goto out; - } - hidden_mode_cnt++; - } else { - if (hidden_mode_cnt == 1) /* last one */ - rv = rt946x_write8(chgnum, mt6370_reg_en_hidden_mode[0], - 0x00); - hidden_mode_cnt--; - if (rv) - goto out; - } - -out: - mutex_unlock(&hidden_mode_lock); - return rv; -} - -/* - * Vsys short protection: - * When the system is charging at 500mA, and if Isys > 3600mA, the - * power path will be turned off and cause the system shutdown. - * When Ichg < 400mA, then power path is roughly 1/8 of the original. - * When Isys > 3600mA, this cause the voltage between Vbat and Vsys too - * huge (Vbat - Vsys > Vsys short portection) and turns off the power - * path. - * To workaround this, - * 1. disable Vsys short protection when Ichg is set below 900mA - * 2. forbids Ichg <= 400mA (this is done natually on mt6370, since mt6370's - * minimum current is 512) - */ -static int mt6370_ichg_workaround(int chgnum, int new_ichg) -{ - int rv = EC_SUCCESS; - int curr_ichg; - - /* - * TODO(b:144532905): The workaround should be applied to rt9466 as - * well. But this needs rt9466's hidden register datasheet. Enable - * this if we need it in the future. - */ - if (!IS_ENABLED(CONFIG_CHARGER_MT6370)) - return EC_SUCCESS; - - rv = rt946x_get_current(chgnum, &curr_ichg); - if (rv) - return rv; - - mt6370_enable_hidden_mode(chgnum, 1); - - /* disable Vsys protect if if the new ichg is below 900mA */ - if (curr_ichg >= 900 && new_ichg < 900) - rv = rt946x_update_bits(chgnum, RT946X_REG_CHGHIDDENCTRL7, - RT946X_MASK_HIDDENCTRL7_VSYS_PROTECT, - 0); - /* enable Vsys protect if the new ichg is above 900mA */ - else if (new_ichg >= 900 && curr_ichg < 900) - rv = rt946x_update_bits(chgnum, RT946X_REG_CHGHIDDENCTRL7, - RT946X_MASK_HIDDENCTRL7_VSYS_PROTECT, - RT946X_ENABLE_VSYS_PROTECT); - - mt6370_enable_hidden_mode(chgnum, 0); - return rv; -} -#endif /* CONFIG_CHARGER_MT6370 */ - -static inline int rt946x_enable_wdt(int chgnum, int en) -{ - return (en ? rt946x_set_bit : rt946x_clr_bit) - (chgnum, RT946X_REG_CHGCTRL13, RT946X_MASK_WDT_EN); -} - -/* Enable high-impedance mode */ -static inline int rt946x_enable_hz(int chgnum, int en) -{ - return (en ? rt946x_set_bit : rt946x_clr_bit) - (chgnum, RT946X_REG_CHGCTRL1, RT946X_MASK_HZ_EN); -} - -int rt946x_por_reset(void) -{ - int rv, val; - -#ifdef CONFIG_CHARGER_MT6370 - /* Soft reset. It takes only 1ns for resetting. b/116682788 */ - val = RT946X_MASK_SOFT_RST; - /* - * MT6370 has to set passcodes before resetting all the registers and - * logics. - */ - rv = rt946x_write8(CHARGER_SOLO, MT6370_REG_RSTPASCODE1, - MT6370_MASK_RSTPASCODE1); - rv |= rt946x_write8(CHARGER_SOLO, MT6370_REG_RSTPASCODE2, - MT6370_MASK_RSTPASCODE2); -#else - /* Hard reset, may take several milliseconds. */ - val = RT946X_MASK_RST; - rv = rt946x_enable_hz(CHARGER_SOLO, 0); -#endif - if (rv) - return rv; - - return rt946x_set_bit(CHARGER_SOLO, RT946X_REG_CORECTRL_RST, val); -} - -static int rt946x_reset_to_zero(int chgnum) -{ - int rv; - - rv = rt946x_set_current(chgnum, 0); - if (rv) - return rv; - - rv = rt946x_set_voltage(chgnum, 0); - if (rv) - return rv; - - return rt946x_enable_hz(chgnum, 1); -} - -static int rt946x_enable_bc12_detection(int chgnum, int en) -{ -#if defined(CONFIG_CHARGER_RT9467) || defined(CONFIG_CHARGER_MT6370) - int rv; - - if (en) { -#ifdef CONFIG_CHARGER_MT6370_BC12_GPIO - gpio_set_level(GPIO_BC12_DET_EN, 1); -#endif /* CONFIG_CHARGER_MT6370_BC12_GPIO */ - return rt946x_set_bit(chgnum, RT946X_REG_DPDM1, - RT946X_MASK_USBCHGEN); - } - - rv = rt946x_clr_bit(chgnum, RT946X_REG_DPDM1, RT946X_MASK_USBCHGEN); -#ifdef CONFIG_CHARGER_MT6370_BC12_GPIO - gpio_set_level(GPIO_BC12_DET_EN, 0); -#endif /* CONFIG_CHARGER_MT6370_BC12_GPIO */ - return rv; -#endif - return 0; -} - -static int rt946x_set_ieoc(int chgnum, unsigned int ieoc) -{ - uint8_t reg_ieoc; - - reg_ieoc = rt946x_closest_reg(RT946X_IEOC_MIN, RT946X_IEOC_MAX, - RT946X_IEOC_STEP, ieoc); - - CPRINTS("ieoc=%d", ieoc); - - return rt946x_update_bits(chgnum, RT946X_REG_CHGCTRL9, RT946X_MASK_IEOC, - reg_ieoc << RT946X_SHIFT_IEOC); -} - -static int rt946x_set_mivr(int chgnum, unsigned int mivr) -{ - uint8_t reg_mivr = 0; - - reg_mivr = rt946x_closest_reg(RT946X_MIVR_MIN, RT946X_MIVR_MAX, - RT946X_MIVR_STEP, mivr); - - CPRINTS("mivr=%d", mivr); - - return rt946x_update_bits(chgnum, RT946X_REG_CHGCTRL6, RT946X_MASK_MIVR, - reg_mivr << RT946X_SHIFT_MIVR); -} - -static int rt946x_set_boost_voltage(int chgnum, unsigned int voltage) -{ - uint8_t reg_voltage = 0; - - reg_voltage = rt946x_closest_reg(RT946X_BOOST_VOLTAGE_MIN, - RT946X_BOOST_VOLTAGE_MAX, RT946X_BOOST_VOLTAGE_STEP, voltage); - - CPRINTS("voltage=%d", voltage); - - return rt946x_update_bits(chgnum, RT946X_REG_CHGCTRL5, - RT946X_MASK_BOOST_VOLTAGE, - reg_voltage << RT946X_SHIFT_BOOST_VOLTAGE); -} - -static int rt946x_set_boost_current(int chgnum, unsigned int current) -{ - int i; - - /* - * Find the smallest output current threshold which can support - * our requested output current. Use the greatest achievable - * boost current (2.4A) if requested current is too large. - */ - for (i = 0; i < ARRAY_SIZE(rt946x_boost_current) - 1; i++) { - if (current < rt946x_boost_current[i]) - break; - } - - CPRINTS("current=%d", current); - - return rt946x_update_bits(chgnum, RT946X_REG_CHGCTRL10, - RT946X_MASK_BOOST_CURRENT, - i << RT946X_SHIFT_BOOST_CURRENT); -} - -static int rt946x_set_ircmp_vclamp(int chgnum, unsigned int vclamp) -{ - uint8_t reg_vclamp = 0; - - reg_vclamp = rt946x_closest_reg(RT946X_IRCMP_VCLAMP_MIN, - RT946X_IRCMP_VCLAMP_MAX, RT946X_IRCMP_VCLAMP_STEP, vclamp); - - CPRINTS("vclamp=%d", vclamp); - - return rt946x_update_bits(chgnum, RT946X_REG_CHGCTRL18, - RT946X_MASK_IRCMP_VCLAMP, - reg_vclamp << RT946X_SHIFT_IRCMP_VCLAMP); -} - -static int rt946x_set_ircmp_res(int chgnum, unsigned int res) -{ - uint8_t reg_res = 0; - - reg_res = rt946x_closest_reg(RT946X_IRCMP_RES_MIN, RT946X_IRCMP_RES_MAX, - RT946X_IRCMP_RES_STEP, res); - - CPRINTS("res=%d", res); - - return rt946x_update_bits(chgnum, RT946X_REG_CHGCTRL18, - RT946X_MASK_IRCMP_RES, - reg_res << RT946X_SHIFT_IRCMP_RES); -} - -static int rt946x_set_vprec(int chgnum, unsigned int vprec) -{ - uint8_t reg_vprec = 0; - - reg_vprec = rt946x_closest_reg(RT946X_VPREC_MIN, RT946X_VPREC_MAX, - RT946X_VPREC_STEP, vprec); - - CPRINTS("vprec=%d", vprec); - - return rt946x_update_bits(chgnum, RT946X_REG_CHGCTRL8, - RT946X_MASK_VPREC, - reg_vprec << RT946X_SHIFT_VPREC); -} - -static int rt946x_set_iprec(int chgnum, unsigned int iprec) -{ - uint8_t reg_iprec = 0; - - reg_iprec = rt946x_closest_reg(RT946X_IPREC_MIN, RT946X_IPREC_MAX, - RT946X_IPREC_STEP, iprec); - - CPRINTS("iprec=%d", iprec); - - return rt946x_update_bits(chgnum, RT946X_REG_CHGCTRL8, - RT946X_MASK_IPREC, - reg_iprec << RT946X_SHIFT_IPREC); -} - -static int rt946x_init_irq(int chgnum) -{ - int rv = 0; - int unused; - int i; - - /* Mask all interrupts */ - rv = rt946x_block_write(chgnum, RT946X_REG_CHGSTATCCTRL, - rt946x_irq_maskall, RT946X_IRQ_COUNT); - if (rv) - return rv; - - /* Clear all interrupt flags */ - for (i = 0; i < RT946X_IRQ_COUNT; i++) { - rv = rt946x_read8(chgnum, RT946X_REG_CHGSTATC + i, &unused); - if (rv) - return rv; - } - - /* Init interrupt */ - return rt946x_block_write(chgnum, RT946X_REG_CHGSTATCCTRL, - rt946x_irqmask, ARRAY_SIZE(rt946x_irqmask)); -} - -static int rt946x_init_setting(int chgnum) -{ - int rv = 0; - const struct battery_info *batt_info = battery_get_info(); - const struct rt946x_init_setting *setting = board_rt946x_init_setting(); - -#ifdef CONFIG_BATTERY_SMART - /* Disable EOC */ - rv = rt946x_enable_charge_eoc(0); - if (rv) - return rv; -#endif - -#ifdef CONFIG_CHARGER_OTG - /* Disable boost-mode output voltage */ - rv = rt946x_enable_otg_power(chgnum, 0); - if (rv) - return rv; -#endif - /* Disable BC 1.2 detection by default. It will be enabled on demand */ - rv = rt946x_enable_bc12_detection(chgnum, 0); - if (rv) - return rv; - /* Disable WDT */ - rv = rt946x_enable_wdt(chgnum, 0); - if (rv) - return rv; - /* Disable battery thermal protection */ - rv = rt946x_clr_bit(chgnum, RT946X_REG_CHGCTRL16, RT946X_MASK_JEITA_EN); - if (rv) - return rv; - /* Disable charge timer */ - rv = rt946x_clr_bit(chgnum, RT946X_REG_CHGCTRL12, RT946X_MASK_TMR_EN); - if (rv) - return rv; - rv = rt946x_set_mivr(chgnum, setting->mivr); - if (rv) - return rv; - rv = rt946x_set_ieoc(chgnum, setting->eoc_current); - if (rv) - return rv; - rv = rt946x_set_boost_voltage(chgnum, - setting->boost_voltage); - if (rv) - return rv; - rv = rt946x_set_boost_current(chgnum, - setting->boost_current); - if (rv) - return rv; - rv = rt946x_set_ircmp_vclamp(chgnum, setting->ircmp_vclamp); - if (rv) - return rv; - rv = rt946x_set_ircmp_res(chgnum, setting->ircmp_res); - if (rv) - return rv; - rv = rt946x_set_vprec(chgnum, batt_info->precharge_voltage ? - batt_info->precharge_voltage : batt_info->voltage_min); - if (rv) - return rv; - rv = rt946x_set_iprec(chgnum, batt_info->precharge_current); - if (rv) - return rv; - -#ifdef CONFIG_CHARGER_MT6370_BACKLIGHT - rt946x_write8(chgnum, MT6370_BACKLIGHT_BLEN, - MT6370_MASK_BLED_EXT_EN | MT6370_MASK_BLED_EN | - MT6370_MASK_BLED_1CH_EN | MT6370_MASK_BLED_2CH_EN | - MT6370_MASK_BLED_3CH_EN | MT6370_MASK_BLED_4CH_EN | - MT6370_BLED_CODE_LINEAR); - rt946x_update_bits(chgnum, MT6370_BACKLIGHT_BLPWM, - MT6370_MASK_BLPWM_BLED_PWM, - BIT(MT6370_SHIFT_BLPWM_BLED_PWM)); -#endif - - return rt946x_init_irq(chgnum); -} - -#ifdef CONFIG_CHARGER_OTG -static enum ec_error_list rt946x_enable_otg_power(int chgnum, int enabled) -{ - return (enabled ? rt946x_set_bit : rt946x_clr_bit) - (chgnum, RT946X_REG_CHGCTRL1, RT946X_MASK_OPA_MODE); -} - -static int rt946x_is_sourcing_otg_power(int chgnum, int port) -{ - int val; - - if (rt946x_read8(CHARGER_SOLO, RT946X_REG_CHGCTRL1, &val)) - return 0; - - return !!(val & RT946X_MASK_OPA_MODE); -} -#endif - -static enum ec_error_list rt946x_set_input_current_limit(int chgnum, - int input_current) -{ - uint8_t reg_iin = 0; - const struct charger_info * const info = rt946x_get_info(chgnum); - - reg_iin = rt946x_closest_reg(info->input_current_min, - info->input_current_max, info->input_current_step, - input_current); - - CPRINTS("iin=%d", input_current); - - return rt946x_update_bits(chgnum, RT946X_REG_CHGCTRL3, RT946X_MASK_AICR, - reg_iin << RT946X_SHIFT_AICR); -} - -static enum ec_error_list rt946x_get_input_current_limit(int chgnum, - int *input_current) -{ - int rv; - int val = 0; - const struct charger_info * const info = rt946x_get_info(chgnum); - - rv = rt946x_read8(chgnum, RT946X_REG_CHGCTRL3, &val); - if (rv) - return rv; - - val = (val & RT946X_MASK_AICR) >> RT946X_SHIFT_AICR; - *input_current = val * info->input_current_step - + info->input_current_min; - - return EC_SUCCESS; -} - -static enum ec_error_list rt946x_manufacturer_id(int chgnum, int *id) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -static enum ec_error_list rt946x_device_id(int chgnum, int *id) -{ - int rv; - - rv = rt946x_read8(chgnum, RT946X_REG_DEVICEID, id); - if (rv == EC_SUCCESS) - *id &= RT946X_MASK_VENDOR_ID; - return rv; -} - -static enum ec_error_list rt946x_get_option(int chgnum, int *option) -{ - /* Ignored: does not exist */ - *option = 0; - return EC_SUCCESS; -} - -static enum ec_error_list rt946x_set_option(int chgnum, int option) -{ - /* Ignored: does not exist */ - return EC_SUCCESS; -} - -static const struct charger_info *rt946x_get_info(int chgnum) -{ - return &rt946x_charger_info; -} - -static enum ec_error_list rt946x_get_status(int chgnum, int *status) -{ - int rv; - int val = 0; - - rv = rt946x_read8(chgnum, RT946X_REG_CHGCTRL2, &val); - if (rv) - return rv; - val = (val & RT946X_MASK_CHG_EN) >> RT946X_SHIFT_CHG_EN; - if (!val) - *status |= CHARGER_CHARGE_INHIBITED; - - rv = rt946x_read8(chgnum, RT946X_REG_CHGFAULT, &val); - if (rv) - return rv; - if (val & RT946X_MASK_CHG_VBATOV) - *status |= CHARGER_VOLTAGE_OR; - - - rv = rt946x_read8(chgnum, RT946X_REG_CHGNTC, &val); - if (rv) - return rv; - val = (val & RT946X_MASK_BATNTC_FAULT) >> RT946X_SHIFT_BATNTC_FAULT; - - switch (val) { - case RT946X_BATTEMP_WARM: - *status |= CHARGER_RES_HOT; - break; - case RT946X_BATTEMP_COOL: - *status |= CHARGER_RES_COLD; - break; - case RT946X_BATTEMP_COLD: - *status |= CHARGER_RES_COLD; - *status |= CHARGER_RES_UR; - break; - case RT946X_BATTEMP_HOT: - *status |= CHARGER_RES_HOT; - *status |= CHARGER_RES_OR; - break; - default: - break; - } - - return EC_SUCCESS; -} - -static enum ec_error_list rt946x_set_mode(int chgnum, int mode) -{ - int rv; - - if (mode & CHARGE_FLAG_POR_RESET) { - rv = rt946x_por_reset(); - if (rv) - return rv; - } - - if (mode & CHARGE_FLAG_RESET_TO_ZERO) { - rv = rt946x_reset_to_zero(chgnum); - if (rv) - return rv; - } - - return EC_SUCCESS; -} - -static enum ec_error_list rt946x_get_current(int chgnum, int *current) -{ - int rv; - int val = 0; - const struct charger_info * const info = rt946x_get_info(chgnum); - - rv = rt946x_read8(chgnum, RT946X_REG_CHGCTRL7, &val); - if (rv) - return rv; - - val = (val & RT946X_MASK_ICHG) >> RT946X_SHIFT_ICHG; - *current = val * info->current_step + info->current_min; - - return EC_SUCCESS; -} - -static enum ec_error_list rt946x_set_current(int chgnum, int current) -{ - int rv; - uint8_t reg_icc; - static int workaround; - const struct charger_info *const info = rt946x_get_info(chgnum); - - /* - * mt6370's minimum regulated current is 500mA REG17[7:2] 0b100, - * values below 0b100 are preserved. - */ - if (IS_ENABLED(CONFIG_CHARGER_MT6370)) - current = MAX(500, current); - -#ifdef CONFIG_CHARGER_MT6370 - rv = mt6370_ichg_workaround(chgnum, current); - if (rv) - return rv; -#endif - - reg_icc = rt946x_closest_reg(info->current_min, info->current_max, - info->current_step, current); - - rv = rt946x_update_bits(chgnum, RT946X_REG_CHGCTRL7, RT946X_MASK_ICHG, - reg_icc << RT946X_SHIFT_ICHG); - if (rv) - return rv; - - if (IS_ENABLED(CONFIG_CHARGER_RT9466) || - IS_ENABLED(CONFIG_CHARGER_MT6370)) { - uint32_t curr_ieoc; - - /* - * workaround to make IEOC accurate: - * witht normal charging (ICC >= 900mA), the power path is fully - * turned on. But at low charging current state (ICC < 900mA), - * the power path will only be partially turned on. So under - * such situation, the IEOC is inaccurate. - */ - rv = rt946x_get_ieoc(chgnum, &curr_ieoc); - if (rv) - return rv; - - if (current < 900 && !workaround) { - /* raise IEOC if charge current is under 900 */ - rv = rt946x_set_ieoc(chgnum, curr_ieoc + 100); - workaround = 1; - } else if (current >= 900 && workaround) { - /* reset IEOC if charge current is above 900 */ - workaround = 0; - rv = rt946x_set_ieoc(chgnum, curr_ieoc - 100); - } - } - - return rv; -} - -static enum ec_error_list rt946x_get_voltage(int chgnum, int *voltage) -{ - int rv; - int val = 0; - const struct charger_info * const info = rt946x_get_info(chgnum); - - rv = rt946x_read8(chgnum, RT946X_REG_CHGCTRL4, &val); - if (rv) - return rv; - - val = (val & RT946X_MASK_CV) >> RT946X_SHIFT_CV; - *voltage = val * info->voltage_step + info->voltage_min; - - return EC_SUCCESS; -} - -static enum ec_error_list rt946x_set_voltage(int chgnum, int voltage) -{ - uint8_t reg_cv = 0; - const struct charger_info * const info = rt946x_get_info(chgnum); - - reg_cv = rt946x_closest_reg(info->voltage_min, info->voltage_max, - info->voltage_step, voltage); - - return rt946x_update_bits(chgnum, RT946X_REG_CHGCTRL4, RT946X_MASK_CV, - reg_cv << RT946X_SHIFT_CV); -} - -static enum ec_error_list rt946x_discharge_on_ac(int chgnum, int enable) -{ - return rt946x_enable_hz(chgnum, enable); -} - -/* Setup sourcing current to prevent overload */ -#ifdef CONFIG_CHARGER_ILIM_PIN_DISABLED -static int rt946x_enable_ilim_pin(int chgnum, int en) -{ - int ret; - - ret = (en ? rt946x_set_bit : rt946x_clr_bit) - (chgnum, RT946X_REG_CHGCTRL3, RT946X_MASK_ILIMEN); - - return ret; -} - -static int rt946x_select_ilmt(int chgnum, enum rt946x_ilmtsel sel) -{ - int ret; - - ret = rt946x_update_bits(chgnum, RT946X_REG_CHGCTRL2, - RT946X_MASK_ILMTSEL, - sel << RT946X_SHIFT_ILMTSEL); - - return ret; -} -#endif /* CONFIG_CHARGER_ILIM_PIN_DISABLED */ - -/* Charging power state initialization */ -static enum ec_error_list rt946x_post_init(int chgnum) -{ -#ifdef CONFIG_CHARGER_ILIM_PIN_DISABLED - int rv; - - rv = rt946x_select_ilmt(chgnum, RT946X_ILMTSEL_AICR); - if (rv) - return rv; - - /* Need 5ms to ramp after choose current limit source */ - msleep(5); - - /* Disable ILIM pin */ - rv = rt946x_enable_ilim_pin(chgnum, 0); - if (rv) - return rv; -#endif - return EC_SUCCESS; -} - -/* Hardware current ramping (aka AICL: Average Input Current Level) */ -#ifdef CONFIG_CHARGE_RAMP_HW -static int rt946x_get_mivr(int chgnum, int *mivr) -{ - int rv; - int val = 0; - - rv = rt946x_read8(chgnum, RT946X_REG_CHGCTRL6, &val); - if (rv) - return rv; - - val = (val & RT946X_MASK_MIVR) >> RT946X_SHIFT_MIVR; - *mivr = val * RT946X_MIVR_STEP + RT946X_MIVR_MIN; - - return EC_SUCCESS; -} - -static int rt946x_set_aicl_vth(int chgnum, uint8_t aicl_vth) -{ - uint8_t reg_aicl_vth = 0; - - reg_aicl_vth = rt946x_closest_reg(RT946X_AICLVTH_MIN, - RT946X_AICLVTH_MAX, RT946X_AICLVTH_STEP, aicl_vth); - - return rt946x_update_bits(chgnum, RT946X_REG_CHGCTRL14, - RT946X_MASK_AICLVTH, - reg_aicl_vth << RT946X_SHIFT_AICLVTH); -} - -static enum ec_error_list rt946x_set_hw_ramp(int chgnum, int enable) -{ - int rv; - unsigned int mivr = 0; - - if (!enable) { - rv = rt946x_clr_bit(chgnum, RT946X_REG_CHGCTRL14, - RT946X_MASK_AICLMEAS); - return rv; - } - - rv = rt946x_get_mivr(chgnum, &mivr); - if (rv < 0) - return rv; - - /* - * Check if there's a suitable AICL_VTH. - * The vendor suggests setting AICL_VTH as (MIVR + 200mV). - */ - if ((mivr + 200) > RT946X_AICLVTH_MAX) { - CPRINTS("mivr(%d) too high", mivr); - return EC_ERROR_INVAL; - } - - rv = rt946x_set_aicl_vth(chgnum, mivr + 200); - if (rv < 0) - return rv; - - return rt946x_set_bit(chgnum, RT946X_REG_CHGCTRL14, - RT946X_MASK_AICLMEAS); -} - -static int rt946x_ramp_is_stable(int chgnum) -{ - int rv; - int val = 0; - - rv = rt946x_read8(chgnum, RT946X_REG_CHGCTRL14, &val); - val = (val & RT946X_MASK_AICLMEAS) >> RT946X_SHIFT_AICLMEAS; - - return (!rv && !val); -} - -static int rt946x_ramp_is_detected(int chgnum) -{ - return 1; -} - -static int rt946x_ramp_get_current_limit(int chgnum) -{ - int rv; - int input_current = 0; - - rv = rt946x_get_input_current_limit(chgnum, &input_current); - - return rv ? -1 : input_current; -} -#endif /* CONFIG_CHARGE_RAMP_HW */ - -static void rt946x_init(int chgnum) -{ - int ret = rt946x_init_setting(chgnum); - - CPRINTS("init%d %s(%d)", chgnum, ret ? "fail" : "good", ret); -} - -#ifdef HAS_TASK_USB_CHG -#ifdef CONFIG_CHARGER_MT6370 -static int mt6370_detect_apple_samsung_ta(int chgnum, int usb_stat) -{ - int ret, reg; - int chg_type = - (usb_stat & MT6370_MASK_USB_STATUS) >> MT6370_SHIFT_USB_STATUS; - int dp_2_3v, dm_2_3v; - - /* Only SDP/CDP/DCP could possibly be Apple/Samsung TA */ - if (chg_type != MT6370_CHG_TYPE_SDPNSTD && - chg_type != MT6370_CHG_TYPE_CDP && - chg_type != MT6370_CHG_TYPE_DCP) - return chg_type; - - if (chg_type == MT6370_CHG_TYPE_SDPNSTD || - chg_type == MT6370_CHG_TYPE_CDP) - if (!(usb_stat & MT6370_MASK_DCD_TIMEOUT)) - return chg_type; - - /* Check D+ > 0.9V */ - ret = rt946x_update_bits(chgnum, MT6370_REG_QCSTATUS2, - MT6360_MASK_CHECK_DPDM, - MT6370_MASK_APP_SS_EN | MT6370_MASK_APP_SS_PL); - ret |= rt946x_read8(chgnum, MT6370_REG_QCSTATUS2, ®); - - if (ret) - return chg_type; - - /* Normal port (D+ < 0.9V) */ - if (!(reg & MT6370_MASK_SS_OUT)) - return chg_type; - - /* Samsung charger (D+ < 1.5V) */ - if (!(reg & MT6370_MASK_APP_OUT)) - return MT6370_CHG_TYPE_SAMSUNG_CHARGER; - - /* Check D+ > 2.3 V */ - ret = rt946x_update_bits(chgnum, MT6370_REG_QCSTATUS2, - MT6360_MASK_CHECK_DPDM, - MT6370_MASK_APP_REF | MT6370_MASK_APP_SS_PL | - MT6370_MASK_APP_SS_EN); - ret |= rt946x_read8(chgnum, MT6370_REG_QCSTATUS2, ®); - dp_2_3v = reg & MT6370_MASK_APP_OUT; - - /* Check D- > 2.3 V */ - ret |= rt946x_update_bits(chgnum, - MT6370_REG_QCSTATUS2, MT6360_MASK_CHECK_DPDM, - MT6370_MASK_APP_REF | MT6370_MASK_APP_DPDM_IN | - MT6370_MASK_APP_SS_PL | MT6370_MASK_APP_SS_EN); - ret |= rt946x_read8(chgnum, MT6370_REG_QCSTATUS2, ®); - dm_2_3v = reg & MT6370_MASK_APP_OUT; - - if (ret) - return chg_type; - - /* Apple charger */ - if (!dp_2_3v && !dm_2_3v) - /* Apple 2.5W charger */ - return MT6370_CHG_TYPE_APPLE_0_5A_CHARGER; - else if (!dp_2_3v && dm_2_3v) - /* Apple 5W charger */ - return MT6370_CHG_TYPE_APPLE_1_0A_CHARGER; - else if (dp_2_3v && !dm_2_3v) - /* Apple 10W charger */ - return MT6370_CHG_TYPE_APPLE_2_1A_CHARGER; - else - /* Apple 12W charger */ - return MT6370_CHG_TYPE_APPLE_2_4A_CHARGER; -} -#endif - -static int mt6370_get_bc12_device_type(int charger_type) -{ - switch (charger_type) { - case MT6370_CHG_TYPE_SDP: - case MT6370_CHG_TYPE_SDPNSTD: - return CHARGE_SUPPLIER_BC12_SDP; - case MT6370_CHG_TYPE_CDP: - return CHARGE_SUPPLIER_BC12_CDP; - case MT6370_CHG_TYPE_DCP: - case MT6370_CHG_TYPE_SAMSUNG_CHARGER: - case MT6370_CHG_TYPE_APPLE_0_5A_CHARGER: - case MT6370_CHG_TYPE_APPLE_1_0A_CHARGER: - case MT6370_CHG_TYPE_APPLE_2_1A_CHARGER: - case MT6370_CHG_TYPE_APPLE_2_4A_CHARGER: - return CHARGE_SUPPLIER_BC12_DCP; - default: - return CHARGE_SUPPLIER_NONE; - } -} - -/* Returns a mt6370 charger_type. */ -static int mt6370_get_charger_type(int chgnum) -{ -#ifdef CONFIG_CHARGER_MT6370 - int reg; - - if (rt946x_read8(chgnum, MT6370_REG_USBSTATUS1, ®)) - return CHARGE_SUPPLIER_NONE; - return mt6370_detect_apple_samsung_ta(chgnum, reg); -#else - return CHARGE_SUPPLIER_NONE; -#endif -} - -/* - * The USB Type-C specification limits the maximum amount of current from BC 1.2 - * suppliers to 1.5A. Technically, proprietary methods are not allowed, but we - * will continue to allow those. - */ -static int mt6370_get_bc12_ilim(int charge_supplier) -{ - switch (charge_supplier) { - case MT6370_CHG_TYPE_APPLE_0_5A_CHARGER: - return 500; - case MT6370_CHG_TYPE_APPLE_1_0A_CHARGER: - return 1000; - case MT6370_CHG_TYPE_APPLE_2_1A_CHARGER: - case MT6370_CHG_TYPE_APPLE_2_4A_CHARGER: - case MT6370_CHG_TYPE_DCP: - case MT6370_CHG_TYPE_CDP: - case MT6370_CHG_TYPE_SAMSUNG_CHARGER: - return USB_CHARGER_MAX_CURR_MA; - case MT6370_CHG_TYPE_SDP: - default: - return USB_CHARGER_MIN_CURR_MA; - } -} - -static int rt946x_get_bc12_device_type(int chgnum, int charger_type) -{ - int reg; - - if (rt946x_read8(chgnum, RT946X_REG_DPDM1, ®)) - return CHARGE_SUPPLIER_NONE; - - switch (reg & RT946X_MASK_BC12_TYPE) { - case RT946X_MASK_SDP: - return CHARGE_SUPPLIER_BC12_SDP; - case RT946X_MASK_CDP: - return CHARGE_SUPPLIER_BC12_CDP; - case RT946X_MASK_DCP: - return CHARGE_SUPPLIER_BC12_DCP; - default: - return CHARGE_SUPPLIER_NONE; - } -} - -static int rt946x_get_bc12_ilim(int charge_supplier) -{ - switch (charge_supplier) { - case CHARGE_SUPPLIER_BC12_DCP: - if (IS_ENABLED(CONFIG_CHARGE_RAMP_SW) || - IS_ENABLED(CONFIG_CHARGE_RAMP_HW)) - /* A conservative value to prevent a bad charger. */ - return RT946X_AICR_TYP2MAX(USB_CHARGER_MAX_CURR_MA); - /* fallback */ - case CHARGE_SUPPLIER_BC12_CDP: - return USB_CHARGER_MAX_CURR_MA; - case CHARGE_SUPPLIER_BC12_SDP: - default: - return USB_CHARGER_MIN_CURR_MA; - } -} - -static void check_ac_state(void) -{ - static uint8_t ac; - - if (ac != extpower_is_present()) { - ac = !ac; - hook_notify(HOOK_AC_CHANGE); - } -} -DECLARE_DEFERRED(check_ac_state); - -void rt946x_interrupt(enum gpio_signal signal) -{ - task_wake(TASK_ID_USB_CHG); - /* - * Generally, VBUS detection can be done immediately when the port - * plug/unplug happens. But if it's a PD plug(and will generate an - * interrupt), then it will take a few milliseconds to raise VBUS - * by PD negotiation. - */ - hook_call_deferred(&check_ac_state_data, 100 * MSEC); -} - -int rt946x_toggle_bc12_detection(void) -{ - int rv; - rv = rt946x_enable_bc12_detection(CHARGER_SOLO, 0); - if (rv) - return rv; - /* mt6370 requires 40us delay to toggle RT946X_MASK_USBCHGEN */ - udelay(40); - return rt946x_enable_bc12_detection(CHARGER_SOLO, 1); -} - -static void check_pd_capable(void) -{ - const int port = TASK_ID_TO_USB_CHG_PORT(TASK_ID_USB_CHG); - - if (!pd_capable(port)) { - enum tcpc_cc_voltage_status cc1, cc2; - - tcpm_get_cc(port, &cc1, &cc2); - /* if CC is not changed. */ - if (cc_is_rp(cc1) || cc_is_rp(cc2)) - rt946x_toggle_bc12_detection(); - } -} -DECLARE_DEFERRED(check_pd_capable); - -static void rt946x_usb_connect(void) -{ - const int port = TASK_ID_TO_USB_CHG_PORT(TASK_ID_USB_CHG); - enum tcpc_cc_voltage_status cc1, cc2; - - tcpm_get_cc(port, &cc1, &cc2); - - /* - * Only detect BC1.2 device when USB-C device recognition is - * finished to prevent a potential race condition with USB enumeration. - * If CC exists RP, then it might be a BC12 or a PD capable device. - * Check this later to ensure it's not PD capable. - */ - if (cc_is_rp(cc1) || cc_is_rp(cc2)) - /* delay extra 50 ms to ensure SrcCap received */ - hook_call_deferred(&check_pd_capable_data, - PD_T_SINK_WAIT_CAP + 50 * MSEC); - hook_call_deferred(&check_ac_state_data, 0); -} -DECLARE_HOOK(HOOK_USB_PD_CONNECT, rt946x_usb_connect, HOOK_PRIO_DEFAULT); - -static void rt946x_pd_disconnect(void) -{ - /* Type-C disconnected, disable deferred check. */ - hook_call_deferred(&check_pd_capable_data, -1); - hook_call_deferred(&check_ac_state_data, 0); -} -DECLARE_HOOK(HOOK_USB_PD_DISCONNECT, rt946x_pd_disconnect, HOOK_PRIO_DEFAULT); - -int rt946x_get_adc(enum rt946x_adc_in_sel adc_sel, int *adc_val) -{ - int rv, i, adc_start, adc_result = 0; - int adc_data_h, adc_data_l, aicr; - const int max_wait_times = 6; - - if (in_interrupt_context()) { - CPRINTS("Err: use ADC in IRQ"); - return EC_ERROR_INVAL; - } - mutex_lock(&adc_access_lock); -#ifdef CONFIG_CHARGER_MT6370 - mt6370_enable_hidden_mode(CHARGER_SOLO, 1); -#endif - - /* Select ADC to desired channel */ - rv = rt946x_update_bits(CHARGER_SOLO, RT946X_REG_CHGADC, - RT946X_MASK_ADC_IN_SEL, - adc_sel << RT946X_SHIFT_ADC_IN_SEL); - if (rv) - goto out; - - if (adc_sel == MT6370_ADC_IBUS) { - rv = charger_get_input_current_limit(CHARGER_SOLO, &aicr); - if (rv) - goto out; - } - - /* Start ADC conversation */ - rv = rt946x_set_bit(CHARGER_SOLO, RT946X_REG_CHGADC, - RT946X_MASK_ADC_START); - if (rv) - goto out; - - for (i = 0; i < max_wait_times; i++) { - msleep(35); - rv = mt6370_pmu_reg_test_bit(CHARGER_SOLO, RT946X_REG_CHGADC, - RT946X_SHIFT_ADC_START, - &adc_start); - if (!adc_start && rv == 0) - break; - } - if (i == max_wait_times) - CPRINTS("conversion fail sel=%d", adc_sel); - - /* Read ADC data */ - rv = rt946x_read8(CHARGER_SOLO, RT946X_REG_ADCDATAH, &adc_data_h); - rv = rt946x_read8(CHARGER_SOLO, RT946X_REG_ADCDATAL, &adc_data_l); - if (rv) - goto out; - -#if defined(CONFIG_CHARGER_RT9466) || defined(CONFIG_CHARGER_RT9467) - if (adc_sel == RT946X_ADC_VBUS_DIV5) - adc_result = ((adc_data_h << 8) | adc_data_l) * 25; - else - CPRINTS("unsupported channel %d", adc_sel); - *adc_val = adc_result; -#elif defined(CONFIG_CHARGER_MT6370) - /* Calculate ADC value */ - adc_result = (adc_data_h * 256 + adc_data_l) - * mt6370_adc_unit[adc_sel] + mt6370_adc_offset[adc_sel]; - - /* For TS_BAT/TS_BUS, the real unit is 0.25, here we use 25(unit) */ - if (adc_sel == MT6370_ADC_TS_BAT) - adc_result /= 100; -#endif - -out: -#ifdef CONFIG_CHARGER_MT6370 - if (adc_sel == MT6370_ADC_IBUS) { - if (aicr < 400) /* 400mA */ - adc_result = adc_result * 67 / 100; - } - - if (adc_sel != MT6370_ADC_TS_BAT && adc_sel != MT6370_ADC_TEMP_JC) - *adc_val = adc_result / 1000; - else - *adc_val = adc_result; - mt6370_enable_hidden_mode(CHARGER_SOLO, 0); -#endif - mutex_unlock(&adc_access_lock); - return rv; -} - -static enum ec_error_list rt946x_get_vbus_voltage(int chgnum, int port, - int *voltage) -{ - int vbus_mv; - int rv; - - rv = rt946x_get_adc(RT946X_ADC_VBUS_DIV5, &vbus_mv); - *voltage = vbus_mv; - - return rv; -} - -#ifdef CONFIG_CHARGER_MT6370 -static int mt6370_toggle_cfo(void) -{ - int rv, data; - - rv = rt946x_read8(CHARGER_SOLO, MT6370_REG_FLEDEN, &data); - if (rv) - return rv; - - if (data & MT6370_STROBE_EN_MASK) - return rv; - - /* read data */ - rv = rt946x_read8(CHARGER_SOLO, RT946X_REG_CHGCTRL2, &data); - if (rv) - return rv; - - /* cfo off */ - data &= ~RT946X_MASK_CFO_EN; - rv = rt946x_write8(CHARGER_SOLO, RT946X_REG_CHGCTRL2, data); - if (rv) - return rv; - - /* cfo on */ - data |= RT946X_MASK_CFO_EN; - return rt946x_write8(CHARGER_SOLO, RT946X_REG_CHGCTRL2, data); -} - -static int mt6370_pmu_chg_mivr_irq_handler(int chgnum) -{ - int rv, ibus = 0, mivr_stat; - - rv = mt6370_pmu_reg_test_bit(chgnum, MT6370_REG_CHGSTAT1, - MT6370_SHIFT_MIVR_STAT, &mivr_stat); - if (rv) - return rv; - - if (!mivr_stat) { - CPRINTS("no mivr stat"); - return rv; - } - - rv = rt946x_get_adc(MT6370_ADC_IBUS, &ibus); - if (rv) - return rv; - - if (ibus < 100) /* 100mA */ - rv = mt6370_toggle_cfo(); - - return rv; -} - -static int mt6370_irq_handler(int chgnum) -{ - int data, mask, ret, reg_val; - int stat_chg, valid_chg, stat_old, stat_new; - - ret = rt946x_write8(chgnum, MT6370_REG_IRQMASK, MT6370_IRQ_MASK_ALL); - if (ret) - return ret; - - ret = rt946x_read8(chgnum, MT6370_REG_IRQIND, ®_val); - if (ret) - return ret; - - /* read stat before reading irq evt */ - ret = rt946x_read8(chgnum, MT6370_REG_CHGSTAT1, &stat_old); - if (ret) - return ret; - - /* workaround for irq, divided irq event into upper and lower */ - ret = rt946x_read8(chgnum, MT6370_REG_CHGIRQ1, &data); - if (ret) - return ret; - - /* read stat after reading irq evt */ - ret = rt946x_read8(chgnum, MT6370_REG_CHGSTAT1, &stat_new); - if (ret) - return ret; - - ret = rt946x_read8(chgnum, MT6370_REG_CHGMASK1, &mask); - if (ret) - return ret; - - ret = rt946x_write8(chgnum, MT6370_REG_IRQMASK, 0x00); - if (ret) - return ret; - - stat_chg = stat_old ^ stat_new; - valid_chg = (stat_new & 0xF1) | (~stat_new & 0xF1); - data |= (stat_chg & valid_chg); - data &= ~mask; - if (data) - ret = mt6370_pmu_chg_mivr_irq_handler(chgnum); - return ret; -} -#endif /* CONFIG_CHARGER_MT6370 */ - -static void rt946x_bc12_workaround(void) -{ - /* - * There is a parasitic capacitance on D+, - * which results in pulling D+ up too slow while detecting BC1.2. - * So we try to fix this in two steps: - * 1. Pull D+ up to a voltage under 0.6V - * 2. re-toggling and pull D+ up to 0.6V (again) - * and then detect the voltage of D-. - */ - rt946x_toggle_bc12_detection(); - msleep(10); - rt946x_toggle_bc12_detection(); -} -DECLARE_DEFERRED(rt946x_bc12_workaround); - -static void rt946x_usb_charger_task(const int unused) -{ - struct charge_port_info chg; - int bc12_type = CHARGE_SUPPLIER_NONE; - int chg_type; - int reg = 0; - int bc12_cnt = 0; - const int max_bc12_cnt = 3; - int voltage; - - chg.voltage = USB_CHARGER_VOLTAGE_MV; - while (1) { -#ifdef CONFIG_CHARGER_MT6370 - mt6370_irq_handler(CHARGER_SOLO); -#endif /* CONFIG_CHARGER_MT6370 */ - - rt946x_read8(CHARGER_SOLO, RT946X_REG_DPDMIRQ, ®); - - /* VBUS attach event */ - if (reg & RT946X_MASK_DPDMIRQ_ATTACH) { - charger_get_vbus_voltage(0, &voltage); - CPRINTS("VBUS attached: %dmV", voltage); - if (IS_ENABLED(CONFIG_CHARGER_MT6370)) { - chg_type = - mt6370_get_charger_type(CHARGER_SOLO); - bc12_type = - mt6370_get_bc12_device_type(chg_type); - chg.current = mt6370_get_bc12_ilim(bc12_type); - } else { - bc12_type = - rt946x_get_bc12_device_type(CHARGER_SOLO, - chg_type); - chg.current = rt946x_get_bc12_ilim(bc12_type); - } - CPRINTS("BC12 type %d", bc12_type); - if (bc12_type == CHARGE_SUPPLIER_NONE) - goto bc12_none; - if (IS_ENABLED(CONFIG_WIRELESS_CHARGER_P9221_R7) && - bc12_type == CHARGE_SUPPLIER_BC12_SDP && - wpc_chip_is_online()) { - p9221_notify_vbus_change(1); - CPRINTS("WPC ON"); - } - if (bc12_type == CHARGE_SUPPLIER_BC12_SDP && - ++bc12_cnt < max_bc12_cnt) { - /* - * defer the workaround and awaiting for - * waken up by the interrupt. - */ - hook_call_deferred( - &rt946x_bc12_workaround_data, 5); - goto wait_event; - } - - charge_manager_update_charge(bc12_type, 0, &chg); -bc12_none: - rt946x_enable_bc12_detection(CHARGER_SOLO, 0); - } - - /* VBUS detach event */ - if (reg & RT946X_MASK_DPDMIRQ_DETACH && - bc12_type != CHARGE_SUPPLIER_NONE) { - CPRINTS("VBUS detached"); - bc12_cnt = 0; -#ifdef CONFIG_WIRELESS_CHARGER_P9221_R7 - p9221_notify_vbus_change(0); -#endif - charge_manager_update_charge(bc12_type, 0, NULL); - } - -wait_event: - task_wait_event(-1); - } -} - -static int rt946x_ramp_allowed(int supplier) -{ - return supplier == CHARGE_SUPPLIER_BC12_DCP; -} - -static int rt946x_ramp_max(int supplier, int sup_curr) -{ - return rt946x_get_bc12_ilim(supplier); -} -#endif /* HAS_TASK_USB_CHG */ - -/* Non-standard interface functions */ - -int rt946x_enable_charger_boost(int en) -{ - return (en ? rt946x_set_bit : rt946x_clr_bit) - (CHARGER_SOLO, RT946X_REG_CHGCTRL2, RT946X_MASK_CHG_EN); -} - -/* - * rt946x reports VBUS ready after VBUS is up for ~500ms. - * Check if this works for the use case before calling this function. - */ -int rt946x_is_vbus_ready(void) -{ - int val = 0; - - return rt946x_read8(CHARGER_SOLO, RT946X_REG_CHGSTATC, &val) ? - 0 : !!(val & RT946X_MASK_PWR_RDY); -} - -int rt946x_is_charge_done(void) -{ - int val = 0; - - if (rt946x_read8(CHARGER_SOLO, RT946X_REG_CHGSTAT, &val)) - return 0; - - val = (val & RT946X_MASK_CHG_STAT) >> RT946X_SHIFT_CHG_STAT; - - return val == RT946X_CHGSTAT_DONE; -} - -int rt946x_cutoff_battery(void) -{ -#ifdef CONFIG_CHARGER_MT6370 -/* - * We should lock ADC usage to prevent from using ADC while - * cut-off. Or this might cause the ADC power not turning off. - */ - - int rv; - - mutex_lock(&adc_access_lock); - rv = rt946x_write8(CHARGER_SOLO, MT6370_REG_RSTPASCODE1, - MT6370_MASK_RSTPASCODE1); - if (rv) - goto out; - - rv = rt946x_write8(CHARGER_SOLO, MT6370_REG_RSTPASCODE2, - MT6370_MASK_RSTPASCODE2); - if (rv) - goto out; - - /* reset all chg/fled/ldo/rgb/bl/db reg and logic */ - rv = rt946x_write8(CHARGER_SOLO, RT946X_REG_CORECTRL2, 0x7F); - if (rv) - goto out; - - /* disable chg auto sensing */ - mt6370_enable_hidden_mode(CHARGER_SOLO, 1); - rv = rt946x_clr_bit(CHARGER_SOLO, MT6370_REG_CHGHIDDENCTRL15, - MT6370_MASK_ADC_TS_AUTO); - mt6370_enable_hidden_mode(CHARGER_SOLO, 0); - if (rv) - goto out; - msleep(50); - /* enter shipping mode */ - rv = rt946x_set_bit(CHARGER_SOLO, RT946X_REG_CHGCTRL2, - RT946X_MASK_SHIP_MODE); - -out: - mutex_unlock(&adc_access_lock); - return rv; -#endif - /* enter shipping mode */ - return rt946x_set_bit(CHARGER_SOLO, RT946X_REG_CHGCTRL2, - RT946X_MASK_SHIP_MODE); -} - -int rt946x_enable_charge_termination(int en) -{ - return (en ? rt946x_set_bit : rt946x_clr_bit) - (CHARGER_SOLO, RT946X_REG_CHGCTRL2, RT946X_MASK_TE); -} - -int rt946x_enable_charge_eoc(int en) -{ - return (en ? rt946x_set_bit : rt946x_clr_bit) - (CHARGER_SOLO, RT946X_REG_CHGCTRL9, RT946X_MASK_EOC); -} - -#ifdef CONFIG_CHARGER_MT6370 -/* MT6370 LDO */ - -int mt6370_set_ldo_voltage(int mv) -{ - int rv; - int vout_val; - const int vout_mask = MT6370_MASK_LDOVOUT_EN | MT6370_MASK_LDOVOUT_VOUT; - - /* LDO output-off mode to floating. */ - rv = rt946x_update_bits(CHARGER_SOLO, MT6370_REG_LDOCFG, - MT6370_MASK_LDOCFG_OMS, 0); - if (rv) - return rv; - - /* Disable LDO if voltage is zero. */ - if (mv == 0) - return rt946x_clr_bit(CHARGER_SOLO, MT6370_REG_LDOVOUT, - MT6370_MASK_LDOVOUT_EN); - - vout_val = 1 << MT6370_SHIFT_LDOVOUT_EN; - vout_val |= rt946x_closest_reg(MT6370_LDO_MIN, MT6370_LDO_MAX, - MT6370_LDO_STEP, mv); - return rt946x_update_bits(CHARGER_SOLO, MT6370_REG_LDOVOUT, vout_mask, - vout_val); -} - -/* MT6370 Display bias */ -int mt6370_db_external_control(int en) -{ - return rt946x_update_bits(CHARGER_SOLO, MT6370_REG_DBCTRL1, - MT6370_MASK_DB_EXT_EN, - en << MT6370_SHIFT_DB_EXT_EN); -} - -int mt6370_db_set_voltages(int vbst, int vpos, int vneg) -{ - int rv; - - /* set display bias VBST */ - rv = rt946x_update_bits(CHARGER_SOLO, MT6370_REG_DBVBST, - MT6370_MASK_DB_VBST, - rt946x_closest_reg(MT6370_DB_VBST_MIN, - MT6370_DB_VBST_MAX, - MT6370_DB_VBST_STEP, vbst)); - - /* set display bias VPOS */ - rv |= rt946x_update_bits(CHARGER_SOLO, MT6370_REG_DBVPOS, - MT6370_MASK_DB_VPOS, - rt946x_closest_reg(MT6370_DB_VPOS_MIN, - MT6370_DB_VPOS_MAX, - MT6370_DB_VPOS_STEP, vpos)); - - /* set display bias VNEG */ - rv |= rt946x_update_bits(CHARGER_SOLO, MT6370_REG_DBVNEG, - MT6370_MASK_DB_VNEG, - rt946x_closest_reg(MT6370_DB_VNEG_MIN, - MT6370_DB_VNEG_MAX, - MT6370_DB_VNEG_STEP, vneg)); - - /* Enable VNEG/VPOS discharge when VNEG/VPOS rails disabled. */ - rv |= rt946x_update_bits(CHARGER_SOLO, - MT6370_REG_DBCTRL2, - MT6370_MASK_DB_VNEG_DISC | MT6370_MASK_DB_VPOS_DISC, - MT6370_MASK_DB_VNEG_DISC | MT6370_MASK_DB_VPOS_DISC); - - return rv; -} - -/* MT6370 BACKLIGHT LED */ - -int mt6370_backlight_set_dim(uint16_t dim) -{ - int rv; - - /* datasheet suggests that update BLDIM2 first then BLDIM */ - rv = rt946x_write8(CHARGER_SOLO, MT6370_BACKLIGHT_BLDIM2, - dim & MT6370_MASK_BLDIM2); - - if (rv) - return rv; - - rv = rt946x_write8(CHARGER_SOLO, MT6370_BACKLIGHT_BLDIM, - (dim >> MT6370_SHIFT_BLDIM_MSB) & MT6370_MASK_BLDIM); - - return rv; -} - -/* MT6370 RGB LED */ - -int mt6370_led_set_dim_mode(enum mt6370_led_index index, - enum mt6370_led_dim_mode mode) -{ - if (index <= MT6370_LED_ID_OFF || index >= MT6370_LED_ID_COUNT) - return EC_ERROR_INVAL; - - rt946x_update_bits(CHARGER_SOLO, MT6370_REG_RGBDIM_BASE + index, - MT6370_MASK_RGB_DIMMODE, - mode << MT6370_SHIFT_RGB_DIMMODE); - return EC_SUCCESS; -} - -int mt6370_led_set_color(uint8_t mask) -{ - return rt946x_update_bits(CHARGER_SOLO, MT6370_REG_RGBEN, - MT6370_MASK_RGB_ISNK_ALL_EN, mask); -} - -int mt6370_led_set_brightness(enum mt6370_led_index index, uint8_t brightness) -{ - if (index >= MT6370_LED_ID_COUNT || index <= MT6370_LED_ID_OFF) - return EC_ERROR_INVAL; - - rt946x_update_bits(CHARGER_SOLO, MT6370_REG_RGBISNK_BASE + index, - MT6370_MASK_RGBISNK_CURSEL, - brightness << MT6370_SHIFT_RGBISNK_CURSEL); - return EC_SUCCESS; -} - -int mt6370_led_set_pwm_dim_duty(enum mt6370_led_index index, uint8_t dim_duty) -{ - if (index >= MT6370_LED_ID_COUNT || index <= MT6370_LED_ID_OFF) - return EC_ERROR_INVAL; - - rt946x_update_bits(CHARGER_SOLO, MT6370_REG_RGBDIM_BASE + index, - MT6370_MASK_RGB_DIMDUTY, - dim_duty << MT6370_SHIFT_RGB_DIMDUTY); - return EC_SUCCESS; -} - -int mt6370_led_set_pwm_frequency(enum mt6370_led_index index, - enum mt6370_led_pwm_freq freq) -{ - if (index >= MT6370_LED_ID_COUNT || index <= MT6370_LED_ID_OFF) - return EC_ERROR_INVAL; - - rt946x_update_bits(CHARGER_SOLO, MT6370_REG_RGBISNK_BASE + index, - MT6370_MASK_RGBISNK_DIMFSEL, - freq << MT6370_SHIFT_RGBISNK_DIMFSEL); - return EC_SUCCESS; -} - -int mt6370_reduce_db_bl_driving(void) -{ - int rv; - - /* Enter test mode */ - rv = rt946x_block_write(CHARGER_SOLO, MT6370_REG_TM_PAS_CODE1, - mt6370_val_en_test_mode, - ARRAY_SIZE(mt6370_val_en_test_mode)); - if (rv) - return rv; - msleep(1); - rv = rt946x_write8(CHARGER_SOLO, MT6370_REG_BANK, MT6370_MASK_REG_TM); - if (rv) - return rv; - msleep(1); - /* reduce bl driving */ - rv = rt946x_update_bits(CHARGER_SOLO, MT6370_TM_REG_BL3, - MT6370_TM_MASK_BL3_SL, MT6370_TM_REDUCE_BL3_SL); - if (rv) - return rv; - msleep(1); - /* reduce db driving */ - rv = rt946x_update_bits(CHARGER_SOLO, MT6370_TM_REG_DSV1, - MT6370_TM_MASK_DSV1_SL, - MT6370_TM_REDUCE_DSV1_SL); - if (rv) - return rv; - msleep(1); - /* Leave test mode */ - return rt946x_write8(CHARGER_SOLO, MT6370_REG_TM_PAS_CODE1, - MT6370_LEAVE_TM); -} -#endif /* CONFIG_CHARGER_MT6370 */ - -const struct charger_drv rt946x_drv = { - .init = &rt946x_init, - .post_init = &rt946x_post_init, - .get_info = &rt946x_get_info, - .get_status = &rt946x_get_status, - .set_mode = &rt946x_set_mode, - .enable_otg_power = &rt946x_enable_otg_power, - .is_sourcing_otg_power = &rt946x_is_sourcing_otg_power, - .get_current = &rt946x_get_current, - .set_current = &rt946x_set_current, - .get_voltage = &rt946x_get_voltage, - .set_voltage = &rt946x_set_voltage, - .discharge_on_ac = &rt946x_discharge_on_ac, - .get_vbus_voltage = &rt946x_get_vbus_voltage, - .set_input_current_limit = &rt946x_set_input_current_limit, - .get_input_current_limit = &rt946x_get_input_current_limit, - .manufacturer_id = &rt946x_manufacturer_id, - .device_id = &rt946x_device_id, - .get_option = &rt946x_get_option, - .set_option = &rt946x_set_option, -#ifdef CONFIG_CHARGE_RAMP_HW - .set_hw_ramp = &rt946x_set_hw_ramp, - .ramp_is_stable = &rt946x_ramp_is_stable, - .ramp_is_detected = &rt946x_ramp_is_detected, - .ramp_get_current_limit = &rt946x_ramp_get_current_limit, -#endif -}; - -#ifdef HAS_TASK_USB_CHG -const struct bc12_drv rt946x_bc12_drv = { - .usb_charger_task = rt946x_usb_charger_task, - .ramp_allowed = rt946x_ramp_allowed, - .ramp_max = rt946x_ramp_max, -}; - -#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 = &rt946x_bc12_drv, - }, -}; -#endif /* CONFIG_BC12_SINGLE_DRIVER */ -#endif diff --git a/driver/charger/rt946x.h b/driver/charger/rt946x.h deleted file mode 100644 index 5e6f9e0223..0000000000 --- a/driver/charger/rt946x.h +++ /dev/null @@ -1,853 +0,0 @@ -/* Copyright 2017 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. - * - * Richtek rt9466/rt9467, Mediatek mt6370 battery charger driver. - */ - -#ifndef __CROS_EC_RT946X_H -#define __CROS_EC_RT946X_H - -/* Registers for rt9466, rt9467 */ -#if defined(CONFIG_CHARGER_RT9466) || defined(CONFIG_CHARGER_RT9467) -#define RT946X_REG_CORECTRL0 0x00 -#define RT946X_REG_CORECTRL_RST RT946X_REG_CORECTRL0 -#define RT946X_REG_CHGCTRL1 0x01 -#define RT946X_REG_CHGCTRL2 0x02 -#define RT946X_REG_CHGCTRL3 0x03 -#define RT946X_REG_CHGCTRL4 0x04 -#define RT946X_REG_CHGCTRL5 0x05 -#define RT946X_REG_CHGCTRL6 0x06 -#define RT946X_REG_CHGCTRL7 0x07 -#define RT946X_REG_CHGCTRL8 0x08 -#define RT946X_REG_CHGCTRL9 0x09 -#define RT946X_REG_CHGCTRL10 0x0A -#define RT946X_REG_CHGCTRL11 0x0B -#define RT946X_REG_CHGCTRL12 0x0C -#define RT946X_REG_CHGCTRL13 0x0D -#define RT946X_REG_CHGCTRL14 0x0E -#define RT946X_REG_CHGCTRL15 0x0F -#define RT946X_REG_CHGCTRL16 0x10 -#define RT946X_REG_CHGADC 0x11 - -#ifdef CONFIG_CHARGER_RT9467 -#define RT946X_REG_DPDM1 0x12 -#define RT946X_REG_DPDM2 0x13 -#define RT946X_REG_DPDM3 0x14 -#endif - -#define RT946X_REG_CHGCTRL19 0x18 -#define RT946X_REG_CHGCTRL17 0x19 -#define RT946X_REG_CHGCTRL18 0x1A -#define RT946X_REG_CHGHIDDENCTRL2 0x21 -#define RT946X_REG_CHGHIDDENCTRL4 0x23 -#define RT946X_REG_CHGHIDDENCTRL6 0x25 -#define RT946X_REG_CHGHIDDENCTRL7 0x26 -#define RT946X_REG_CHGHIDDENCTRL8 0x27 -#define RT946X_REG_CHGHIDDENCTRL9 0x28 -#define RT946X_REG_CHGHIDDENCTRL15 0x2E -#define RT946X_REG_DEVICEID 0x40 -#define RT946X_REG_CHGSTAT 0x42 -#define RT946X_REG_CHGNTC 0x43 -#define RT946X_REG_ADCDATAH 0x44 -#define RT946X_REG_ADCDATAL 0x45 -#define RT946X_REG_CHGSTATC 0x50 -#define RT946X_REG_CHGFAULT 0x51 -#define RT946X_REG_TSSTATC 0x52 -#define RT946X_REG_CHGIRQ1 0x53 -#define RT946X_REG_CHGIRQ2 0x54 -#define RT946X_REG_CHGIRQ3 0x55 - -#ifdef CONFIG_CHARGER_RT9467 -#define RT946X_REG_DPDMIRQ 0x56 -#endif - -#define RT946X_REG_CHGSTATCCTRL 0x60 -#define RT946X_REG_CHGFAULTCTRL 0x61 -#define RT946X_REG_TSSTATCCTRL 0x62 -#define RT946X_REG_CHGIRQ1CTRL 0x63 -#define RT946X_REG_CHGIRQ2CTRL 0x64 -#define RT946X_REG_CHGIRQ3CTRL 0x65 - -#ifdef CONFIG_CHARGER_RT9467 -#define RT946X_REG_DPDMIRQCTRL 0x66 -#endif - -#elif defined(CONFIG_CHARGER_MT6370) -/* Registers for mt6370 */ -#define RT946X_REG_DEVICEID 0x00 -#define RT946X_REG_CORECTRL1 0x01 -#define RT946X_REG_CORECTRL2 0x02 -#define RT946X_REG_CORECTRL_RST RT946X_REG_CORECTRL2 -#define MT6370_REG_RSTPASCODE1 0x03 -#define MT6370_REG_RSTPASCODE2 0x04 -#define MT6370_REG_HIDDENPASCODE1 0x07 -#define MT6370_REG_HIDDENPASCODE2 0x08 -#define MT6370_REG_HIDDENPASCODE3 0x09 -#define MT6370_REG_HIDDENPASCODE4 0x0A -#define MT6370_REG_IRQIND 0x0B -#define MT6370_REG_IRQMASK 0x0C -#define MT6370_REG_OSCCTRL 0x10 -#define RT946X_REG_CHGCTRL1 0x11 -#define RT946X_REG_CHGCTRL2 0x12 -#define RT946X_REG_CHGCTRL3 0x13 -#define RT946X_REG_CHGCTRL4 0x14 -#define RT946X_REG_CHGCTRL5 0x15 -#define RT946X_REG_CHGCTRL6 0x16 -#define RT946X_REG_CHGCTRL7 0x17 -#define RT946X_REG_CHGCTRL8 0x18 -#define RT946X_REG_CHGCTRL9 0x19 -#define RT946X_REG_CHGCTRL10 0x1A -#define RT946X_REG_CHGCTRL11 0x1B -#define RT946X_REG_CHGCTRL12 0x1C -#define RT946X_REG_CHGCTRL13 0x1D -#define RT946X_REG_CHGCTRL14 0x1E -#define RT946X_REG_CHGCTRL15 0x1F -#define RT946X_REG_CHGCTRL16 0x20 -#define RT946X_REG_CHGADC 0x21 -#define MT6370_REG_DEVICETYPE 0x22 -#define RT946X_REG_DPDM1 MT6370_REG_DEVICETYPE -#define MT6370_REG_USBSTATUS1 0x27 -#define MT6370_REG_QCSTATUS2 0x29 -#define RT946X_REG_CHGCTRL17 0X2B -#define RT946X_REG_CHGCTRL18 0X2C -#define RT946X_REG_CHGHIDDENCTRL7 0x36 -#define MT6370_REG_CHGHIDDENCTRL15 0x3E -#define RT946X_REG_CHGSTAT 0X4A -#define RT946X_REG_CHGNTC 0X4B -#define RT946X_REG_ADCDATAH 0X4C -#define RT946X_REG_ADCDATAL 0X4D -/* FLED */ -#define MT6370_REG_FLEDEN 0x7E -/* LDO */ -#define MT6370_REG_LDOCFG 0X80 -#define MT6370_REG_LDOVOUT 0X81 -/* RGB led */ -#define MT6370_REG_RGBDIM_BASE 0x81 -#define MT6370_REG_RGB1DIM 0x82 -#define MT6370_REG_RGB2DIM 0x83 -#define MT6370_REG_RGB3DIM 0x84 -#define MT6370_REG_RGBEN 0x85 -#define MT6370_REG_RGBISNK_BASE 0x85 -#define MT6370_REG_RGB1ISNK 0x86 -#define MT6370_REG_RGB2ISNK 0x87 -#define MT6370_REG_RGB3ISNK 0x88 -#define MT6370_REG_RGBCHRINDDIM 0x92 -#define MT6370_REG_RGBCHRINDCTRL 0x93 - -/* backlight */ -#define MT6370_BACKLIGHT_BLEN 0xA0 -#define MT6370_BACKLIGHT_BLPWM 0xA2 -#define MT6370_BACKLIGHT_BLDIM2 0xA4 -#define MT6370_BACKLIGHT_BLDIM 0xA5 - -/* Display bias */ -#define MT6370_REG_DBCTRL1 0XB0 -#define MT6370_REG_DBCTRL2 0XB1 -#define MT6370_REG_DBVBST 0XB2 -#define MT6370_REG_DBVPOS 0XB3 -#define MT6370_REG_DBVNEG 0XB4 -#define MT6370_REG_CHGIRQ1 0xC0 -#define RT946X_REG_DPDMIRQ 0xC6 - -/* status event */ -#define MT6370_REG_CHGSTAT1 0xD0 -#define RT946X_REG_CHGSTATC MT6370_REG_CHGSTAT1 -#define MT6370_REG_CHGSTAT2 0xD1 -#define RT946X_REG_CHGFAULT MT6370_REG_CHGSTAT2 -#define MT6370_REG_CHGSTAT3 0xD2 -#define MT6370_REG_CHGSTAT4 0xD3 -#define MT6370_REG_CHGSTAT5 0xD4 -#define MT6370_REG_CHGSTAT6 0xD5 -#define MT6370_REG_DPDMSTAT 0xD6 -#define MT6370_REG_DICHGSTAT 0xD7 -#define MT6370_REG_OVPCTRLSTAT 0xD8 -#define MT6370_REG_FLEDSTAT1 0xD9 -#define MT6370_REG_FLEDSTAT2 0xDA -#define MT6370_REG_BASESTAT 0xDB -#define MT6370_REG_LDOSTAT 0xDC -#define MT6370_REG_RGBSTAT 0xDD -#define MT6370_REG_BLSTAT 0xDE -#define MT6370_REG_DBSTAT 0xDF -/* irq mask */ -#define MT6370_REG_CHGMASK1 0xE0 -#define RT946X_REG_CHGSTATCCTRL MT6370_REG_CHGMASK1 -#define MT6370_REG_CHGMASK2 0xE1 -#define MT6370_REG_CHGMASK3 0xE2 -#define MT6370_REG_CHGMASK4 0xE3 -#define MT6370_REG_CHGMASK5 0xE4 -#define MT6370_REG_CHGMASK6 0xE5 -#define MT6370_REG_DPDMMASK1 0xE6 -#define MT6370_REG_DICHGMASK 0xE7 -#define MT6370_REG_OVPCTRLMASK 0xE8 -#define MT6370_REG_FLEDMASK1 0xE9 -#define MT6370_REG_FLEDMASK2 0xEA -#define MT6370_REG_BASEMASK 0xEB -#define MT6370_REG_LDOMASK 0xEC -#define MT6370_REG_RGBMASK 0xED -#define MT6370_REG_BLMASK 0xEE -#define MT6370_REG_DBMASK 0xEF -#define MT6370_REG_TM_PAS_CODE1 0xF0 -#define MT6370_REG_BANK 0xFF -/* TM REGISTER */ -#define MT6370_TM_REG_BL3 0x34 -#define MT6370_TM_REG_DSV1 0x37 -#else -#error "No suitable charger option defined" -#endif - -/* EOC current */ -#define RT946X_IEOC_MIN 100 -#define RT946X_IEOC_MAX 850 -#define RT946X_IEOC_STEP 50 - -/* Minimum Input Voltage Regulator */ -#define RT946X_MIVR_MIN 3900 -#define RT946X_MIVR_MAX 13400 -#define RT946X_MIVR_STEP 100 - -/* Boost voltage */ -#define RT946X_BOOST_VOLTAGE_MIN 4425 -#define RT946X_BOOST_VOLTAGE_MAX 5825 -#define RT946X_BOOST_VOLTAGE_STEP 25 - -/* IR compensation resistor */ -#define RT946X_IRCMP_RES_MIN 0 -#define RT946X_IRCMP_RES_MAX 175 -#define RT946X_IRCMP_RES_STEP 25 - -/* IR compensation voltage clamp */ -#define RT946X_IRCMP_VCLAMP_MIN 0 -#define RT946X_IRCMP_VCLAMP_MAX 224 -#define RT946X_IRCMP_VCLAMP_STEP 32 - -/* Pre-charge mode threshold voltage */ -#define RT946X_VPREC_MIN 2000 -#define RT946X_VPREC_MAX 3500 -#define RT946X_VPREC_STEP 100 - -/* Pre-charge current */ -#define RT946X_IPREC_MIN 100 -#define RT946X_IPREC_MAX 850 -#define RT946X_IPREC_STEP 50 - -/* AICLVTH */ -#define RT946X_AICLVTH_MIN 4100 -#define RT946X_AICLVTH_MAX 4800 -#define RT946X_AICLVTH_STEP 100 - -/* NTC */ -#define RT946X_BATTEMP_NORMAL 0x00 -#define RT946X_BATTEMP_WARM 0x02 -#define RT946X_BATTEMP_COOL 0x03 -#define RT946X_BATTEMP_COLD 0x05 -#define RT946X_BATTEMP_HOT 0x06 - -/* LDO voltage */ -#define MT6370_LDO_MIN 1600 -#define MT6370_LDO_MAX 4000 -#define MT6370_LDO_STEP 200 - -/* ========== CORECTRL0 0x00 ============ */ -#define RT946X_SHIFT_RST 7 -#define RT946X_SHIFT_CHG_RST 6 -#define RT946X_SHIFT_FLED_RST 5 -#define RT946X_SHIFT_LDO_RST 4 -#define RT946X_SHIFT_RGB_RST 3 -#define RT946X_SHIFT_BL_RST 2 -#define RT946X_SHIFT_DB_RST 1 -#define RT946X_SHIFT_REG_RST 0 - -#define RT946X_MASK_RST BIT(RT946X_SHIFT_RST) -#define RT946X_MASK_CHG_RST BIT(RT946X_SHIFT_CHG_RST) -#define RT946X_MASK_FLED_RST BIT(RT946X_SHIFT_FLED_RST) -#define RT946X_MASK_LDO_RST BIT(RT946X_SHIFT_LDO_RST) -#define RT946X_MASK_RGB_RST BIT(RT946X_SHIFT_RGB_RST) -#define RT946X_MASK_BL_RST BIT(RT946X_SHIFT_BL_RST) -#define RT946X_MASK_DB_RST BIT(RT946X_SHIFT_DB_RST) -#define RT946X_MASK_REG_RST BIT(RT946X_SHIFT_REG_RST) -#define RT946X_MASK_SOFT_RST \ - (RT946X_MASK_CHG_RST | RT946X_MASK_FLED_RST | RT946X_MASK_LDO_RST | \ - RT946X_MASK_RGB_RST | RT946X_MASK_BL_RST | RT946X_MASK_DB_RST | \ - RT946X_MASK_REG_RST) - -/* ========== CHGCTRL1 0x01 ============ */ -#define RT946X_SHIFT_OPA_MODE 0 -#define RT946X_SHIFT_HZ_EN 2 -#define RT946X_SHIFT_STAT_EN 4 - -#define RT946X_MASK_OPA_MODE BIT(RT946X_SHIFT_OPA_MODE) -#define RT946X_MASK_HZ_EN BIT(RT946X_SHIFT_HZ_EN) -#define RT946X_MASK_STAT_EN BIT(RT946X_SHIFT_STAT_EN) - -/* ========== CHGCTRL2 0x02 ============ */ -#define RT946X_SHIFT_SHIP_MODE 7 -#define RT946X_SHIFT_TE 4 -#define RT946X_SHIFT_ILMTSEL 2 -#define RT946X_SHIFT_CFO_EN 1 -#define RT946X_SHIFT_CHG_EN 0 - -#define RT946X_MASK_SHIP_MODE BIT(RT946X_SHIFT_SHIP_MODE) -#define RT946X_MASK_TE BIT(RT946X_SHIFT_TE) -#define RT946X_MASK_ILMTSEL (0x3 << RT946X_SHIFT_ILMTSEL) -#define RT946X_MASK_CFO_EN BIT(RT946X_SHIFT_CFO_EN) -#define RT946X_MASK_CHG_EN BIT(RT946X_SHIFT_CHG_EN) - -/* ========== RSTPASCODE1 0x03 (mt6370) ============ */ -#define MT6370_MASK_RSTPASCODE1 0xA9 - -/* ========== CHGCTRL3 0x03 ============ */ -#define RT946X_SHIFT_AICR 2 -#define RT946X_SHIFT_ILIMEN 0 - -#define RT946X_MASK_AICR (0x3F << RT946X_SHIFT_AICR) -#define RT946X_MASK_ILIMEN BIT(RT946X_SHIFT_ILIMEN) - -/* - * The accuracy of AICR is 7%. So if AICR = 2150, - * then Max=2150, Typ=2000, Min=1860. And plus 25 since the AICR - * is 50ma a step. - */ -#define RT946X_AICR_TYP2MAX(x) ((x) * 107 / 100 + 25) - -/* ========== RSTPASCODE2 0x04 (mt6370) ============ */ -#define MT6370_MASK_RSTPASCODE2 0x96 - -/* ========== CHGCTRL4 0x04 ============ */ -#define RT946X_SHIFT_CV 1 - -#define RT946X_MASK_CV 0xFE - -/* ========== CHGCTRL5 0x05 ============ */ -#define RT946X_SHIFT_BOOST_VOLTAGE 2 - -#define RT946X_MASK_BOOST_VOLTAGE 0xFC - -/* ========== CHGCTRL6 0x06 ============ */ -#define RT946X_SHIFT_MIVR 1 - -#define RT946X_MASK_MIVR (0x7F << RT946X_SHIFT_MIVR) - -/* ========== CHGCTRL7 0x07 ============ */ -#define RT946X_SHIFT_ICHG 2 - -#define RT946X_MASK_ICHG (0x3F << RT946X_SHIFT_ICHG) - -/* ========== CHGCTRL8 0x08 ============ */ -#define RT946X_SHIFT_VPREC 4 -#define RT946X_SHIFT_IPREC 0 - -#define RT946X_MASK_VPREC (0xF << RT946X_SHIFT_VPREC) -#define RT946X_MASK_IPREC (0xF << RT946X_SHIFT_IPREC) - -/* ========== CHGCTRL9 0x09 ============ */ -#define RT946X_SHIFT_EOC 3 -#define RT946X_SHIFT_IEOC 4 - -#define RT946X_MASK_EOC BIT(RT946X_SHIFT_EOC) -#define RT946X_MASK_IEOC (0xF << RT946X_SHIFT_IEOC) - -/* ========== CHGCTRL10 0x0A ============ */ -#define RT946X_SHIFT_BOOST_CURRENT 0 - -#define RT946X_MASK_BOOST_CURRENT 0x07 - -/* ========== CHGCTRL12 0x0C ============ */ -#define RT946X_SHIFT_TMR_EN 1 -#define MT6370_IRQ_MASK_ALL 0xFE - -#define RT946X_MASK_TMR_EN BIT(RT946X_SHIFT_TMR_EN) - -/* ========== CHGCTRL13 0x0D ============ */ -#define RT946X_SHIFT_WDT_EN 7 - -#define RT946X_MASK_WDT_EN BIT(RT946X_SHIFT_WDT_EN) - -/* ========== CHGCTRL14 0x0E ============ */ -#define RT946X_SHIFT_AICLMEAS 7 -#define RT946X_SHIFT_AICLVTH 0 - -#define RT946X_MASK_AICLMEAS BIT(RT946X_SHIFT_AICLMEAS) -#define RT946X_MASK_AICLVTH 0x07 - -/* ========== CHGCTRL16 0x10 ============ */ -#define RT946X_SHIFT_JEITA_EN 4 - -#define RT946X_MASK_JEITA_EN BIT(RT946X_SHIFT_JEITA_EN) - -/* ========== CHGADC 0x11 ============ */ -#define RT946X_SHIFT_ADC_IN_SEL 4 -#define RT946X_SHIFT_ADC_START 0 - -#define RT946X_MASK_ADC_IN_SEL (0xF << RT946X_SHIFT_ADC_IN_SEL) -#define RT946X_MASK_ADC_START BIT(RT946X_SHIFT_ADC_START) - -/* ========== CHGDPDM1 0x12 (rt946x) DEVICETYPE 0x22 (mt6370) ============ */ -#define RT946X_SHIFT_USBCHGEN 7 -#define RT946X_SHIFT_DCDTIMEOUT 6 -#define RT946X_SHIFT_DCP 2 -#define RT946X_SHIFT_CDP 1 -#define RT946X_SHIFT_SDP 0 - -#define RT946X_MASK_USBCHGEN BIT(RT946X_SHIFT_USBCHGEN) -#define RT946X_MASK_DCDTIMEOUT BIT(RT946X_SHIFT_DCDTIMEOUT) -#define RT946X_MASK_DCP BIT(RT946X_SHIFT_DCP) -#define RT946X_MASK_CDP BIT(RT946X_SHIFT_CDP) -#define RT946X_MASK_SDP BIT(RT946X_SHIFT_SDP) - -#define RT946X_MASK_BC12_TYPE (RT946X_MASK_DCP | \ - RT946X_MASK_CDP | \ - RT946X_MASK_SDP) - -/* ========== USBSTATUS1 0x27 (mt6370) ============ */ -#define MT6370_SHIFT_DCD_TIMEOUT 2 -#define MT6370_SHIFT_USB_STATUS 4 - -#define MT6370_MASK_USB_STATUS 0x70 - -#define MT6370_CHG_TYPE_NOVBUS 0 -#define MT6370_CHG_TYPE_BUSY 1 -#define MT6370_CHG_TYPE_SDP 2 -#define MT6370_CHG_TYPE_SDPNSTD 3 -#define MT6370_CHG_TYPE_DCP 4 -#define MT6370_CHG_TYPE_CDP 5 -#define MT6370_CHG_TYPE_SAMSUNG_CHARGER 6 -#define MT6370_CHG_TYPE_APPLE_0_5A_CHARGER 7 -#define MT6370_CHG_TYPE_APPLE_1_0A_CHARGER 8 -#define MT6370_CHG_TYPE_APPLE_2_1A_CHARGER 9 -#define MT6370_CHG_TYPE_APPLE_2_4A_CHARGER 10 - -#define MT6370_MASK_DCD_TIMEOUT BIT(MT6370_SHIFT_DCD_TIMEOUT) - -/* ========== QCSTATUS2 0x29 (mt6370) ============ */ -#define MT6370_SHIFT_APP_OUT 5 -#define MT6370_SHIFT_SS_OUT 4 -#define MT6370_SHIFT_APP_REF 3 -#define MT6370_SHIFT_APP_DPDM_IN 2 -#define MT6370_SHIFT_APP_SS_PL 1 -#define MT6370_SHIFT_APP_SS_EN 0 - -#define MT6370_MASK_APP_OUT BIT(MT6370_SHIFT_APP_OUT) -#define MT6370_MASK_SS_OUT BIT(MT6370_SHIFT_SS_OUT) -#define MT6370_MASK_APP_REF BIT(MT6370_SHIFT_APP_REF) -#define MT6370_MASK_APP_DPDM_IN BIT(MT6370_SHIFT_APP_DPDM_IN) -#define MT6370_MASK_APP_SS_PL BIT(MT6370_SHIFT_APP_SS_PL) -#define MT6370_MASK_APP_SS_EN BIT(MT6370_SHIFT_APP_SS_EN) - -#define MT6360_MASK_CHECK_DPDM (MT6370_MASK_APP_SS_EN | \ - MT6370_MASK_APP_SS_PL | \ - MT6370_MASK_APP_DPDM_IN | \ - MT6370_MASK_APP_REF) - -/* ========= CHGHIDDENCTRL7 0x36 (mt6370) ======== */ -#define RT946X_ENABLE_VSYS_PROTECT 0x40 - -#define RT946X_SHIFT_HIDDENCTRL7_VSYS_PROTECT 5 -#define RT946X_MASK_HIDDENCTRL7_VSYS_PROTECT \ - (0x3 << RT946X_SHIFT_HIDDENCTRL7_VSYS_PROTECT) - -/* ========== CHGCTRL18 0x1A ============ */ -#define RT946X_SHIFT_IRCMP_RES 3 -#define RT946X_SHIFT_IRCMP_VCLAMP 0 - -#define RT946X_MASK_IRCMP_RES (0x7 << RT946X_SHIFT_IRCMP_RES) -#define RT946X_MASK_IRCMP_VCLAMP (0x7 << RT946X_SHIFT_IRCMP_VCLAMP) - -/* ========== HIDDEN CTRL15 0x3E ============ */ -#define MT6370_SHIFT_ADC_TS_AUTO 0 -#define MT6370_MASK_ADC_TS_AUTO BIT(MT6370_SHIFT_ADC_TS_AUTO) - -/* ========== DEVICE_ID 0x40 ============ */ -#define RT946X_MASK_VENDOR_ID 0xF0 -#define RT946X_MASK_CHIP_REV 0x0F - -/* ========== CHGSTAT 0x42 ============ */ -#define RT946X_SHIFT_CHG_STAT 6 -#define RT946X_SHIFT_ADC_STAT 0 - -#define RT946X_MASK_CHG_STAT (0x3 << RT946X_SHIFT_CHG_STAT) -#define RT946X_MASK_ADC_STAT BIT(RT946X_SHIFT_ADC_STAT) - -/* ========== CHGNTC 0x43 ============ */ -#define RT946X_SHIFT_BATNTC_FAULT 4 - -#define RT946X_MASK_BATNTC_FAULT 0x70 - -/* ========== CHGSTATC 0x50 (rt946x) ============ */ -#define RT946X_SHIFT_PWR_RDY 7 - -#define RT946X_MASK_PWR_RDY BIT(RT946X_SHIFT_PWR_RDY) - -/* ========== CHGFAULT 0x51 (rt946x) ============ */ -#if defined(CONFIG_CHARGER_RT9466) || defined(CONFIG_CHARGER_RT9467) -#define RT946X_SHIFT_CHG_VSYSUV 4 -#define RT946X_SHIFT_CHG_VSYSOV 5 -#define RT946X_SHIFT_CHG_VBATOV 6 -#define RT946X_SHIFT_CHG_VBUSOV 7 - -#define RT946X_MASK_CHG_VSYSUV BIT(RT946X_SHIFT_CHG_VSYSUV) -#define RT946X_MASK_CHG_VSYSOV BIT(RT946X_SHIFT_CHG_VSYSOV) -#define RT946X_MASK_CHG_VBATOV BIT(RT946X_SHIFT_CHG_VBATOV) -#define RT946X_MASK_CHG_VBUSOV BIT(RT946X_SHIFT_CHG_VBUSOV) -#endif - -/* ========== DPDMIRQ 0x56 ============ */ -#if defined(CONFIG_CHARGER_RT9467) || defined(CONFIG_CHARGER_MT6370) -#define RT946X_SHIFT_DPDMIRQ_DETACH 1 -#define RT946X_SHIFT_DPDMIRQ_ATTACH 0 - -#define RT946X_MASK_DPDMIRQ_DETACH BIT(RT946X_SHIFT_DPDMIRQ_DETACH) -#define RT946X_MASK_DPDMIRQ_ATTACH BIT(RT946X_SHIFT_DPDMIRQ_ATTACH) -#endif - -/* ========== FLED EN 0x7E (mt6370) ============ */ -#define MT6370_STROBE_EN_MASK 0x04 - -/* ========== LDOCFG 0x80 (mt6370) ============ */ -#define MT6370_SHIFT_LDOCFG_OMS 6 - -#define MT6370_MASK_LDOCFG_OMS BIT(MT6370_SHIFT_LDOCFG_OMS) - -/* ========== LDOVOUT 0x81 (mt6370) ============ */ -#define MT6370_SHIFT_LDOVOUT_EN 7 -#define MT6370_SHIFT_LDOVOUT_VOUT 0 - -#define MT6370_MASK_LDOVOUT_EN BIT(MT6370_SHIFT_LDOVOUT_EN) -#define MT6370_MASK_LDOVOUT_VOUT (0xf << MT6370_SHIFT_LDOVOUT_VOUT) - -/* ========== RGBDIM 0x82/0x83/0x84 (mt6370) ============ */ -#define MT6370_LED_PWM_DIMDUTY_MIN 0x00 -#define MT6370_LED_PWM_DIMDUTY_MAX 0x1f - -#define MT6370_SHIFT_RGB_DIMMODE 5 -#define MT6370_SHIFT_RGB_DIMDUTY 0 - -#define MT6370_MASK_RGB_DIMMODE (3 << MT6370_SHIFT_RGB_DIMMODE) -#define MT6370_MASK_RGB_DIMDUTY (0x1f << MT6370_SHIFT_RGB_DIMDUTY) - -/* ========== RGBEN 0x85 (mt6370) ============ */ -#define MT6370_SHIFT_RGB_ISNK1DIM 7 -#define MT6370_SHIFT_RGB_ISNK2DIM 6 -#define MT6370_SHIFT_RGB_ISNK3DIM 5 -#define MT6370_SHIFT_RGB_ISNKDIM_BASE 8 - -#define MT6370_MASK_RGB_ISNK1DIM_EN BIT(MT6370_SHIFT_RGB_ISNK1DIM) -#define MT6370_MASK_RGB_ISNK2DIM_EN BIT(MT6370_SHIFT_RGB_ISNK2DIM) -#define MT6370_MASK_RGB_ISNK3DIM_EN BIT(MT6370_SHIFT_RGB_ISNK3DIM) -#define MT6370_MASK_RGB_ISNK_ALL_EN (MT6370_MASK_RGB_ISNK1DIM_EN | \ - MT6370_MASK_RGB_ISNK2DIM_EN | \ - MT6370_MASK_RGB_ISNK3DIM_EN) - -/* ========== RGB_ISNK 0x86/0x87/0x88 (mt6370) ============ */ -#define MT6370_LED_BRIGHTNESS_MIN 0 -#define MT6370_LED_BRIGHTNESS_MAX 7 - -#define MT6370_SHIFT_RGBISNK_CURSEL 0 -#define MT6370_SHIFT_RGBISNK_DIMFSEL 3 -#define MT6370_MASK_RGBISNK_CURSEL (0x7 << MT6370_SHIFT_RGBISNK_CURSEL) -#define MT6370_MASK_RGBISNK_DIMFSEL (0x7 << MT6370_SHIFT_RGBISNK_DIMFSEL) - -/* ========== DBCTRL1 (mt6370) ============ */ -#define MT6370_SHIFT_DB_EXT_EN 0 -#define MT6370_SHIFT_DB_PERIODIC_FIX 4 -#define MT6370_SHIFT_DB_SINGLE_PIN 5 -#define MT6370_SHIFT_DB_FREQ_PM 6 -#define MT6370_SHIFT_DB_PERIODIC_MODE 7 - -#define MT6370_MASK_DB_EXT_EN 1 -#define MT6370_MASK_DB_PERIODIC_FIX 1 -#define MT6370_MASK_DB_SINGLE_PIN 1 -#define MT6370_MASK_DB_FREQ_PM 1 -#define MT6370_MASK_DB_PERIODIC_MODE 1 - -/* ========== DBCTRL1 (mt6370) ============ */ -#define MT6370_MASK_DB_VNEG_DISC BIT(2) -#define MT6370_MASK_DB_VPOS_DISC BIT(5) - -/* ========== DBVBST (mt6370) ============ */ -#define MT6370_SHIFT_DB_VBST 0 - -#define MT6370_MASK_DB_VBST 0x3f - -#define MT6370_DB_VBST_MAX 6200 -#define MT6370_DB_VBST_MIN 4000 -#define MT6370_DB_VBST_STEP 50 - -/* ========== DBVPOS (mt6370) ============ */ -#define MT6370_SHIFT_DB_VPOS 0 - -#define MT6370_MASK_DB_VPOS 0x3f - -#define MT6370_DB_VPOS_MAX 6000 -#define MT6370_DB_VPOS_MIN 4000 -#define MT6370_DB_VPOS_STEP 50 - -/* ========== DBVNEG (mt6370) ============ */ -#define MT6370_SHIFT_DB_VNEG 0 - -#define MT6370_MASK_DB_VNEG 0x3f - -#define MT6370_DB_VNEG_MAX 6000 -#define MT6370_DB_VNEG_MIN 4000 -#define MT6370_DB_VNEG_STEP 50 - -/* ========== BLEN 0xA0 (mt6370) ============ */ -#define MT6370_SHIFT_BLED_EXT_EN 7 -#define MT6370_SHIFT_BLED_EN 6 -#define MT6370_SHIFT_BLED_1CH_EN 5 -#define MT6370_SHIFT_BLED_2CH_EN 4 -#define MT6370_SHIFT_BLED_3CH_EN 3 -#define MT6370_SHIFT_BLED_4CH_EN 2 -#define MT6370_SHIFT_BLED_CODE 1 -#define MT6370_SHIFT_BLED_CONFIG 0 - -#define MT6370_MASK_BLED_EXT_EN BIT(MT6370_SHIFT_BLED_EXT_EN) -#define MT6370_MASK_BLED_EN BIT(MT6370_SHIFT_BLED_EN) -#define MT6370_MASK_BLED_1CH_EN BIT(MT6370_SHIFT_BLED_1CH_EN) -#define MT6370_MASK_BLED_2CH_EN BIT(MT6370_SHIFT_BLED_2CH_EN) -#define MT6370_MASK_BLED_3CH_EN BIT(MT6370_SHIFT_BLED_3CH_EN) -#define MT6370_MASK_BLED_4CH_EN BIT(MT6370_SHIFT_BLED_4CH_EN) - -#define MT6370_BLED_CODE_LINEAR BIT(MT6370_SHIFT_BLED_CODE) -#define MT6370_BLED_CODE_EXP 0 - -#define MT6370_BLED_CONFIG_ACTIVE_HIGH BIT(MT6370_SHIFT_BLED_CONFIG) -#define MT6370_BLED_CONFIG_ACTIVE_LOW 0 - -/* ========== BLPWM 0xA2 (mt6370) ============ */ -#define MT6370_SHIFT_BLPWM_BLED_PWM 7 - -#define MT6370_MASK_BLPWM_BLED_PWM BIT(MT6370_SHIFT_BLPWM_BLED_PWM) - -/* ========== BLDIM2 0xA4 (mt6370) ============ */ -#define MT6370_MASK_BLDIM2 0x7 - -/* ========== BLDIM 0xA5 (mt6370) ============ */ -#define MT6370_SHIFT_BLDIM_MSB 3 -#define MT6370_MASK_BLDIM 0xff - -#define MT6370_BLDIM_DEFAULT 0x7ff - -/* ========== CHG_IRQ1 0xC0 (mt6370) ============ */ -#define MT6370_SHIFT_MIVR_EVT 6 -#define MT6370_MASK_MIVR_EVT BIT(MT6370_SHIFT_MIVR_EVT) - -/* ========== CHGSTAT2 0xD0 (mt6370) ============ */ -#define MT6370_SHIFT_MIVR_STAT 6 - -/* ========== CHGSTAT2 0xD1 (mt6370) ============ */ -#ifdef CONFIG_CHARGER_MT6370 -#define MT6370_SHIFT_CHG_VBUSOV_STAT 7 -#define MT6370_SHIFT_CHG_VBATOV_STAT 6 - -#define RT946X_MASK_CHG_VBATOV MT6370_SHIFT_CHG_VBATOV_STAT - -#define MT6370_MASK_CHG_VBUSOV_STAT BIT(MT6370_SHIFT_CHG_VBUSOV_STAT) -#define MT6370_MASK_CHG_VBATOV_STAT BIT(MT6370_SHIFT_CHG_VBATOV_STAT) -#endif - -/* ========== TM PAS CODE1 0xF0 (mt6370) ============ */ -#define MT6370_LEAVE_TM 0x00 - -/* ========== BANK REG 0xFF (mt6370) ============ */ -#define MT6370_MASK_REG_TM 0x69 - -/* ========== TM REG 0x34 (mt6370) ============ */ -#define MT6370_TM_MASK_BL3_SL 0xC0 -#define MT6370_TM_REDUCE_BL3_SL 0xC0 - -/* ========== TM REG 0x37 (mt6370) ============ */ -#define MT6370_TM_MASK_DSV1_SL 0xC0 -#define MT6370_TM_REDUCE_DSV1_SL 0x00 - -/* ADC unit/offset */ -#define MT6370_ADC_UNIT_VBUS_DIV5 25000 /* uV */ -#define MT6370_ADC_UNIT_VBUS_DIV2 10000 /* uV */ -#define MT6370_ADC_UNIT_VSYS 5000 /* uV */ -#define MT6370_ADC_UNIT_VBAT 5000 /* uV */ -#define MT6370_ADC_UNIT_TS_BAT 25 /* 0.01% */ -#define MT6370_ADC_UNIT_IBUS 50000 /* uA */ -#define MT6370_ADC_UNIT_IBAT 50000 /* uA */ -#define MT6370_ADC_UNIT_CHG_VDDP 5000 /* uV */ -#define MT6370_ADC_UNIT_TEMP_JC 2 /* degree */ - -#define MT6370_ADC_OFFSET_VBUS_DIV5 0 /* mV */ -#define MT6370_ADC_OFFSET_VBUS_DIV2 0 /* mV */ -#define MT6370_ADC_OFFSET_VSYS 0 /* mV */ -#define MT6370_ADC_OFFSET_VBAT 0 /* mV */ -#define MT6370_ADC_OFFSET_TS_BAT 0 /* % */ -#define MT6370_ADC_OFFSET_IBUS 0 /* mA */ -#define MT6370_ADC_OFFSET_IBAT 0 /* mA */ -#define MT6370_ADC_OFFSET_CHG_VDDP 0 /* mV */ -#define MT6370_ADC_OFFSET_TEMP_JC (-40) /* degree */ - -/* ========== Variant-specific configuration ============ */ -#if defined(CONFIG_CHARGER_RT9466) - #define RT946X_CHARGER_NAME "rt9466" - #define RT946X_VENDOR_ID 0x80 - #define RT946X_ADDR_FLAGS 0x53 -#elif defined(CONFIG_CHARGER_RT9467) - #define RT946X_CHARGER_NAME "rt9467" - #define RT946X_VENDOR_ID 0x90 - #define RT946X_ADDR_FLAGS 0x5B -#elif defined(CONFIG_CHARGER_MT6370) - #define RT946X_CHARGER_NAME "mt6370" - #define RT946X_VENDOR_ID 0xE0 - #define RT946X_ADDR_FLAGS 0x34 -#else - #error "No suitable charger option defined" -#endif - -/* RT946x specific interface functions */ - -/* Power on reset */ -int rt946x_por_reset(void); - -/* Interrupt handler for rt946x */ -void rt946x_interrupt(enum gpio_signal signal); - -/* Enable/Disable rt946x (in charger or boost mode) */ -int rt946x_enable_charger_boost(int en); - -/* - * Return 1 if VBUS is ready, which means - * UVLO < VBUS < VOVP && VBUS > BATS + VSLP - */ -int rt946x_is_vbus_ready(void); - -/* Return 1 if rt946x triggers charge termination due to full charge. */ -int rt946x_is_charge_done(void); - -/* - * Cut off the battery (force BATFET to turn off). - * Return 0 if it succeeds. - */ -int rt946x_cutoff_battery(void); - -/* Enable/Disable charge temination */ -int rt946x_enable_charge_termination(int en); - -/* Enable/Disable charge EOC */ -int rt946x_enable_charge_eoc(int en); - -enum rt946x_adc_in_sel { - RT946X_ADC_VBUS_DIV5 = 1, - RT946X_ADC_VBUS_DIV2, - MT6370_ADC_TS_BAT = 6, - MT6370_ADC_IBUS = 8, - MT6370_ADC_TEMP_JC = 12, - MT6370_ADC_MAX, -}; - -/** - * Read ADC channels - * - * @param adc_sel The ADC channel - * @param adc_val The read value - * @return EC_SUCCESS or EC_ERROR_* - */ -int rt946x_get_adc(enum rt946x_adc_in_sel adc_sel, int *adc_val); - -/** - * Toggle BC12 detection - * - * @return EC_SUCCESS or EC_ERROR_* - */ -int rt946x_toggle_bc12_detection(void); - -struct rt946x_init_setting { - uint16_t eoc_current; - uint16_t mivr; - uint16_t ircmp_vclamp; - uint16_t ircmp_res; - uint16_t boost_voltage; - uint16_t boost_current; -}; - -#ifdef CONFIG_CHARGER_MT6370 - -/* - * Set LDO voltage. - * Disable LDO if voltage is zero. - */ -int mt6370_set_ldo_voltage(int mv); - -enum mt6370_led_index { - MT6370_LED_ID_OFF = 0, - MT6370_LED_ID1 = 1, - MT6370_LED_ID2 = 2, - MT6370_LED_ID3 = 3, - MT6370_LED_ID_COUNT, /* The bound of the ID indexes. */ -}; - -enum mt6370_led_dim_mode { - MT6370_LED_DIM_MODE_PWM = 0, - MT6370_LED_DIM_MODE_BREATH = 1, - MT6370_LED_DIM_MODE_REGISTER = 3 -}; - -enum mt6370_led_pwm_freq { - MT6370_LED_PWM_FREQ01 = 0, /* 0.1 Hz */ - MT6370_LED_PWM_FREQ02 = 1, /* 0.2 Hz */ - MT6370_LED_PWM_FREQ05 = 2, /* 0.5 Hz */ - MT6370_LED_PWM_FREQ1 = 3, /* 1 Hz */ - MT6370_LED_PWM_FREQ2 = 4, /* 2 Hz */ - MT6370_LED_PWM_FREQ5 = 5, /* 5 Hz */ - MT6370_LED_PWM_FREQ200 = 6, /* 200 Hz */ - MT6370_LED_PWM_FREQ1000 = 7 /* 1000 Hz */ -}; - -/* Enable display bias external pin control. */ -int mt6370_db_external_control(int en); - -/** - * Set backlight LED dim. - * - * dim: A value from 0 to 2047. - * return: EC_SUCCESS on success, and EC_ERROR_* otherwise. - */ -int mt6370_backlight_set_dim(uint16_t dim); - -/** - * MT6370 display bias voltage settings. - * - * Set disaply bias voltages for the panel. - * - * vbst: VBST config in mv. - * vpos: VPOS config in mv. - * vneg: VNEG config in mv. - * return: EC_SUCCESS on succes, and EC_ERROR_* otherwise. - */ -int mt6370_db_set_voltages(int vbst, int vpos, int vneg); - -/* Set LED brightness */ -int mt6370_led_set_brightness(enum mt6370_led_index index, uint8_t brightness); - -/** - * Set LED Color - * - * mask: Bitmap indicating 1=on 0=off for each LED. 000 = all off. - * Combination of MT6370_MASK_RGB_ISNK1/2/3DIM_EN. - * return: EC_SUCCESS or EC_ERROR_* on error. - */ -int mt6370_led_set_color(uint8_t mask); - -/* Set LED dim mode, available modes: REGISTER, PWM, BREATH. */ -int mt6370_led_set_dim_mode(enum mt6370_led_index index, - enum mt6370_led_dim_mode mode); - -/* Set LED PWM mode duty */ -int mt6370_led_set_pwm_dim_duty(enum mt6370_led_index index, uint8_t dim_duty); - -/* Set LED PWM mode frequency */ -int mt6370_led_set_pwm_frequency(enum mt6370_led_index index, - enum mt6370_led_pwm_freq freq); - -/* Reduce mt6370 DB and BL driving capacity */ -int mt6370_reduce_db_bl_driving(void); -#endif - -extern const struct charger_drv rt946x_drv; -extern const struct bc12_drv rt946x_bc12_drv; - -#endif /* __CROS_EC_RT946X_H */ diff --git a/driver/charger/sm5803.c b/driver/charger/sm5803.c deleted file mode 100644 index 460dcf4093..0000000000 --- a/driver/charger/sm5803.c +++ /dev/null @@ -1,1933 +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. - * - * Silicon Mitus SM5803 Buck-Boost Charger - */ -#include "atomic.h" -#include "battery.h" -#include "battery_smart.h" -#include "charge_state_v2.h" -#include "charger.h" -#include "extpower.h" -#include "gpio.h" -#include "hooks.h" -#include "i2c.h" -#include "sm5803.h" -#include "system.h" -#include "stdbool.h" -#include "throttle_ap.h" -#include "timer.h" -#include "usb_charge.h" -#include "usb_pd.h" -#include "usbc_ocp.h" -#include "util.h" -#include "watchdog.h" - -#ifndef CONFIG_CHARGER_NARROW_VDC -#error "SM5803 is a NVDC charger, please enable CONFIG_CHARGER_NARROW_VDC." -#endif - -/* Console output macros */ -#define CPRINTF(format, args...) cprintf(CC_CHARGER, format, ## args) -#define CPRINTS(format, args...) cprints(CC_CHARGER, format, ## args) - -#define UNKNOWN_DEV_ID -1 -static int dev_id = UNKNOWN_DEV_ID; - -static const struct charger_info sm5803_charger_info = { - .name = CHARGER_NAME, - .voltage_max = CHARGE_V_MAX, - .voltage_min = CHARGE_V_MIN, - .voltage_step = CHARGE_V_STEP, - .current_max = CHARGE_I_MAX, - .current_min = CHARGE_I_MIN, - .current_step = CHARGE_I_STEP, - .input_current_max = INPUT_I_MAX, - .input_current_min = INPUT_I_MIN, - .input_current_step = INPUT_I_STEP, -}; - -static uint32_t irq_pending; /* Bitmask of chips with interrupts pending */ - -static struct mutex flow1_access_lock[CHARGER_NUM]; -static struct mutex flow2_access_lock[CHARGER_NUM]; - -static int charger_vbus[CHARGER_NUM]; - -/* Tracker for charging failures per port */ -struct { - int count; - timestamp_t time; -} failure_tracker[CHARGER_NUM] = {}; - -/* Port to restart charging on */ -static int active_restart_port = CHARGE_PORT_NONE; - -/* - * If powered from the sub board port, we need to attempt to enable the BFET - * before proceeding with charging. - */ -static int attempt_bfet_enable; - -/* - * Note if auto fast charge for the primary port is disabled due to a - * disconnected battery, at re-enable auto fast charge later when the battery - * has connected. - */ -static bool fast_charge_disabled; - - -#define CHARGING_FAILURE_MAX_COUNT 5 -#define CHARGING_FAILURE_INTERVAL MINUTE - -static int sm5803_is_sourcing_otg_power(int chgnum, int port); -static enum ec_error_list sm5803_get_dev_id(int chgnum, int *id); -static enum ec_error_list sm5803_set_current(int chgnum, int current); - -static inline enum ec_error_list chg_read8(int chgnum, int offset, int *value) -{ - return i2c_read8(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, - offset, value); -} - -static inline enum ec_error_list chg_write8(int chgnum, int offset, int value) -{ - return i2c_write8(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, - offset, value); -} - -static inline enum ec_error_list meas_read8(int chgnum, int offset, int *value) -{ - return i2c_read8(chg_chips[chgnum].i2c_port, - SM5803_ADDR_MEAS_FLAGS, - offset, value); -} - -static inline enum ec_error_list meas_write8(int chgnum, int offset, int value) -{ - return i2c_write8(chg_chips[chgnum].i2c_port, - SM5803_ADDR_MEAS_FLAGS, - offset, value); -} - -static inline enum ec_error_list main_read8(int chgnum, int offset, int *value) -{ - return i2c_read8(chg_chips[chgnum].i2c_port, - SM5803_ADDR_MAIN_FLAGS, - offset, value); -} - -static inline enum ec_error_list main_write8(int chgnum, int offset, int value) -{ - return i2c_write8(chg_chips[chgnum].i2c_port, - SM5803_ADDR_MAIN_FLAGS, - offset, value); -} - -static inline enum ec_error_list test_write8(int chgnum, int offset, int value) -{ - return i2c_write8(chg_chips[chgnum].i2c_port, - SM5803_ADDR_TEST_FLAGS, - offset, value); -} - -static inline enum ec_error_list test_update8(int chgnum, const int offset, - const uint8_t mask, - const enum mask_update_action action) -{ - return i2c_update8(chg_chips[chgnum].i2c_port, - SM5803_ADDR_TEST_FLAGS, offset, mask, action); -} - -static enum ec_error_list sm5803_flow1_update(int chgnum, const uint8_t mask, - const enum mask_update_action action) -{ - int rv; - - /* Safety checks done, onto the actual register update */ - mutex_lock(&flow1_access_lock[chgnum]); - - rv = i2c_update8(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, - SM5803_REG_FLOW1, - mask, action); - - mutex_unlock(&flow1_access_lock[chgnum]); - - return rv; -} - -static enum ec_error_list sm5803_flow2_update(int chgnum, const uint8_t mask, - const enum mask_update_action action) -{ - int rv; - - mutex_lock(&flow2_access_lock[chgnum]); - - rv = i2c_update8(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, - SM5803_REG_FLOW2, - mask, action); - - mutex_unlock(&flow2_access_lock[chgnum]); - - return rv; -} - -static bool is_platform_id_2s(uint32_t platform_id) -{ - return platform_id >= 0x06 && platform_id <= 0x0D; -} - -static bool is_platform_id_3s(uint32_t platform_id) -{ - return platform_id >= 0x0E && platform_id <= 0x16; -} - -int sm5803_is_vbus_present(int chgnum) -{ - return charger_vbus[chgnum]; -} - -enum ec_error_list sm5803_configure_gpio0(int chgnum, - enum sm5803_gpio0_modes mode, int od) -{ - enum ec_error_list rv; - int reg; - - rv = main_read8(chgnum, SM5803_REG_GPIO0_CTRL, ®); - if (rv) - return rv; - - reg &= ~SM5803_GPIO0_MODE_MASK; - reg |= mode << 1; - - if (od) - reg |= SM5803_GPIO0_OPEN_DRAIN_EN; - else - reg &= ~SM5803_GPIO0_OPEN_DRAIN_EN; - - rv = main_write8(chgnum, SM5803_REG_GPIO0_CTRL, reg); - return rv; -} - -enum ec_error_list sm5803_set_gpio0_level(int chgnum, int level) -{ - enum ec_error_list rv; - int reg; - - rv = main_read8(chgnum, SM5803_REG_GPIO0_CTRL, ®); - if (rv) - return rv; - - if (level) - reg |= SM5803_GPIO0_VAL; - else - reg &= ~SM5803_GPIO0_VAL; - - rv = main_write8(chgnum, SM5803_REG_GPIO0_CTRL, reg); - return rv; -} - -enum ec_error_list sm5803_configure_chg_det_od(int chgnum, int enable) -{ - enum ec_error_list rv; - int reg; - - rv = main_read8(chgnum, SM5803_REG_GPIO0_CTRL, ®); - if (rv) - return rv; - - if (enable) - reg |= SM5803_CHG_DET_OPEN_DRAIN_EN; - else - reg &= ~SM5803_CHG_DET_OPEN_DRAIN_EN; - - rv = main_write8(chgnum, SM5803_REG_GPIO0_CTRL, reg); - return rv; -} - -enum ec_error_list sm5803_get_chg_det(int chgnum, int *chg_det) -{ - enum ec_error_list rv; - int reg; - - rv = main_read8(chgnum, SM5803_REG_STATUS1, ®); - if (rv) - return rv; - - *chg_det = (reg & SM5803_STATUS1_CHG_DET) != 0; - - return EC_SUCCESS; -} - -enum ec_error_list sm5803_set_vbus_disch(int chgnum, int enable) -{ - enum ec_error_list rv; - int reg; - - rv = main_read8(chgnum, SM5803_REG_PORTS_CTRL, ®); - if (rv) - return rv; - - if (enable) - reg |= SM5803_PORTS_VBUS_DISCH; - else - reg &= ~SM5803_PORTS_VBUS_DISCH; - - rv = main_write8(chgnum, SM5803_REG_PORTS_CTRL, reg); - return rv; -} - -enum ec_error_list sm5803_vbus_sink_enable(int chgnum, int enable) -{ - enum ec_error_list rv; - int regval; - - rv = sm5803_get_dev_id(chgnum, &dev_id); - if (rv) - return rv; - - if (enable) { - if (chgnum == CHARGER_PRIMARY) { - /* Magic for new silicon */ - if (dev_id >= 3) { - rv |= main_write8(chgnum, 0x1F, 0x1); - rv |= test_write8(chgnum, 0x44, 0x2); - rv |= main_write8(chgnum, 0x1F, 0); - } - /* - * Only enable auto fast charge when a battery is - * connected and out of cutoff. - */ - if (battery_get_disconnect_state() == - BATTERY_NOT_DISCONNECTED) { - rv = sm5803_flow2_update(chgnum, - SM5803_FLOW2_AUTO_ENABLED, - MASK_SET); - fast_charge_disabled = false; - } else { - rv = sm5803_flow2_update(chgnum, - SM5803_FLOW2_AUTO_TRKL_EN | - SM5803_FLOW2_AUTO_PRECHG_EN, - MASK_SET); - fast_charge_disabled = true; - } - } else { - if (dev_id >= 3) { - /* Touch of magic on the primary charger */ - rv |= main_write8(CHARGER_PRIMARY, 0x1F, 0x1); - rv |= test_write8(CHARGER_PRIMARY, 0x44, 0x20); - rv |= main_write8(CHARGER_PRIMARY, 0x1F, 0x0); - - /* - * Disable linear, pre-charge, and linear fast - * charge for primary charger. - */ - rv = chg_read8(CHARGER_PRIMARY, - SM5803_REG_FLOW3, ®val); - regval &= ~(BIT(6) | BIT(5) | BIT(4)); - - rv |= chg_write8(CHARGER_PRIMARY, - SM5803_REG_FLOW3, regval); - } - } - - /* Last but not least, enable sinking */ - rv |= sm5803_flow1_update(chgnum, CHARGER_MODE_SINK, MASK_SET); - } else { - if (chgnum == CHARGER_PRIMARY) - rv |= sm5803_flow2_update(chgnum, - SM5803_FLOW2_AUTO_ENABLED, - MASK_CLR); - - if (chgnum == CHARGER_SECONDARY) { - rv |= sm5803_flow1_update(CHARGER_PRIMARY, - SM5803_FLOW1_LINEAR_CHARGE_EN, - MASK_CLR); - - rv = chg_read8(CHARGER_PRIMARY, SM5803_REG_FLOW3, - ®val); - regval &= ~(BIT(6) | BIT(5) | BIT(4)); - rv |= chg_write8(CHARGER_PRIMARY, SM5803_REG_FLOW3, - regval); - } - - - /* Disable sink mode, unless currently sourcing out */ - if (!sm5803_is_sourcing_otg_power(chgnum, chgnum)) - rv |= sm5803_flow1_update(chgnum, CHARGER_MODE_SINK, - MASK_CLR); - } - - return rv; - -} - -/* - * Track and store whether we've initialized the charger chips already on this - * boot. This should prevent us from re-running inits after sysjumps. - */ -static bool chip_inited[CHARGER_NUM]; -#define SM5803_SYSJUMP_TAG 0x534D /* SM */ -#define SM5803_HOOK_VERSION 1 - -static void init_status_preserve(void) -{ - system_add_jump_tag(SM5803_SYSJUMP_TAG, SM5803_HOOK_VERSION, - sizeof(chip_inited), &chip_inited); -} -DECLARE_HOOK(HOOK_SYSJUMP, init_status_preserve, HOOK_PRIO_DEFAULT); - -static void init_status_retrieve(void) -{ - const uint8_t *tag_contents; - int version, size; - - tag_contents = system_get_jump_tag(SM5803_SYSJUMP_TAG, - &version, &size); - if (tag_contents && (version == SM5803_HOOK_VERSION) && - (size == sizeof(chip_inited))) - /* Valid init status found, restore before charger chip init */ - memcpy(&chip_inited, tag_contents, size); -} -DECLARE_HOOK(HOOK_INIT, init_status_retrieve, HOOK_PRIO_FIRST); - -static void sm5803_init(int chgnum) -{ - enum ec_error_list rv; - int reg; - int vbus_mv; - const struct battery_info *batt_info; - int pre_term; - int cells; - - /* - * If a charger is not currently present, disable switching per OCPC - * requirements - */ - rv = charger_get_vbus_voltage(chgnum, &vbus_mv); - if (rv == EC_SUCCESS) { - if (vbus_mv < 4000) { - /* - * No charger connected, disable CHG_EN - * (note other bits default to 0) - */ - rv = chg_write8(chgnum, SM5803_REG_FLOW1, 0); - } else if (!sm5803_is_sourcing_otg_power(chgnum, chgnum)) { - charger_vbus[chgnum] = 1; - } - } else { - CPRINTS("%s %d: Failed to read VBUS voltage during init", - CHARGER_NAME, chgnum); - return; - } - - /* - * A previous boot already ran inits, safe to return now that we've - * checked i2c communication to the chip and cached Vbus presence - */ - if (chip_inited[chgnum]) { - CPRINTS("%s %d: Already initialized", CHARGER_NAME, chgnum); - return; - } - - rv |= charger_device_id(®); - if (reg == 0x02) { - /* --- Special register init --- - * For early silicon (ID 2) with 3S batteries - */ - rv |= main_write8(chgnum, 0x20, 0x08); - rv |= main_write8(chgnum, 0x30, 0xC0); - rv |= main_write8(chgnum, 0x80, 0x01); - - rv |= meas_write8(chgnum, 0x08, 0xC2); - - rv |= chg_write8(chgnum, 0x1D, 0x40); - rv |= chg_write8(chgnum, 0x1F, 0x09); - - rv |= chg_write8(chgnum, 0x22, 0xB3); - rv |= chg_write8(chgnum, 0x23, 0x81); - rv |= chg_write8(chgnum, 0x28, 0xB7); - - rv |= chg_write8(chgnum, 0x4A, 0x82); - rv |= chg_write8(chgnum, 0x4B, 0xA3); - rv |= chg_write8(chgnum, 0x4C, 0xA8); - rv |= chg_write8(chgnum, 0x4D, 0xCA); - rv |= chg_write8(chgnum, 0x4E, 0x07); - rv |= chg_write8(chgnum, 0x4F, 0xFF); - - rv |= chg_write8(chgnum, 0x50, 0x98); - rv |= chg_write8(chgnum, 0x51, 0x00); - rv |= chg_write8(chgnum, 0x52, 0x77); - rv |= chg_write8(chgnum, 0x53, 0xD2); - rv |= chg_write8(chgnum, 0x54, 0x02); - rv |= chg_write8(chgnum, 0x55, 0xD1); - rv |= chg_write8(chgnum, 0x56, 0x7F); - rv |= chg_write8(chgnum, 0x57, 0x02); - rv |= chg_write8(chgnum, 0x58, 0xD1); - rv |= chg_write8(chgnum, 0x59, 0x7F); - rv |= chg_write8(chgnum, 0x5A, 0x13); - rv |= chg_write8(chgnum, 0x5B, 0x50); - rv |= chg_write8(chgnum, 0x5C, 0x5B); - rv |= chg_write8(chgnum, 0x5D, 0xB0); - rv |= chg_write8(chgnum, 0x5E, 0x3C); - rv |= chg_write8(chgnum, 0x5F, 0x3C); - - rv |= chg_write8(chgnum, 0x60, 0x44); - rv |= chg_write8(chgnum, 0x61, 0x20); - rv |= chg_write8(chgnum, 0x65, 0x35); - rv |= chg_write8(chgnum, 0x66, 0x29); - rv |= chg_write8(chgnum, 0x67, 0x64); - rv |= chg_write8(chgnum, 0x68, 0x88); - rv |= chg_write8(chgnum, 0x69, 0xC7); - - /* Inits to access page 0x37 and enable trickle charging */ - rv |= main_write8(chgnum, 0x1F, 0x01); - rv |= test_update8(chgnum, 0x8E, BIT(5), MASK_SET); - rv |= main_write8(chgnum, 0x1F, 0x00); - } else if (reg == 0x03) { - uint32_t platform_id; - - rv = main_read8(chgnum, SM5803_REG_PLATFORM, &platform_id); - if (rv) { - CPRINTS("%s %d: Failed to read platform during init", - CHARGER_NAME, chgnum); - return; - } - platform_id &= SM5803_PLATFORM_ID; - - if (is_platform_id_3s(platform_id)) { - /* 3S Battery inits */ - /* set 13.3V VBAT_SNSP TH GPADC THRESHOLD*/ - rv |= meas_write8(chgnum, 0x26, - SM5803_VBAT_SNSP_MAXTH_3S_LEVEL); - /* OV_VBAT HW second level (14.1V) */ - rv |= chg_write8(chgnum, 0x21, - SM5803_VBAT_PWR_MINTH_3S_LEVEL); - rv |= main_write8(chgnum, 0x30, 0xC0); - rv |= main_write8(chgnum, 0x80, 0x01); - rv |= main_write8(chgnum, 0x1A, 0x08); - - rv |= meas_write8(chgnum, 0x08, 0xC2); - - rv |= chg_write8(chgnum, 0x1D, 0x40); - - rv |= chg_write8(chgnum, 0x22, 0xB3); - - rv |= chg_write8(chgnum, 0x3E, 0x3C); - - rv |= chg_write8(chgnum, 0x4B, 0xA6); - rv |= chg_write8(chgnum, 0x4F, 0xBF); - - rv |= chg_write8(chgnum, 0x52, 0x77); - rv |= chg_write8(chgnum, 0x53, 0xD2); - rv |= chg_write8(chgnum, 0x54, 0x02); - rv |= chg_write8(chgnum, 0x55, 0xD1); - rv |= chg_write8(chgnum, 0x56, 0x7F); - rv |= chg_write8(chgnum, 0x57, 0x01); - rv |= chg_write8(chgnum, 0x58, 0x50); - rv |= chg_write8(chgnum, 0x59, 0x7F); - rv |= chg_write8(chgnum, 0x5A, 0x13); - rv |= chg_write8(chgnum, 0x5B, 0x50); - rv |= chg_write8(chgnum, 0x5D, 0xB0); - - rv |= chg_write8(chgnum, 0x60, 0x44); - rv |= chg_write8(chgnum, 0x65, 0x35); - rv |= chg_write8(chgnum, 0x66, 0x29); - - rv |= chg_write8(chgnum, 0x7D, 0x67); - rv |= chg_write8(chgnum, 0x7E, 0x04); - - rv |= chg_write8(chgnum, 0x33, 0x3C); - - rv |= chg_write8(chgnum, 0x5C, 0x7A); - } else if (is_platform_id_2s(platform_id)) { - /* 2S Battery inits */ - - /* - * Set 9V as higher threshold for VBATSNSP_MAX_TH GPADC - * threshold for interrupt generation. - */ - rv |= meas_write8(chgnum, 0x26, - SM5803_VBAT_SNSP_MAXTH_2S_LEVEL); - - /* Set OV_VBAT HW second level threshold as 9.4V */ - rv |= chg_write8(chgnum, 0x21, - SM5803_VBAT_PWR_MINTH_2S_LEVEL); - - rv |= main_write8(chgnum, 0x30, 0xC0); - rv |= main_write8(chgnum, 0x80, 0x01); - rv |= main_write8(chgnum, 0x1A, 0x08); - - rv |= meas_write8(chgnum, 0x08, 0xC2); - - rv |= chg_write8(chgnum, 0x1D, 0x40); - - rv |= chg_write8(chgnum, 0x22, 0xB3); - - rv |= chg_write8(chgnum, 0x3E, 0x3C); - - rv |= chg_write8(chgnum, 0x4F, 0xBF); - - rv |= chg_write8(chgnum, 0x52, 0x77); - rv |= chg_write8(chgnum, 0x53, 0xD2); - rv |= chg_write8(chgnum, 0x54, 0x02); - rv |= chg_write8(chgnum, 0x55, 0xD1); - rv |= chg_write8(chgnum, 0x56, 0x7F); - rv |= chg_write8(chgnum, 0x57, 0x01); - rv |= chg_write8(chgnum, 0x58, 0x50); - rv |= chg_write8(chgnum, 0x59, 0x7F); - rv |= chg_write8(chgnum, 0x5A, 0x13); - rv |= chg_write8(chgnum, 0x5B, 0x52); - rv |= chg_write8(chgnum, 0x5D, 0xD0); - - rv |= chg_write8(chgnum, 0x60, 0x44); - rv |= chg_write8(chgnum, 0x65, 0x35); - rv |= chg_write8(chgnum, 0x66, 0x29); - - rv |= chg_write8(chgnum, 0x7D, 0x97); - rv |= chg_write8(chgnum, 0x7E, 0x07); - - rv |= chg_write8(chgnum, 0x33, 0x3C); - - rv |= chg_write8(chgnum, 0x5C, 0x7A); - } - - rv |= chg_write8(chgnum, 0x73, 0x22); - rv |= chg_write8(chgnum, 0x50, 0x88); - rv |= chg_read8(chgnum, 0x34, ®); - reg |= BIT(7); - rv |= chg_write8(chgnum, 0x34, reg); - rv |= main_write8(chgnum, 0x1F, 0x1); - rv |= test_write8(chgnum, 0x43, 0x10); - rv |= test_write8(chgnum, 0x47, 0x10); - rv |= test_write8(chgnum, 0x48, 0x04); - rv |= main_write8(chgnum, 0x1F, 0x0); - } - - /* Enable LDO bits */ - rv |= main_read8(chgnum, SM5803_REG_REFERENCE, ®); - reg &= ~(BIT(0) | BIT(1)); - rv |= main_write8(chgnum, SM5803_REG_REFERENCE, reg); - - /* Set a higher clock speed in case it was lowered for z-state */ - rv |= main_read8(chgnum, SM5803_REG_CLOCK_SEL, ®); - reg &= ~SM5803_CLOCK_SEL_LOW; - rv |= main_write8(chgnum, SM5803_REG_CLOCK_SEL, reg); - - /* - * Turn on GPADCs to default. Enable the IBAT_CHG ADC in order to - * measure battery current and calculate system resistance. - */ - reg = SM5803_GPADCC1_TINT_EN | - SM5803_GPADCC1_VSYS_EN | - SM5803_GPADCC1_VCHGPWR_EN | - SM5803_GPADCC1_VBUS_EN | - SM5803_GPADCC1_IBAT_CHG_EN | - SM5803_GPADCC1_IBAT_DIS_EN | - SM5803_GPADCC1_VBATSNSP_EN; - rv |= meas_write8(chgnum, SM5803_REG_GPADC_CONFIG1, reg); - - /* Enable Psys DAC */ - rv |= meas_read8(chgnum, SM5803_REG_PSYS1, ®); - reg |= SM5803_PSYS1_DAC_EN; - rv |= meas_write8(chgnum, SM5803_REG_PSYS1, reg); - - /* Enable ADC sigma delta */ - rv |= chg_read8(chgnum, SM5803_REG_CC_CONFIG1, ®); - reg |= SM5803_CC_CONFIG1_SD_PWRUP; - rv |= chg_write8(chgnum, SM5803_REG_CC_CONFIG1, reg); - - /* Enable PROCHOT comparators except Ibus */ - rv |= chg_read8(chgnum, SM5803_REG_PHOT1, ®); - reg |= SM5803_PHOT1_COMPARATOR_EN; - reg &= ~SM5803_PHOT1_IBUS_PHOT_COMP_EN; - rv |= chg_write8(chgnum, SM5803_REG_PHOT1, reg); - - /* Set DPM Voltage to 4200 mv, see b:172173517 */ - reg = SM5803_VOLTAGE_TO_REG(4200); - rv = chg_write8(chgnum, SM5803_REG_DPM_VL_SET_MSB, (reg >> 3)); - rv |= chg_write8(chgnum, SM5803_REG_DPM_VL_SET_LSB, (reg & 0x7)); - - /* Set default input current */ - reg = SM5803_CURRENT_TO_REG(CONFIG_CHARGER_INPUT_CURRENT) - & SM5803_CHG_ILIM_RAW; - rv |= chg_write8(chgnum, SM5803_REG_CHG_ILIM, reg); - - /* Configure charger insertion interrupts */ - rv |= main_write8(chgnum, SM5803_REG_INT1_EN, SM5803_INT1_CHG); - /* Enable end of charge interrupts for logging */ - rv |= main_write8(chgnum, SM5803_REG_INT4_EN, SM5803_INT4_CHG_FAIL | - SM5803_INT4_CHG_DONE | - SM5803_INT4_OTG_FAIL); - - /* Set TINT interrupts for higher threshold 360 K */ - rv |= meas_write8(chgnum, SM5803_REG_TINT_HIGH_TH, - SM5803_TINT_HIGH_LEVEL); - /* - * Set TINT interrupts for lower threshold to 0 when not - * throttled to prevent trigger interrupts continually - */ - rv |= meas_write8(chgnum, SM5803_REG_TINT_LOW_TH, - SM5803_TINT_MIN_LEVEL); - - /* - * Configure VBAT_SNSP high interrupt to fire after thresholds are set. - */ - rv |= main_read8(chgnum, SM5803_REG_INT2_EN, ®); - reg |= SM5803_INT2_VBATSNSP; - rv |= main_write8(chgnum, SM5803_REG_INT2_EN, reg); - - - /* Configure TINT interrupts to fire after thresholds are set */ - rv |= main_write8(chgnum, SM5803_REG_INT2_EN, SM5803_INT2_TINT); - - /* - * Configure CHG_ENABLE to only be set through I2C by setting - * HOST_MODE_EN bit (all other register bits are 0 by default) - */ - rv |= chg_write8(chgnum, SM5803_REG_FLOW2, SM5803_FLOW2_HOST_MODE_EN); - - if (chgnum == CHARGER_PRIMARY) { - int ibat_eoc_ma; - - /* Set end of fast charge threshold */ - batt_info = battery_get_info(); - ibat_eoc_ma = batt_info->precharge_current - 50; - ibat_eoc_ma /= 100; - ibat_eoc_ma = CLAMP(ibat_eoc_ma, 0, SM5803_CONF5_IBAT_EOC_TH); - rv |= chg_read8(chgnum, SM5803_REG_FAST_CONF5, ®); - reg &= ~SM5803_CONF5_IBAT_EOC_TH; - reg |= ibat_eoc_ma; - rv |= chg_write8(CHARGER_PRIMARY, SM5803_REG_FAST_CONF5, reg); - - /* Setup the proper precharge thresholds. */ - cells = batt_info->voltage_max / 4; - pre_term = batt_info->voltage_min / cells; - pre_term /= 100; /* Convert to decivolts. */ - pre_term = CLAMP(pre_term, SM5803_VBAT_PRE_TERM_MIN_DV, - SM5803_VBAT_PRE_TERM_MAX_DV); - pre_term -= SM5803_VBAT_PRE_TERM_MIN_DV; /* Convert to regval */ - - rv |= chg_read8(chgnum, SM5803_REG_PRE_FAST_CONF_REG1, ®); - reg &= ~SM5803_VBAT_PRE_TERM; - reg |= pre_term << SM5803_VBAT_PRE_TERM_SHIFT; - rv |= chg_write8(chgnum, SM5803_REG_PRE_FAST_CONF_REG1, reg); - - /* - * Set up precharge current - * Note it is preferred to under-shoot the precharge current - * requested. Upper bits of this register are read/write 1 to - * clear - */ - reg = SM5803_CURRENT_TO_REG(batt_info->precharge_current); - reg = MIN(reg, SM5803_PRECHG_ICHG_PRE_SET); - rv |= chg_write8(chgnum, SM5803_REG_PRECHG, reg); - - /* - * Set up BFET alerts - * - * We'll set the soft limit at 1.5W and the hard limit at 6W. - * - * The register is 29.2 mW per bit. - */ - reg = (1500 * 10) / 292; - rv |= meas_write8(chgnum, SM5803_REG_BFET_PWR_MAX_TH, reg); - reg = (6000 * 10) / 292; - rv |= meas_write8(chgnum, SM5803_REG_BFET_PWR_HWSAFE_MAX_TH, - reg); - rv |= main_read8(chgnum, SM5803_REG_INT3_EN, ®); - reg |= SM5803_INT3_BFET_PWR_LIMIT | - SM5803_INT3_BFET_PWR_HWSAFE_LIMIT; - rv |= main_write8(chgnum, SM5803_REG_INT3_EN, reg); - - rv |= chg_read8(chgnum, SM5803_REG_FLOW3, ®); - reg &= ~SM5803_FLOW3_SWITCH_BCK_BST; - rv |= chg_write8(chgnum, SM5803_REG_FLOW3, reg); - - rv |= chg_read8(chgnum, SM5803_REG_SWITCHER_CONF, ®); - reg |= SM5803_SW_BCK_BST_CONF_AUTO; - rv |= chg_write8(chgnum, SM5803_REG_SWITCHER_CONF, reg); - } - - if (rv) - CPRINTS("%s %d: Failed initialization", CHARGER_NAME, chgnum); - else - chip_inited[chgnum] = true; -} - -static enum ec_error_list sm5803_post_init(int chgnum) -{ - /* Nothing to do, charger is always powered */ - return EC_SUCCESS; -} - -void sm5803_hibernate(int chgnum) -{ - enum ec_error_list rv; - int reg; - - rv = main_read8(chgnum, SM5803_REG_REFERENCE, ®); - if (rv) { - CPRINTS("%s %d: Failed to read REFERENCE reg", CHARGER_NAME, - chgnum); - return; - } - - /* Disable LDO bits - note the primary LDO should not be disabled */ - if (chgnum != CHARGER_PRIMARY) { - reg |= (BIT(0) | BIT(1)); - rv |= main_write8(chgnum, SM5803_REG_REFERENCE, reg); - } - - /* Slow the clock speed */ - rv |= main_read8(chgnum, SM5803_REG_CLOCK_SEL, ®); - reg |= SM5803_CLOCK_SEL_LOW; - rv |= main_write8(chgnum, SM5803_REG_CLOCK_SEL, reg); - - /* Turn off GPADCs */ - rv |= meas_write8(chgnum, SM5803_REG_GPADC_CONFIG1, 0); - rv |= meas_write8(chgnum, SM5803_REG_GPADC_CONFIG2, 0); - - /* Disable Psys DAC */ - rv |= meas_read8(chgnum, SM5803_REG_PSYS1, ®); - reg &= ~SM5803_PSYS1_DAC_EN; - rv |= meas_write8(chgnum, SM5803_REG_PSYS1, reg); - - /* Disable ADC sigma delta */ - rv |= chg_read8(chgnum, SM5803_REG_CC_CONFIG1, ®); - reg &= ~SM5803_CC_CONFIG1_SD_PWRUP; - rv |= chg_write8(chgnum, SM5803_REG_CC_CONFIG1, reg); - - /* Disable PROCHOT comparators */ - rv |= chg_read8(chgnum, SM5803_REG_PHOT1, ®); - reg &= ~SM5803_PHOT1_COMPARATOR_EN; - rv |= chg_write8(chgnum, SM5803_REG_PHOT1, reg); - - if (rv) - CPRINTS("%s %d: Failed to set hibernate", CHARGER_NAME, chgnum); -} - -static void sm5803_disable_runtime_low_power_mode(void) -{ - enum ec_error_list rv; - int reg; - int chgnum = TASK_ID_TO_PD_PORT(task_get_current()); - - CPRINTS("%s %d: disable runtime low power mode", CHARGER_NAME, chgnum); - rv = main_read8(chgnum, SM5803_REG_REFERENCE, ®); - if (rv) { - CPRINTS("%s %d: Failed to read REFERENCE reg", CHARGER_NAME, - chgnum); - return; - } - /* Set a higher clock speed */ - rv |= main_read8(chgnum, SM5803_REG_CLOCK_SEL, ®); - reg &= ~SM5803_CLOCK_SEL_LOW; - rv |= main_write8(chgnum, SM5803_REG_CLOCK_SEL, reg); - - /* Enable ADC sigma delta */ - rv |= chg_read8(chgnum, SM5803_REG_CC_CONFIG1, ®); - reg |= SM5803_CC_CONFIG1_SD_PWRUP; - rv |= chg_write8(chgnum, SM5803_REG_CC_CONFIG1, reg); - - if (rv) - CPRINTS("%s %d: Failed to set in disable runtime LPM", - CHARGER_NAME, chgnum); -} -DECLARE_HOOK(HOOK_USB_PD_CONNECT, - sm5803_disable_runtime_low_power_mode, - HOOK_PRIO_FIRST); - -static enum ec_error_list sm5803_enable_linear_charge(int chgnum, bool enable) -{ - int rv; - int regval; - const struct battery_info *batt_info; - - if (enable) { - /* - * We need to wait for the BFET enable attempt to complete, - * otherwise we may end up disabling linear charge. - */ - if (!attempt_bfet_enable) - return EC_ERROR_TRY_AGAIN; - rv = main_write8(chgnum, 0x1F, 0x1); - rv |= test_write8(chgnum, 0x44, 0x20); - rv |= main_write8(chgnum, 0x1F, 0); - - /* - * Precharge thresholds have already been set up as a part of - * init, however set fast charge current equal to the precharge - * current in case the battery moves beyond that threshold. - */ - batt_info = battery_get_info(); - rv |= sm5803_set_current(CHARGER_PRIMARY, - batt_info->precharge_current); - - /* Enable linear charge mode. */ - rv |= sm5803_flow1_update(chgnum, - SM5803_FLOW1_LINEAR_CHARGE_EN, - MASK_SET); - rv |= chg_read8(chgnum, SM5803_REG_FLOW3, ®val); - regval |= BIT(6) | BIT(5) | BIT(4); - rv |= chg_write8(chgnum, SM5803_REG_FLOW3, regval); - } else { - rv = sm5803_flow1_update(chgnum, - SM5803_FLOW1_LINEAR_CHARGE_EN, - MASK_CLR); - rv |= sm5803_flow2_update(chgnum, - SM5803_FLOW2_AUTO_ENABLED, - MASK_CLR); - rv |= chg_read8(chgnum, SM5803_REG_FLOW3, ®val); - regval &= ~(BIT(6) | BIT(5) | BIT(4) | - SM5803_FLOW3_SWITCH_BCK_BST); - rv |= chg_write8(chgnum, SM5803_REG_FLOW3, regval); - rv |= chg_read8(chgnum, SM5803_REG_SWITCHER_CONF, ®val); - regval |= SM5803_SW_BCK_BST_CONF_AUTO; - rv |= chg_write8(chgnum, SM5803_REG_SWITCHER_CONF, regval); - } - - return rv; -} - -static void sm5803_enable_runtime_low_power_mode(void) -{ - enum ec_error_list rv; - int reg; - int chgnum = TASK_ID_TO_PD_PORT(task_get_current()); - - CPRINTS("%s %d: enable runtime low power mode", CHARGER_NAME, chgnum); - rv = main_read8(chgnum, SM5803_REG_REFERENCE, ®); - if (rv) { - CPRINTS("%s %d: Failed to read REFERENCE reg", CHARGER_NAME, - chgnum); - return; - } - /* Slow the clock speed */ - rv |= main_read8(chgnum, SM5803_REG_CLOCK_SEL, ®); - reg |= SM5803_CLOCK_SEL_LOW; - rv |= main_write8(chgnum, SM5803_REG_CLOCK_SEL, reg); - - /* Disable ADC sigma delta */ - rv |= chg_read8(chgnum, SM5803_REG_CC_CONFIG1, ®); - reg &= ~SM5803_CC_CONFIG1_SD_PWRUP; - rv |= chg_write8(chgnum, SM5803_REG_CC_CONFIG1, reg); - - /* If the system is off, all PROCHOT comparators may be turned off */ - if (chipset_in_state(CHIPSET_STATE_ANY_OFF | - CHIPSET_STATE_ANY_SUSPEND)) { - rv |= chg_read8(chgnum, SM5803_REG_PHOT1, ®); - reg &= ~SM5803_PHOT1_COMPARATOR_EN; - rv |= chg_write8(chgnum, SM5803_REG_PHOT1, reg); - } - - if (rv) - CPRINTS("%s %d: Failed to set in enable runtime LPM", - CHARGER_NAME, chgnum); -} -DECLARE_HOOK(HOOK_USB_PD_DISCONNECT, - sm5803_enable_runtime_low_power_mode, - HOOK_PRIO_LAST); - -void sm5803_disable_low_power_mode(int chgnum) -{ - enum ec_error_list rv; - int reg; - - CPRINTS("%s %d: disable low power mode", CHARGER_NAME, chgnum); - rv = main_read8(chgnum, SM5803_REG_REFERENCE, ®); - if (rv) { - CPRINTS("%s %d: Failed to read REFERENCE reg", CHARGER_NAME, - chgnum); - return; - } - /* Enable Psys DAC */ - rv |= meas_read8(chgnum, SM5803_REG_PSYS1, ®); - reg |= SM5803_PSYS1_DAC_EN; - rv |= meas_write8(chgnum, SM5803_REG_PSYS1, reg); - - /* Enable PROCHOT comparators except Ibus */ - rv |= chg_read8(chgnum, SM5803_REG_PHOT1, ®); - reg |= SM5803_PHOT1_COMPARATOR_EN; - reg &= ~SM5803_PHOT1_IBUS_PHOT_COMP_EN; - rv |= chg_write8(chgnum, SM5803_REG_PHOT1, reg); - - if (rv) - CPRINTS("%s %d: Failed to set in disable low power mode", - CHARGER_NAME, chgnum); -} - -void sm5803_enable_low_power_mode(int chgnum) -{ - enum ec_error_list rv; - int reg; - - CPRINTS("%s %d: enable low power mode", CHARGER_NAME, chgnum); - rv = main_read8(chgnum, SM5803_REG_REFERENCE, ®); - if (rv) { - CPRINTS("%s %d: Failed to read REFERENCE reg", CHARGER_NAME, - chgnum); - return; - } - /* Disable Psys DAC */ - rv |= meas_read8(chgnum, SM5803_REG_PSYS1, ®); - reg &= ~SM5803_PSYS1_DAC_EN; - rv |= meas_write8(chgnum, SM5803_REG_PSYS1, reg); - - /* - * Disable all PROCHOT comparators only if port is inactive. Vbus - * sourcing requires that the Vbus comparator be enabled, and it - * cannot be enabled from HOOK_USB_PD_CONNECT since that is - * called after Vbus has turned on. - */ - rv |= chg_read8(chgnum, SM5803_REG_PHOT1, ®); - reg &= ~SM5803_PHOT1_COMPARATOR_EN; - if (pd_is_connected(chgnum)) - reg |= SM5803_PHOT1_VBUS_MON_EN; - rv |= chg_write8(chgnum, SM5803_REG_PHOT1, reg); - - - if (rv) - CPRINTS("%s %d: Failed to set in enable low power mode", - CHARGER_NAME, chgnum); -} - -/* - * Restart charging on the active port, if it's still active and it hasn't - * exceeded our maximum number of restarts. - */ -void sm5803_restart_charging(void) -{ - int act_chg = charge_manager_get_active_charge_port(); - timestamp_t now = get_time(); - - if (act_chg == active_restart_port) { - if (timestamp_expired(failure_tracker[act_chg].time, &now)) { - /* - * Enough time has passed since our last failure, - * restart the timing and count from now. - */ - failure_tracker[act_chg].time.val = now.val + - CHARGING_FAILURE_INTERVAL; - failure_tracker[act_chg].count = 1; - - sm5803_vbus_sink_enable(act_chg, 1); - } else if (++failure_tracker[act_chg].count > - CHARGING_FAILURE_MAX_COUNT) { - CPRINTS("%s %d: Exceeded charging failure retries", - CHARGER_NAME, act_chg); - } else { - sm5803_vbus_sink_enable(act_chg, 1); - } - } - - active_restart_port = CHARGE_PORT_NONE; -} -DECLARE_DEFERRED(sm5803_restart_charging); - -/* - * Process interrupt registers and report any Vbus changes. Alert the AP if the - * charger has become too hot. - */ -void sm5803_handle_interrupt(int chgnum) -{ - enum ec_error_list rv; - int int_reg, meas_reg; - static bool throttled; - struct batt_params bp; - int act_chg, val; - - /* Note: Interrupt registers are clear on read */ - rv = main_read8(chgnum, SM5803_REG_INT1_REQ, &int_reg); - if (rv) { - CPRINTS("%s %d: Failed read int1 register", CHARGER_NAME, - chgnum); - return; - } - - if (int_reg & SM5803_INT1_CHG) { - rv = main_read8(chgnum, SM5803_REG_STATUS1, &meas_reg); - if (!(meas_reg & SM5803_STATUS1_CHG_DET)) { - charger_vbus[chgnum] = 0; - if (IS_ENABLED(CONFIG_USB_CHARGER)) - usb_charger_vbus_change(chgnum, 0); - } else { - charger_vbus[chgnum] = 1; - if (IS_ENABLED(CONFIG_USB_CHARGER)) - usb_charger_vbus_change(chgnum, 1); - } - board_check_extpower(); - } - - rv = main_read8(chgnum, SM5803_REG_INT2_REQ, &int_reg); - if (rv) { - CPRINTS("%s %d: Failed read int2 register", CHARGER_NAME, - chgnum); - return; - } - - if (int_reg & SM5803_INT2_TINT) { - rv = meas_read8(chgnum, SM5803_REG_TINT_MEAS_MSB, &meas_reg); - if ((meas_reg <= SM5803_TINT_LOW_LEVEL) && throttled) { - throttled = false; - throttle_ap(THROTTLE_OFF, THROTTLE_HARD, - THROTTLE_SRC_THERMAL); - /* - * Set back higher threshold to 360 K and set lower - * threshold to 0. - */ - rv |= meas_write8(chgnum, SM5803_REG_TINT_LOW_TH, - SM5803_TINT_MIN_LEVEL); - rv |= meas_write8(chgnum, SM5803_REG_TINT_HIGH_TH, - SM5803_TINT_HIGH_LEVEL); - } else if (meas_reg >= SM5803_TINT_HIGH_LEVEL) { - throttled = true; - throttle_ap(THROTTLE_ON, THROTTLE_HARD, - THROTTLE_SRC_THERMAL); - /* - * Set back lower threshold to 330 K and set higher - * threshold to maximum. - */ - rv |= meas_write8(chgnum, SM5803_REG_TINT_HIGH_TH, - SM5803_TINT_MAX_LEVEL); - rv |= meas_write8(chgnum, SM5803_REG_TINT_LOW_TH, - SM5803_TINT_LOW_LEVEL); - } - /* - * If the interrupt came in and we're not currently throttling - * or the level is below the upper threshold, it can likely be - * ignored. - */ - } - - if (int_reg & SM5803_INT2_VBATSNSP) { - int meas_volt; - uint32_t platform_id; - - rv = main_read8(chgnum, SM5803_REG_PLATFORM, &platform_id); - if (rv) { - CPRINTS("%s %d: Failed to read platform in interrupt", - CHARGER_NAME, chgnum); - return; - } - platform_id &= SM5803_PLATFORM_ID; - act_chg = charge_manager_get_active_charge_port(); - rv = meas_read8(CHARGER_PRIMARY, - SM5803_REG_VBATSNSP_MEAS_MSB, - &meas_reg); - if (rv) - return; - meas_volt = meas_reg << 2; - rv = meas_read8(CHARGER_PRIMARY, - SM5803_REG_VBATSNSP_MEAS_LSB, - &meas_reg); - if (rv) - return; - meas_volt |= meas_reg & 0x03; - rv = meas_read8(CHARGER_PRIMARY, - SM5803_REG_VBATSNSP_MAX_TH, &meas_reg); - if (rv) - return; - - if (is_platform_id_2s(platform_id)) { - /* 2S Battery */ - CPRINTS("%s %d : VBAT_SNSP_HIGH_TH: %d mV ! - " - "VBAT %d mV", - CHARGER_NAME, CHARGER_PRIMARY, - meas_reg * 408/10, - meas_volt * 102/10); - } - - if (is_platform_id_3s(platform_id)) { - /* 3S Battery */ - CPRINTS("%s %d : VBAT_SNSP_HIGH_TH: %d mV ! " - "- VBAT %d mV", - CHARGER_NAME, CHARGER_PRIMARY, - meas_reg * 616/10, - meas_volt * 154/10); - } - - /* Set Vbat Threshold to Max value to re-arm the interrupt */ - rv = meas_write8(CHARGER_PRIMARY, - SM5803_REG_VBATSNSP_MAX_TH, 0xFF); - - /* Disable battery charge */ - rv |= sm5803_flow1_update(chgnum, CHARGER_MODE_DISABLED, - MASK_CLR); - if (is_platform_id_2s(platform_id)) { - /* 2S battery: set VBAT_SENSP TH 9V */ - rv |= meas_write8(CHARGER_PRIMARY, - SM5803_REG_VBATSNSP_MAX_TH, - SM5803_VBAT_SNSP_MAXTH_2S_LEVEL); - } - if (is_platform_id_3s(platform_id)) { - /* 3S battery: set VBAT_SENSP TH 13.3V */ - rv |= meas_write8(CHARGER_PRIMARY, - SM5803_REG_VBATSNSP_MAX_TH, - SM5803_VBAT_SNSP_MAXTH_3S_LEVEL); - } - - active_restart_port = act_chg; - hook_call_deferred(&sm5803_restart_charging_data, 1 * SECOND); - } - - /* TODO(b/159376384): Take action on fatal BFET power alert. */ - rv = main_read8(chgnum, SM5803_REG_INT3_REQ, &int_reg); - if (rv) { - CPRINTS("%s %d: Failed to read int3 register", CHARGER_NAME, - chgnum); - return; - } - - if ((int_reg & SM5803_INT3_BFET_PWR_LIMIT) || - (int_reg & SM5803_INT3_BFET_PWR_HWSAFE_LIMIT)) { - battery_get_params(&bp); - act_chg = charge_manager_get_active_charge_port(); - CPRINTS("%s BFET power limit reached! (%s)", CHARGER_NAME, - (int_reg & SM5803_INT3_BFET_PWR_LIMIT) ? "warn" : - "FATAL"); - CPRINTS("\tVbat: %dmV", bp.voltage); - CPRINTS("\tIbat: %dmA", bp.current); - charger_get_voltage(act_chg, &val); - CPRINTS("\tVsys(aux): %dmV", val); - charger_get_current(act_chg, &val); - CPRINTS("\tIsys: %dmA", val); - cflush(); - } - - rv = main_read8(chgnum, SM5803_REG_INT4_REQ, &int_reg); - if (rv) { - CPRINTS("%s %d: Failed to read int4 register", CHARGER_NAME, - chgnum); - return; - } - - if (int_reg & SM5803_INT4_CHG_FAIL) { - int status_reg; - - act_chg = charge_manager_get_active_charge_port(); - chg_read8(chgnum, SM5803_REG_STATUS_CHG_REG, &status_reg); - CPRINTS("%s %d: CHG_FAIL_INT fired. Status 0x%02x", - CHARGER_NAME, chgnum, status_reg); - - /* Write 1 to clear status interrupts */ - chg_write8(chgnum, SM5803_REG_STATUS_CHG_REG, status_reg); - - /* - * If a survivable fault happened, re-start sinking on the - * active charger after an appropriate delay. - */ - if (status_reg & SM5803_STATUS_CHG_OV_ITEMP) { - active_restart_port = act_chg; - hook_call_deferred(&sm5803_restart_charging_data, - 30 * SECOND); - } else if ((status_reg & SM5803_STATUS_CHG_OV_VBAT) && - act_chg == CHARGER_PRIMARY) { - active_restart_port = act_chg; - hook_call_deferred(&sm5803_restart_charging_data, - 1 * SECOND); - } - } - - if (int_reg & SM5803_INT4_CHG_DONE) - CPRINTS("%s %d: CHG_DONE_INT fired!!!", CHARGER_NAME, chgnum); - - if (int_reg & SM5803_INT4_OTG_FAIL) { - int status_reg; - - /* - * Gather status to detect if this was overcurrent - * - * Note: a status of 0 with this interrupt also indicates an - * overcurrent (see b/170517117) - */ - chg_read8(chgnum, SM5803_REG_STATUS_DISCHG, &status_reg); - CPRINTS("%s %d: OTG_FAIL_INT fired. Status 0x%02x", - CHARGER_NAME, chgnum, status_reg); - if ((status_reg == 0) || - (status_reg == SM5803_STATUS_DISCHG_VBUS_SHORT)) { - pd_handle_overcurrent(chgnum); - } - - /* - * Clear source mode here when status is 0, since OTG disable - * will detect us as sinking in this failure case. - */ - if (status_reg == 0) - rv = sm5803_flow1_update(chgnum, CHARGER_MODE_SOURCE | - SM5803_FLOW1_DIRECTCHG_SRC_EN, - MASK_CLR); - } - -} - -static void sm5803_irq_deferred(void) -{ - int i; - uint32_t pending = atomic_clear(&irq_pending); - - for (i = 0; i < CHARGER_NUM; i++) - if (BIT(i) & pending) - sm5803_handle_interrupt(i); -} -DECLARE_DEFERRED(sm5803_irq_deferred); - -void sm5803_interrupt(int chgnum) -{ - atomic_or(&irq_pending, BIT(chgnum)); - hook_call_deferred(&sm5803_irq_deferred_data, 0); -} - -static enum ec_error_list sm5803_get_dev_id(int chgnum, int *id) -{ - int rv = EC_SUCCESS; - - if (dev_id == UNKNOWN_DEV_ID) - rv = main_read8(chgnum, SM5803_REG_CHIP_ID, &dev_id); - - if (!rv) - *id = dev_id; - - return rv; - -} - -static const struct charger_info *sm5803_get_info(int chgnum) -{ - return &sm5803_charger_info; -} - -static enum ec_error_list sm5803_get_status(int chgnum, int *status) -{ - enum ec_error_list rv; - int reg; - - /* Charger obeys smart battery requests - making it level 2 */ - *status = CHARGER_LEVEL_2; - - rv = chg_read8(chgnum, SM5803_REG_FLOW1, ®); - if (rv) - return rv; - - - if ((reg & SM5803_FLOW1_MODE) == CHARGER_MODE_DISABLED && - !(reg & SM5803_FLOW1_LINEAR_CHARGE_EN)) - *status |= CHARGER_CHARGE_INHIBITED; - - return EC_SUCCESS; -} - -static enum ec_error_list sm5803_set_mode(int chgnum, int mode) -{ - enum ec_error_list rv = EC_SUCCESS; - - if (mode & CHARGE_FLAG_INHIBIT_CHARGE) { - rv = sm5803_flow1_update(chgnum, 0xFF, MASK_CLR); - rv |= sm5803_flow2_update(chgnum, SM5803_FLOW2_AUTO_ENABLED, - MASK_CLR); - } - - return rv; -} - -static enum ec_error_list sm5803_get_actual_current(int chgnum, int *current) -{ - enum ec_error_list rv; - int reg; - int curr; - - rv = meas_read8(chgnum, SM5803_REG_IBAT_CHG_AVG_MEAS_MSB, ®); - if (rv) - return rv; - curr = reg << 2; - - rv = meas_read8(chgnum, SM5803_REG_IBAT_CHG_AVG_MEAS_LSB, ®); - if (rv) - return rv; - curr |= reg & SM5803_IBAT_CHG_MEAS_LSB; - - /* The LSB is 7.32mA */ - *current = curr * 732 / 100; - return EC_SUCCESS; -} - -static enum ec_error_list sm5803_get_current(int chgnum, int *current) -{ - enum ec_error_list rv; - int reg; - - rv = chg_read8(chgnum, SM5803_REG_FAST_CONF4, ®); - if (rv) - return rv; - - reg &= SM5803_CONF4_ICHG_FAST; - *current = SM5803_REG_TO_CURRENT(reg); - - return EC_SUCCESS; -} - -static enum ec_error_list sm5803_set_current(int chgnum, int current) -{ - enum ec_error_list rv; - int reg; - - rv = chg_read8(chgnum, SM5803_REG_FAST_CONF4, ®); - if (rv) - return rv; - - reg &= ~SM5803_CONF4_ICHG_FAST; - reg |= SM5803_CURRENT_TO_REG(current); - - rv = chg_write8(chgnum, SM5803_REG_FAST_CONF4, reg); - return rv; -} - -static enum ec_error_list sm5803_get_actual_voltage(int chgnum, int *voltage) -{ - enum ec_error_list rv; - int reg; - int volt_bits; - - rv = meas_read8(chgnum, SM5803_REG_VSYS_AVG_MEAS_MSB, ®); - if (rv) - return rv; - volt_bits = reg << 2; - - rv = meas_read8(chgnum, SM5803_REG_VSYS_AVG_MEAS_LSB, ®); - if (rv) - return rv; - volt_bits |= reg & 0x3; - - /* The LSB is 23.4mV */ - *voltage = volt_bits * 234 / 10; - - return EC_SUCCESS; -} - -static enum ec_error_list sm5803_get_voltage(int chgnum, int *voltage) -{ - enum ec_error_list rv; - int regval; - int v; - - rv = chg_read8(chgnum, SM5803_REG_VBAT_FAST_MSB, ®val); - v = regval << 3; - rv |= chg_read8(chgnum, SM5803_REG_VBAT_FAST_LSB, ®val); - v |= (regval & 0x3); - - *voltage = SM5803_REG_TO_VOLTAGE(v); - - if (rv) - return EC_ERROR_UNKNOWN; - - return EC_SUCCESS; -} - -static enum ec_error_list sm5803_set_voltage(int chgnum, int voltage) -{ - enum ec_error_list rv; - int regval; - - regval = SM5803_VOLTAGE_TO_REG(voltage); - - /* - * Note: Set both voltages on both chargers. Vbat will only be used on - * primary, which enables charging. - */ - rv = chg_write8(chgnum, SM5803_REG_VSYS_PREREG_MSB, (regval >> 3)); - rv |= chg_write8(chgnum, SM5803_REG_VSYS_PREREG_LSB, (regval & 0x7)); - rv |= chg_write8(chgnum, SM5803_REG_VBAT_FAST_MSB, (regval >> 3)); - rv |= chg_write8(chgnum, SM5803_REG_VBAT_FAST_LSB, (regval & 0x7)); - - /* Once battery is connected, set up fast charge enable */ - if (fast_charge_disabled && chgnum == CHARGER_PRIMARY && - battery_get_disconnect_state() == BATTERY_NOT_DISCONNECTED) { - rv = sm5803_flow2_update(chgnum, - SM5803_FLOW2_AUTO_ENABLED, - MASK_SET); - fast_charge_disabled = false; - } - - if (IS_ENABLED(CONFIG_OCPC) && chgnum != CHARGER_PRIMARY) { - /* - * Check to see if the BFET is enabled. If not, enable it by - * toggling linear mode on the primary charger. The BFET can be - * disabled if the system is powered up from an auxiliary charge - * port and the battery is dead. - */ - rv |= chg_read8(CHARGER_PRIMARY, SM5803_REG_LOG1, ®val); - if (!(regval & SM5803_BATFET_ON) && !attempt_bfet_enable) { - CPRINTS("SM5803: Attempting to turn on BFET"); - cflush(); - rv |= sm5803_flow1_update(CHARGER_PRIMARY, - SM5803_FLOW1_LINEAR_CHARGE_EN, - MASK_SET); - rv |= sm5803_flow1_update(CHARGER_PRIMARY, - SM5803_FLOW1_LINEAR_CHARGE_EN, - MASK_CLR); - attempt_bfet_enable = 1; - sm5803_vbus_sink_enable(chgnum, 1); - } - /* There's no need to attempt it if the BFET's already on. */ - if (regval & SM5803_BATFET_ON) - attempt_bfet_enable = 1; - } - - return rv; -} - -static enum ec_error_list sm5803_discharge_on_ac(int chgnum, int enable) -{ - enum ec_error_list rv = EC_SUCCESS; - - if (enable) { - rv = sm5803_vbus_sink_enable(chgnum, 0); - } else { - if (chgnum == charge_manager_get_active_charge_port()) - rv = sm5803_vbus_sink_enable(chgnum, 1); - } - - return rv; -} - -static enum ec_error_list sm5803_get_vbus_voltage(int chgnum, int port, - int *voltage) -{ - enum ec_error_list rv; - int reg; - int volt_bits; - - rv = meas_read8(chgnum, SM5803_REG_VBUS_MEAS_MSB, ®); - if (rv) - return rv; - - volt_bits = reg << 2; - - rv = meas_read8(chgnum, SM5803_REG_VBUS_MEAS_LSB, ®); - - volt_bits |= reg & SM5803_VBUS_MEAS_LSB; - - /* Vbus ADC is in 23.4 mV steps */ - *voltage = (volt_bits * 234) / 10; - return rv; -} - -static enum ec_error_list sm5803_set_input_current_limit(int chgnum, - int input_current) -{ - int reg; - - reg = SM5803_CURRENT_TO_REG(input_current) & SM5803_CHG_ILIM_RAW; - - return chg_write8(chgnum, SM5803_REG_CHG_ILIM, reg); -} - -static enum ec_error_list sm5803_get_input_current_limit(int chgnum, - int *input_current) -{ - int rv; - int val; - - rv = chg_read8(chgnum, SM5803_REG_CHG_ILIM, &val); - if (rv) - return rv; - - *input_current = SM5803_REG_TO_CURRENT(val & SM5803_CHG_ILIM_RAW); - return rv; -} - -static enum ec_error_list sm5803_get_input_current(int chgnum, - int *input_current) -{ - enum ec_error_list rv; - int reg; - int curr; - - rv = meas_read8(chgnum, SM5803_REG_IBUS_CHG_MEAS_MSB, ®); - if (rv) - return rv; - curr = reg << 2; - - rv = meas_read8(chgnum, SM5803_REG_IBUS_CHG_MEAS_LSB, ®); - if (rv) - return rv; - curr |= reg & 0x3; - - /* The LSB is 7.32mA */ - *input_current = curr * 732 / 100; - return EC_SUCCESS; -} - -static enum ec_error_list sm5803_get_option(int chgnum, int *option) -{ - enum ec_error_list rv; - uint32_t control; - int reg; - - rv = chg_read8(chgnum, SM5803_REG_FLOW1, ®); - control = reg; - - rv |= chg_read8(chgnum, SM5803_REG_FLOW2, ®); - control |= reg << 8; - - rv |= chg_read8(chgnum, SM5803_REG_FLOW3, ®); - control |= reg << 16; - - return rv; -} - -enum ec_error_list sm5803_is_acok(int chgnum, bool *acok) -{ - int rv; - int reg, vbus_mv; - - rv = main_read8(chgnum, SM5803_REG_STATUS1, ®); - - if (rv) - return rv; - - /* If we're not sinking, then AC can't be OK. */ - if (!(reg & SM5803_STATUS1_CHG_DET)) { - *acok = false; - return EC_SUCCESS; - } - - /* - * Okay, we're sinking. Check that VBUS has some voltage. This - * should indicate that the path is good. - */ - rv = charger_get_vbus_voltage(chgnum, &vbus_mv); - - if (rv) - return rv; - - /* Assume that ACOK would be asserted if VBUS is higher than ~4V. */ - *acok = vbus_mv >= 4000; - - return EC_SUCCESS; -} - -static enum ec_error_list sm5803_is_input_current_limit_reached(int chgnum, - bool *reached) -{ - enum ec_error_list rv; - int reg; - - rv = chg_read8(chgnum, SM5803_REG_LOG2, ®); - if (rv) - return rv; - - *reached = (reg & SM5803_ISOLOOP_ON) ? true : false; - - return EC_SUCCESS; -} - -static enum ec_error_list sm5803_set_option(int chgnum, int option) -{ - enum ec_error_list rv; - int reg; - - mutex_lock(&flow1_access_lock[chgnum]); - - reg = option & 0xFF; - rv = chg_write8(chgnum, SM5803_REG_FLOW1, reg); - - mutex_unlock(&flow1_access_lock[chgnum]); - if (rv) - return rv; - - reg = (option >> 8) & 0xFF; - rv = chg_write8(chgnum, SM5803_REG_FLOW2, reg); - if (rv) - return rv; - - reg = (option >> 16) & 0xFF; - rv = chg_write8(chgnum, SM5803_REG_FLOW3, reg); - - return rv; -} - -static enum ec_error_list sm5803_set_otg_current_voltage(int chgnum, - int output_current, - int output_voltage) -{ - enum ec_error_list rv; - int reg; - - rv = chg_read8(chgnum, SM5803_REG_DISCH_CONF5, ®); - if (rv) - return rv; - - reg &= ~SM5803_DISCH_CONF5_CLS_LIMIT; - reg |= MIN((output_current / SM5803_CLS_CURRENT_STEP), - SM5803_DISCH_CONF5_CLS_LIMIT); - rv |= chg_write8(chgnum, SM5803_REG_DISCH_CONF5, reg); - - reg = SM5803_VOLTAGE_TO_REG(output_voltage); - rv = chg_write8(chgnum, SM5803_REG_VPWR_MSB, (reg >> 3)); - rv |= chg_write8(chgnum, SM5803_REG_DISCH_CONF2, - reg & SM5803_DISCH_CONF5_VPWR_LSB); - - return rv; -} - -static enum ec_error_list sm5803_enable_otg_power(int chgnum, int enabled) -{ - enum ec_error_list rv; - int reg, status; - - if (enabled) { - int selected_current; - - rv = chg_read8(chgnum, SM5803_REG_ANA_EN1, ®); - if (rv) - return rv; - - /* Enable current limit */ - reg &= ~SM5803_ANA_EN1_CLS_DISABLE; - rv = chg_write8(chgnum, SM5803_REG_ANA_EN1, reg); - - /* Disable ramps on current set in discharge */ - rv |= chg_read8(chgnum, SM5803_REG_DISCH_CONF6, ®); - reg |= SM5803_DISCH_CONF6_RAMPS_DIS; - rv |= chg_write8(chgnum, SM5803_REG_DISCH_CONF6, reg); - - /* - * In order to ensure the Vbus output doesn't overshoot too - * much, turn the starting voltage down to 4.8 V and ramp up - * after 4 ms - */ - rv = chg_read8(chgnum, SM5803_REG_DISCH_CONF5, ®); - if (rv) - return rv; - - selected_current = (reg & SM5803_DISCH_CONF5_CLS_LIMIT) * - SM5803_CLS_CURRENT_STEP; - sm5803_set_otg_current_voltage(chgnum, selected_current, 4800); - - /* - * Enable: SOURCE_MODE - enable sourcing out - * DIRECTCHG_SOURCE_EN - enable current loop - * (for designs with no external Vbus FET) - */ - rv = sm5803_flow1_update(chgnum, CHARGER_MODE_SOURCE | - SM5803_FLOW1_DIRECTCHG_SRC_EN, - MASK_SET); - usleep(4000); - - sm5803_set_otg_current_voltage(chgnum, selected_current, 5000); - } else { - /* Always clear out discharge status before clearing FLOW1 */ - rv = chg_read8(chgnum, SM5803_REG_STATUS_DISCHG, &status); - if (rv) - return rv; - - if (status) - CPRINTS("%s %d: Discharge failure 0x%02x", CHARGER_NAME, - chgnum, status); - - rv |= chg_write8(chgnum, SM5803_REG_STATUS_DISCHG, status); - - /* Re-enable ramps on current set in discharge */ - rv |= chg_read8(chgnum, SM5803_REG_DISCH_CONF6, ®); - reg &= ~SM5803_DISCH_CONF6_RAMPS_DIS; - rv |= chg_write8(chgnum, SM5803_REG_DISCH_CONF6, reg); - - /* - * PD tasks will always turn off previous sourcing on init. - * Protect ourselves from brown out on init by checking if we're - * sinking right now. The init process should only leave sink - * mode enabled if a charger is plugged in; otherwise it's - * expected to be 0. - * - * Always clear out sourcing if the previous source-out failed. - */ - rv |= chg_read8(chgnum, SM5803_REG_FLOW1, ®); - if (rv) - return rv; - - if ((reg & SM5803_FLOW1_MODE) != CHARGER_MODE_SINK || status) - rv = sm5803_flow1_update(chgnum, CHARGER_MODE_SOURCE | - SM5803_FLOW1_DIRECTCHG_SRC_EN, - MASK_CLR); - } - - return rv; -} - -static int sm5803_is_sourcing_otg_power(int chgnum, int port) -{ - enum ec_error_list rv; - int reg; - - rv = chg_read8(chgnum, SM5803_REG_FLOW1, ®); - if (rv) - return 0; - - /* - * Note: In linear mode, MB charger will read a reserved mode when - * sourcing, so bit 1 is the most reliable way to detect sourcing. - */ - return (reg & BIT(1)); -} - -static enum ec_error_list sm5803_set_vsys_compensation(int chgnum, - struct ocpc_data *ocpc, - int current_ma, - int voltage_mv) -{ - - int rv; - int regval; - int r; - - /* Set IR drop compensation */ - r = ocpc->combined_rsys_rbatt_mo * 100 / 167; /* 1.67mOhm steps */ - r = MAX(0, r); - rv = chg_write8(chgnum, SM5803_REG_IR_COMP2, r & 0x7F); - rv |= chg_read8(chgnum, SM5803_REG_IR_COMP1, ®val); - regval &= ~SM5803_IR_COMP_RES_SET_MSB; - r = r >> 8; /* Bits 9:8 */ - regval |= (r & 0x3) << SM5803_IR_COMP_RES_SET_MSB_SHIFT; - regval |= SM5803_IR_COMP_EN; - rv |= chg_write8(chgnum, SM5803_REG_IR_COMP1, regval); - - if (rv) - return EC_ERROR_UNKNOWN; - - return EC_ERROR_UNIMPLEMENTED; -} - -/* Hardware current ramping (aka DPM: Dynamic Power Management) */ - -#ifdef CONFIG_CHARGE_RAMP_HW -static enum ec_error_list sm5803_set_hw_ramp(int chgnum, int enable) -{ - enum ec_error_list rv; - int reg; - - rv = chg_read8(chgnum, SM5803_REG_CHG_MON_REG, ®); - - if (enable) - reg |= SM5803_DPM_LOOP_EN; - else - reg &= ~SM5803_DPM_LOOP_EN; - - rv |= chg_write8(chgnum, SM5803_REG_CHG_MON_REG, reg); - - return rv; -} - -static int sm5803_ramp_is_stable(int chgnum) -{ - /* - * There is no way to read current limit that the ramp has - * settled on with sm5803, so we don't consider the ramp stable, - * because we never know what the stable limit is. - */ - return 0; -} - -static int sm5803_ramp_is_detected(int chgnum) -{ - return 1; -} - -static int sm5803_ramp_get_current_limit(int chgnum) -{ - int rv; - int input_current = 0; - - rv = sm5803_get_input_current_limit(chgnum, &input_current); - - return rv ? -1 : input_current; -} -#endif /* CONFIG_CHARGE_RAMP_HW */ - -#ifdef CONFIG_CMD_CHARGER_DUMP -static int command_sm5803_dump(int argc, char **argv) -{ - int reg; - int regval; - int chgnum = 0; - - if (argc > 1) - chgnum = atoi(argv[1]); - - /* Dump base regs */ - ccprintf("BASE regs\n"); - for (reg = 0x01; reg <= 0x30; reg++) { - if (!main_read8(chgnum, reg, ®val)) - ccprintf("[0x%02X] = 0x%02x\n", reg, regval); - if (reg & 0xf) { - cflush(); /* Flush periodically */ - watchdog_reload(); - } - } - - /* Dump measure regs */ - ccprintf("MEAS regs\n"); - for (reg = 0x01; reg <= 0xED; reg++) { - if (!meas_read8(chgnum, reg, ®val)) - ccprintf("[0x%02X] = 0x%02x\n", reg, regval); - if (reg & 0xf) { - cflush(); /* Flush periodically */ - watchdog_reload(); - } - } - - /* Dump Charger regs from 0x1C to 0x7F */ - ccprintf("CHG regs\n"); - for (reg = 0x1C; reg <= 0x7F; reg++) { - if (!chg_read8(chgnum, reg, ®val)) - ccprintf("[0x%02X] = 0x%02x\n", reg, regval); - if (reg & 0xf) { - cflush(); /* Flush periodically */ - watchdog_reload(); - } - } - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(charger_dump, command_sm5803_dump, - "charger_dump [chgnum]", "Dumps SM5803 registers"); -#endif /* CONFIG_CMD_CHARGER_DUMP */ - -const struct charger_drv sm5803_drv = { - .init = &sm5803_init, - .post_init = &sm5803_post_init, - .get_info = &sm5803_get_info, - .get_status = &sm5803_get_status, - .set_mode = &sm5803_set_mode, - .get_actual_current = &sm5803_get_actual_current, - .get_current = &sm5803_get_current, - .set_current = &sm5803_set_current, - .get_actual_voltage = &sm5803_get_actual_voltage, - .get_voltage = &sm5803_get_voltage, - .set_voltage = &sm5803_set_voltage, - .discharge_on_ac = &sm5803_discharge_on_ac, - .get_vbus_voltage = &sm5803_get_vbus_voltage, - .set_input_current_limit = &sm5803_set_input_current_limit, - .get_input_current_limit = &sm5803_get_input_current_limit, - .get_input_current = &sm5803_get_input_current, - .device_id = &sm5803_get_dev_id, - .get_option = &sm5803_get_option, - .set_option = &sm5803_set_option, - .set_otg_current_voltage = &sm5803_set_otg_current_voltage, - .enable_otg_power = &sm5803_enable_otg_power, - .is_sourcing_otg_power = &sm5803_is_sourcing_otg_power, - .set_vsys_compensation = &sm5803_set_vsys_compensation, - .is_icl_reached = &sm5803_is_input_current_limit_reached, - .enable_linear_charge = &sm5803_enable_linear_charge, -#ifdef CONFIG_CHARGE_RAMP_HW - .set_hw_ramp = &sm5803_set_hw_ramp, - .ramp_is_stable = &sm5803_ramp_is_stable, - .ramp_is_detected = &sm5803_ramp_is_detected, - .ramp_get_current_limit = &sm5803_ramp_get_current_limit, -#endif -}; diff --git a/driver/charger/sm5803.h b/driver/charger/sm5803.h deleted file mode 100644 index b7638411e4..0000000000 --- a/driver/charger/sm5803.h +++ /dev/null @@ -1,432 +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. - * - * Silicon Mitus SM5803 Buck-Boost Charger - */ - -#ifndef __CROS_EC_SM5803_H -#define __CROS_EC_SM5803_H - -#include "common.h" - -/* Note: configure charger struct with CHARGER_FLAGS */ -#define SM5803_ADDR_MAIN_FLAGS 0x30 -#define SM5803_ADDR_MEAS_FLAGS 0x31 -#define SM5803_ADDR_CHARGER_FLAGS 0x32 -#define SM5803_ADDR_TEST_FLAGS 0x37 - -/* Main registers (address 0x30) */ - -#define SM5803_REG_CHIP_ID 0x00 - -#define SM5803_REG_STATUS1 0x01 -#define SM5803_STATUS1_VSYS_OK BIT(0) -#define SM5803_STATUS1_VPWR_OK BIT(1) -#define SM5803_STATUS1_VBUS_UVL BIT(3) -#define SM5803_STATUS1_VBUS_SHORT BIT(4) -#define SM5803_STATUS1_VBUS_OVH BIT(5) -#define SM5803_STATUS1_CHG_DET BIT(6) -#define SM5803_STATUS1_BAT_DET BIT(7) - -#define SM5803_REG_STATUS2 0x02 -#define SM5803_STATUS2_BAT_DET_FG BIT(1) -#define SM5803_STATUS2_VBAT_SHORT BIT(0) - -#define SM5803_REG_INT1_REQ 0x05 -#define SM5803_REG_INT1_EN 0x0A -#define SM5803_INT1_VBUS_PWR_HWSAFE_LIMIT BIT(0) -#define SM5803_INT1_CHG BIT(2) -#define SM5803_INT1_BAT BIT(3) -#define SM5803_INT1_CLS_OC BIT(4) -#define SM5803_INT1_SLV_DET BIT(5) -#define SM5803_INT1_SWL_DISCH BIT(6) -#define SM5803_INT1_PREREG BIT(7) - -#define SM5803_REG_INT2_REQ 0x06 -#define SM5803_REG_INT2_EN 0x0B -#define SM5803_INT2_VBATSNSP BIT(0) -#define SM5803_INT2_IBAT_DISCHG BIT(1) -#define SM5803_INT2_IBAT_CHG BIT(2) -#define SM5803_INT2_IBUS BIT(3) -#define SM5803_INT2_VBUS BIT(4) -#define SM5803_INT2_VCHGPWR BIT(5) -#define SM5803_INT2_VSYS BIT(6) -#define SM5803_INT2_TINT BIT(7) - -#define SM5803_REG_INT3_REQ 0x07 -#define SM5803_REG_INT3_EN 0x0C -#define SM5803_INT3_GPADC0 BIT(0) -#define SM5803_INT3_BFET_PWR_LIMIT BIT(1) -#define SM5803_INT3_BFET_PWR_HWSAFE_LIMIT BIT(2) -#define SM5803_INT3_SPARE BIT(3) -#define SM5803_INT3_VBUS_PWR_LIMIT BIT(4) -#define SM5803_INT3_IBAT BIT(5) - -#define SM5803_REG_INT4_REQ 0x08 -#define SM5803_REG_INT4_EN 0x0D -#define SM5803_INT4_CHG_FAIL BIT(0) -#define SM5803_INT4_CHG_DONE BIT(1) -#define SM5803_INT4_CHG_START BIT(2) -#define SM5803_INT4_SLP_EXIT BIT(3) -#define SM5803_INT4_OTG_FAIL BIT(4) -#define SM5803_INT4_CHG_ILIM BIT(5) -#define SM5803_INT4_IBAT_CC BIT(6) -#define SM5803_INT4_CC BIT(7) - -#define SM5803_REG_MISC_CONFIG 0x15 -#define SM5803_MISC_INV_INT BIT(0) -#define SM5803_INT_CLEAR_MODE BIT(1) -#define SM5803_INT_MASK_MODE BIT(2) - -#define SM5803_REG_PLATFORM 0x18 -#define SM5803_PLATFORM_ID GENMASK(4, 0) - -#define SM5803_REG_REFERENCE 0x20 -#define SM5803_REFERENCE_LDO3P3_PGOOD BIT(4) -#define SM5803_REFERENCE_LDO5_PGOOD BIT(5) - -#define SM5803_REG_CLOCK_SEL 0x2A -#define SM5803_CLOCK_SEL_LOW BIT(0) - -#define SM5803_REG_GPIO0_CTRL 0x30 -#define SM5803_GPIO0_VAL BIT(0) -#define SM5803_GPIO0_MODE_MASK GENMASK(2, 1) -#define SM5803_GPIO0_OPEN_DRAIN_EN BIT(6) -#define SM5803_CHG_DET_OPEN_DRAIN_EN BIT(7) - -#define SM5803_REG_VBATSNSP_MEAS_MSB 0x40 -#define SM5803_REG_VBATSNSP_MEAS_LSB 0x41 - -enum sm5803_gpio0_modes { - GPIO0_MODE_PROCHOT, - GPIO0_MODE_OUTPUT, - GPIO0_MODE_INPUT -}; - -#define SM5803_REG_BFET_PWR_MAX_TH 0x35 -#define SM5803_REG_BFET_PWR_HWSAFE_MAX_TH 0x36 - -#define SM5803_REG_PORTS_CTRL 0x40 -#define SM5803_PORTS_VBUS_DISCH BIT(0) -#define SM5803_PORTS_VBUS_PULLDOWN BIT(1) -#define SM5803_PORTS_VBUS_SNS_DISCH BIT(2) -#define SM5803_PORTS_VBUS_SNS_PULLDOWN BIT(3) - -/* ADC Registers (address 0x31) */ - -/* - * Note: Some register bits must be enabled for the DC-DC converter to properly - * handle transitions. - */ -#define SM5803_REG_GPADC_CONFIG1 0x01 -#define SM5803_GPADCC1_VBATSNSP_EN BIT(0) -#define SM5803_GPADCC1_IBAT_DIS_EN BIT(1) -#define SM5803_GPADCC1_IBAT_CHG_EN BIT(2) -#define SM5803_GPADCC1_IBUS_EN BIT(3) -#define SM5803_GPADCC1_VBUS_EN BIT(4) -#define SM5803_GPADCC1_VCHGPWR_EN BIT(5) /* NOTE: DO NOT CLEAR */ -#define SM5803_GPADCC1_VSYS_EN BIT(6) /* NOTE: DO NOT CLEAR */ -#define SM5803_GPADCC1_TINT_EN BIT(7) - -#define SM5803_REG_GPADC_CONFIG2 0x02 - -#define SM5803_REG_PSYS1 0x04 -#define SM5803_PSYS1_DAC_EN BIT(0) - -/* Note: Threshold registers all assume lower 2 bits are 0 */ -#define SM5803_REG_VBUS_LOW_TH 0x1A -#define SM5803_REG_VBATSNSP_MAX_TH 0x26 -#define SM5803_REG_VBUS_HIGH_TH 0x2A -#define SM5803_REG_VCHG_PWR_LOW_TH 0x1B -#define SM5803_REG_VCHG_PWR_HIGH_TH 0x2B -#define SM5803_REG_TINT_LOW_TH 0x1D -#define SM5803_REG_TINT_HIGH_TH 0x2D - -/* - * Vbus levels increment in 23.4 mV, set thresholds to below 3.5V and above 4.0V - * to mirror what TCPCI uses for Vbus present indication - */ -#define SM5803_VBUS_LOW_LEVEL 0x25 -#define SM5803_VBUS_HIGH_LEVEL 0x2C - - - -/* - * TINT thresholds. TINT steps are in 0.43 K with the upper threshold set to - * 360 K and lower threshold to de-assert PROCHOT at 330 K. - */ -#define SM5803_TINT_LOW_LEVEL 0xBF -#define SM5803_TINT_HIGH_LEVEL 0xD1 - -#define SM5803_TINT_MAX_LEVEL 0xFF -#define SM5803_TINT_MIN_LEVEL 0x00 - -/* - * Set minimum thresholds for VBUS_PWR_LOW_TH interrupt generation - * 2S battery 9.4v - * 3S battery 14.1V VBUS_PWR MIN TH - */ -#define SM5803_VBAT_PWR_MINTH_3S_LEVEL 0x9B -#define SM5803_VBAT_PWR_MINTH_2S_LEVEL 0x9B - -/* - * Set thresholds for VBATSNSP_MAX_TH GPADC interrupt generation - * 2S battery 9v - * 3S battery 13.3V - */ -#define SM5803_VBAT_SNSP_MAXTH_3S_LEVEL 0xD8 -#define SM5803_VBAT_SNSP_MAXTH_2S_LEVEL 0xDC - -/* IBAT levels - The IBAT levels increment in 7.32mA */ -#define SM5803_REG_IBAT_CHG_MEAS_MSB 0x44 -#define SM5803_REG_IBAT_CHG_MEAS_LSB 0x45 -#define SM5803_REG_IBAT_CHG_AVG_MEAS_MSB 0xC4 -#define SM5803_REG_IBAT_CHG_AVG_MEAS_LSB 0xC5 -#define SM5803_IBAT_CHG_MEAS_LSB GENMASK(1, 0) - -/* IBUS levels - The IBUS levels increment in 7.32mA */ -#define SM5803_REG_IBUS_CHG_MEAS_MSB 0x46 -#define SM5803_REG_IBUS_CHG_MEAS_LSB 0x47 -#define SM5803_IBUS_CHG_MEAS_LSB GENMASK(1, 0) - -#define SM5803_REG_VBUS_MEAS_MSB 0x48 -#define SM5803_REG_VBUS_MEAS_LSB 0x49 -#define SM5803_VBUS_MEAS_LSB GENMASK(1, 0) -#define SM5803_VBUS_MEAS_BAT_DET BIT(2) -#define SM5803_VBUS_MEAS_VBUS_SHORT BIT(4) -#define SM5803_VBUS_MEAS_OV_TEMP BIT(5) -#define SM5803_VBUS_MEAS_CHG_DET BIT(6) - -/* VCHGPWR levels - The VCHGPWR levels increment in 23.4mV steps. */ -#define SM5803_REG_VCHG_PWR_MSB 0x4A - -#define SM5803_REG_TINT_MEAS_MSB 0x4E - -/* VSYS levels - The VSYS levels increment in 23.4mV steps. */ -#define SM5803_REG_VSYS_MEAS_MSB 0x4C -#define SM5803_REG_VSYS_MEAS_LSB 0x4D -#define SM5803_REG_VSYS_AVG_MEAS_MSB 0xCC -#define SM5803_REG_VSYS_AVG_MEAS_LSB 0xCD -#define SM5803_VSYS_MEAS_LSB GENMASK(1, 0) - -/* Charger registers (address 0x32) */ - -#define SM5803_REG_CC_CONFIG1 0x01 -#define SM5803_CC_CONFIG1_SD_PWRUP BIT(3) - -#define SM5803_REG_FLOW1 0x1C -#define SM5803_FLOW1_MODE GENMASK(1, 0) -#define SM5803_FLOW1_DIRECTCHG_SRC_EN BIT(2) -#define SM5803_FLOW1_LINEAR_CHARGE_EN BIT(3) -#define SM5803_FLOW1_USB_SUSP BIT(7) - -enum sm5803_charger_modes { - CHARGER_MODE_DISABLED, - CHARGER_MODE_SINK, - CHARGER_MODE_RESERVED, - CHARGER_MODE_SOURCE, -}; - -#define SM5803_REG_FLOW2 0x1D -#define SM5803_FLOW2_AUTO_TRKL_EN BIT(0) -#define SM5803_FLOW2_AUTO_PRECHG_EN BIT(1) -#define SM5803_FLOW2_AUTO_FASTCHG_EN BIT(2) -#define SM5803_FLOW2_AUTO_ENABLED GENMASK(2, 0) -#define SM5803_FLOW2_FW_TRKL_CMD BIT(3) -#define SM5803_FLOW2_FW_PRECHG_CMD BIT(4) -#define SM5803_FLOW2_FW_FASTCHG_CMD BIT(5) -#define SM5803_FLOW2_HOST_MODE_EN BIT(6) -#define SM5803_FLOW2_AUTO_CHGEN_SET BIT(7) - -#define SM5803_REG_FLOW3 0x1E -#define SM5803_FLOW3_SWITCH_BCK_BST BIT(0) -#define SM5803_FLOW3_FW_SWITCH_RESUME BIT(1) -#define SM5803_FLOW3_FW_SWITCH_PAUSE BIT(2) -#define SM5803_FLOW3_SOFT_DISABLE_EN BIT(3) - -#define SM5803_REG_SWITCHER_CONF 0x1F -#define SM5803_SW_BCK_BST_CONF_AUTO BIT(0) - -#define SM5803_REG_ANA_EN1 0x21 -#define SM5803_ANA_EN1_CLS_DISABLE BIT(7) - -/* - * Input current limit is CHG_ILIM_RAW *100 mA - */ -#define SM5803_REG_CHG_ILIM 0x24 -#define SM5803_CHG_ILIM_RAW GENMASK(4, 0) -#define SM5803_CURRENT_STEP 100 -#define SM5803_REG_TO_CURRENT(r) ((r) * SM5803_CURRENT_STEP) -#define SM5803_CURRENT_TO_REG(c) ((c) / SM5803_CURRENT_STEP) - -/* - * DPM Voltage loop regulation contains the 8 bits with MSB register - * and the lower 3 bits with LSB register. - * The regulation value is 2.72 V + DPM_VL_SET * 10mV - */ -#define SM5803_REG_DPM_VL_SET_MSB 0x26 -#define SM5803_REG_DPM_VL_SET_LSB 0x27 - -/* - * Output voltage uses the same equation as Vsys - * Lower saturation value is 3 V, upper 20.5 V - */ -#define SM5803_REG_VPWR_MSB 0x30 -#define SM5803_REG_DISCH_CONF2 0x31 -#define SM5803_DISCH_CONF5_VPWR_LSB GENMASK(2, 0) - -/* - * Output current limit is CLS_LIMIT * 50 mA and saturates to 3.2 A - */ -#define SM5803_REG_DISCH_CONF5 0x34 -#define SM5803_DISCH_CONF5_CLS_LIMIT GENMASK(6, 0) -#define SM5803_CLS_CURRENT_STEP 50 - -#define SM5803_REG_DISCH_CONF6 0x35 -#define SM5803_DISCH_CONF6_RAMPS_DIS BIT(0) -#define SM5803_DISCH_CONF6_SMOOTH_DIS BIT(1) - -/* - * Vsys is 11 bits, with the lower 3 bits in the LSB register. - * The pre-regulation value is 2.72 V + Vsys_prereg * 10 mV - * Lower saturation value is 3V, upper is 20V - */ -#define SM5803_REG_VSYS_PREREG_MSB 0x36 -#define SM5803_REG_VSYS_PREREG_LSB 0x37 -#define SM5803_VOLTAGE_STEP 10 -#define SM5803_VOLTAGE_SHIFT 2720 -#define SM5803_REG_TO_VOLTAGE(r) (SM5803_VOLTAGE_SHIFT + \ - (r) * SM5803_VOLTAGE_STEP) -#define SM5803_VOLTAGE_TO_REG(v) (((v) - SM5803_VOLTAGE_SHIFT) \ - / SM5803_VOLTAGE_STEP) - -/* - * Precharge Termination threshold. - */ -#define SM5803_REG_PRE_FAST_CONF_REG1 0x39 -#define SM5803_VBAT_PRE_TERM_MIN_DV 23 -/* 3.8V+ gets rounded to 4V */ -#define SM5803_VBAT_PRE_TERM_MAX_DV 38 -#define SM5803_VBAT_PRE_TERM GENMASK(7, 4) -#define SM5803_VBAT_PRE_TERM_SHIFT 4 - -/* - * Vbat for fast charge uses the same equation as Vsys - * Lower saturation value is 3V, upper is dependent on number of cells - */ -#define SM5803_REG_VBAT_FAST_MSB 0x3A -#define SM5803_REG_VBAT_FAST_LSB 0x3B - -/* - * Fast charge current limit is ICHG_FAST * 100 mA - * Value read back may be adjusted if tempearture limits are exceeded - */ -#define SM5803_REG_FAST_CONF4 0x3C -#define SM5803_CONF4_ICHG_FAST GENMASK(5, 0) - -/* Fast charge Termination */ -#define SM5803_REG_FAST_CONF5 0x3D -#define SM5803_CONF5_IBAT_EOC_TH GENMASK(3, 0) - -/* IR drop compensation */ -#define SM5803_REG_IR_COMP1 0x3F -#define SM5803_IR_COMP_RES_SET_MSB GENMASK(7, 6) -#define SM5803_IR_COMP_RES_SET_MSB_SHIFT 6 -#define SM5803_IR_COMP_EN BIT(5) - -/* LSB is in 1.67mOhm steps. */ -#define SM5803_REG_IR_COMP2 0x40 - -/* Precharge current limit is also intervals of 100 mA */ -#define SM5803_REG_PRECHG 0x41 -#define SM5803_PRECHG_ICHG_PRE_SET GENMASK(5, 0) - -#define SM5803_REG_LOG1 0x42 -#define SM5803_BATFET_ON BIT(2) - -#define SM5803_REG_LOG2 0x43 -#define SM5803_ISOLOOP_ON BIT(1) - -#define SM5803_REG_STATUS_CHG_REG 0x48 -#define SM5803_STATUS_CHG_BATT_REMOVAL BIT(0) -#define SM5803_STATUS_CHG_CHG_REMOVAL BIT(1) -#define SM5803_STATUS_CHG_BATTEMP_NOK BIT(2) -#define SM5803_STATUS_CHG_CHGWDG_EXP BIT(3) -#define SM5803_STATUS_CHG_VBUS_OC BIT(4) -#define SM5803_STATUS_CHG_OV_VBAT BIT(5) -#define SM5803_STATUS_CHG_TIMEOUT BIT(6) -#define SM5803_STATUS_CHG_OV_ITEMP BIT(7) - -#define SM5803_REG_STATUS_DISCHG 0x49 -#define SM5803_STATUS_DISCHG_BATT_REM BIT(0) -#define SM5803_STATUS_DISCHG_UV_VBAT BIT(1) -#define SM5803_STATUS_DISCHG_VBUS_OC BIT(2) -#define SM5803_STATUS_DISCHG_VBUS_PWR GENMASK(4, 3) -#define SM5803_STATUS_DISCHG_ISO_CURR BIT(5) -#define SM5803_STATUS_DISCHG_VBUS_SHORT BIT(6) -#define SM5803_STATUS_DISCHG_OV_ITEMP BIT(7) - -#define SM5803_REG_CHG_MON_REG 0x5C -#define SM5803_DPM_LOOP_EN BIT(0) - -#define SM5803_REG_PHOT1 0x72 -#define SM5803_PHOT1_IBAT_PHOT_COMP_EN BIT(0) -#define SM5803_PHOT1_IBUS_PHOT_COMP_EN BIT(1) -#define SM5803_PHOT1_VSYS_MON_EN BIT(2) -#define SM5803_PHOT1_VBUS_MON_EN BIT(3) -#define SM5803_PHOT1_COMPARATOR_EN GENMASK(3, 0) -#define SM5803_PHOT1_DURATION GENMASK(6, 4) -#define SM5803_PHOT1_DURATION_SHIFT 4 -#define SM5803_PHOT1_IRQ_MODE BIT(7) - -#define CHARGER_NAME "sm5803" - -#define CHARGE_V_MAX 20000 -#define CHARGE_V_MIN SM5803_VOLTAGE_SHIFT -#define CHARGE_V_STEP SM5803_VOLTAGE_STEP - -#define CHARGE_I_MAX 6300 -#define CHARGE_I_MIN 0 -#define CHARGE_I_STEP SM5803_CURRENT_STEP - -#define INPUT_I_MAX 3100 -#define INPUT_I_MIN 0 -#define INPUT_I_STEP SM5803_CURRENT_STEP - -/* Expose cached Vbus presence */ -int sm5803_is_vbus_present(int chgnum); - -/* Expose functions to control charger's GPIO and CHG_DET configuration */ -enum ec_error_list sm5803_configure_gpio0(int chgnum, - enum sm5803_gpio0_modes mode, int od); -enum ec_error_list sm5803_set_gpio0_level(int chgnum, int level); -enum ec_error_list sm5803_configure_chg_det_od(int chgnum, int enable); -enum ec_error_list sm5803_get_chg_det(int chgnum, int *chg_det); - -/* Expose Vbus discharge function */ -enum ec_error_list sm5803_set_vbus_disch(int chgnum, int enable); -enum ec_error_list sm5803_vbus_sink_enable(int chgnum, int enable); - -void sm5803_hibernate(int chgnum); -void sm5803_interrupt(int chgnum); - -/** - * Return whether ACOK is high or low. - * - * @param chgnum index into chg_chips table. - * @param acok will be set to true if ACOK is asserted, otherwise false. - * @return EC_SUCCESS, error otherwise. - */ -enum ec_error_list sm5803_is_acok(int chgnum, bool *acok); - -/* Expose low power mode functions */ -void sm5803_disable_low_power_mode(int chgnum); -void sm5803_enable_low_power_mode(int chgnum); - -extern const struct charger_drv sm5803_drv; - -/* Expose interrupt handler for processing in PD_INT task when needed */ -void sm5803_handle_interrupt(int chgnum); - -#endif diff --git a/driver/charger/sy21612.c b/driver/charger/sy21612.c deleted file mode 100644 index 7bc6caa4ea..0000000000 --- a/driver/charger/sy21612.c +++ /dev/null @@ -1,213 +0,0 @@ -/* Copyright 2017 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. - * - * SILERGY SY21612 buck-boost converter driver. - */ - - -#include "console.h" -#include "hooks.h" -#include "i2c.h" -#include "sy21612.h" -#include "task.h" -#include "util.h" - -/* Console output macros */ -#define CPUTS(outstr) cputs(CC_CHARGER, outstr) -#define CPRINTF(format, args...) cprintf(CC_CHARGER, format, ## args) -#define CPRINTS(format, args...) cprints(CC_CHARGER, format, ## args) - -static int sy21612_clear_set_reg(int reg, int clear, int set) -{ - int val, old_val, rv; - - rv = i2c_read8(I2C_PORT_SY21612, SY21612_ADDR_FLAGS, reg, &old_val); - if (rv) - return rv; - - val = old_val; - val &= ~clear; - val |= set; - - if (val != old_val || clear || set) - rv = i2c_write8(I2C_PORT_SY21612, SY21612_ADDR_FLAGS, - reg, val); - - return rv; -} - -static int sy21612_read(int reg, int *val) -{ - return i2c_read8(I2C_PORT_SY21612, SY21612_ADDR_FLAGS, reg, val); -} - -int sy21612_enable_regulator(int enable) -{ - return enable ? - sy21612_clear_set_reg(SY21612_CTRL1, 0, SY21612_CTRL1_REG_EN) : - sy21612_clear_set_reg(SY21612_CTRL1, SY21612_CTRL1_REG_EN, 0); -} - -int sy21612_enable_adc(int enable) -{ - return enable ? - sy21612_clear_set_reg(SY21612_CTRL1, 0, SY21612_CTRL1_ADC_EN) : - sy21612_clear_set_reg(SY21612_CTRL1, SY21612_CTRL1_ADC_EN, 0); -} - -int sy21612_set_adc_mode(int auto_mode) -{ - return auto_mode ? - sy21612_clear_set_reg(SY21612_CTRL1, - 0, SY21612_CTRL1_ADC_AUTO_MODE) : - sy21612_clear_set_reg(SY21612_CTRL1, - SY21612_CTRL1_ADC_AUTO_MODE, 0); -} - -int sy21612_set_vbus_discharge(int auto_discharge) -{ - return auto_discharge ? - sy21612_clear_set_reg(SY21612_CTRL1, - SY21612_CTRL1_VBUS_NDISCHG, 0) : - sy21612_clear_set_reg(SY21612_CTRL1, - 0, SY21612_CTRL1_VBUS_NDISCHG); -} - -int sy21612_set_switching_freq(enum sy21612_switching_freq freq) -{ - return sy21612_clear_set_reg(SY21612_CTRL2, - SY21612_CTRL2_FREQ_MASK, - freq << SY21612_CTRL2_FREQ_SHIFT); -} - -int sy21612_set_vbus_volt(enum sy21612_vbus_volt volt) -{ - return sy21612_clear_set_reg(SY21612_CTRL2, - SY21612_CTRL2_VBUS_MASK, - volt << SY21612_CTRL2_VBUS_SHIFT); -} - -int sy21612_set_vbus_adj(enum sy21612_vbus_adj adj) -{ - return sy21612_clear_set_reg(SY21612_CTRL2, - SY21612_CTRL2_VBUS_ADJ_MASK, - adj << SY21612_CTRL2_VBUS_ADJ_SHIFT); -} - -int sy21612_set_sink_mode(int sink_mode) -{ - return sink_mode ? - sy21612_clear_set_reg(SY21612_PROT2, - 0, SY21612_PROT2_SINK_MODE) : - sy21612_clear_set_reg(SY21612_PROT2, - SY21612_PROT2_SINK_MODE, 0); -} - -int sy21612_is_power_good(void) -{ - int reg; - - if (sy21612_read(SY21612_STATE, ®)) - return 0; - - return reg & SY21612_STATE_POWER_GOOD; -} - -int sy21612_read_clear_int(void) -{ - int reg; - - if (sy21612_read(SY21612_INT, ®)) - return 0; - - return reg; -} - -int sy21612_get_vbat_voltage(void) -{ - int reg; - - if (sy21612_read(SY21612_VBAT_VOLT, ®)) - return 0; - - return reg * 25000 / 255; -} - -int sy21612_get_vbus_voltage(void) -{ - int reg; - - if (sy21612_read(SY21612_VBUS_VOLT, ®)) - return 0; - - return reg * 25000 / 255; -} - -int sy21612_get_vbus_current(void) -{ - int reg; - - if (sy21612_read(SY21612_VBUS_CURRENT, ®)) - return 0; - - /* - * delta V in range 0 ~ 67mV - * sense resistor 10 mOhm - */ - return reg * 6700 / 255; -} - -void sy21612_int(enum gpio_signal signal) -{ -#ifdef HAS_TASK_SY21612 - task_wake(TASK_ID_SY21612); -#endif -} - -#ifdef HAS_TASK_SY21612 -void sy21612_task(void *u) -{ - int flags; - - while (1) { - task_wait_event(-1); - if (sy21612_read(SY21612_INT, &flags)) - continue; - /* TODO: notify the error condition and enable regulator */ - if (flags & SY21612_INT_VBUS_OCP) - CPUTS("buck-boost VBUS OCP\n"); - if (flags & SY21612_INT_INDUCTOR_OCP) - CPUTS("buck-boost inductor OCP\n"); - if (flags & SY21612_INT_UVP) - CPUTS("buck-boost UVP\n"); - if (flags & SY21612_INT_OTP) - CPUTS("buck-boost OTP\n"); - } -} -#endif - -#ifdef CONFIG_CMD_CHARGER -static int command_sy21612(int argc, char **argv) -{ - int i, val, rv; - - ccputs("sy21612 regs:\n"); - for (i = 0; i < 9; i++) { - ccprintf("[%02x] ", i); - rv = sy21612_read(i, &val); - if (rv) - ccprintf(" x (%d)\n", rv); - else - ccprintf("%02x - %pb\n", val, BINARY_VALUE(val, 8)); - } - - ccprintf("vbat voltage: %d mV\n", sy21612_get_vbat_voltage()); - ccprintf("vbus voltage: %d mV\n", sy21612_get_vbus_voltage()); - ccprintf("vbus current: %d mA\n", sy21612_get_vbus_current()); - - return 0; -} -DECLARE_CONSOLE_COMMAND(sy21612, command_sy21612, - NULL, NULL); -#endif diff --git a/driver/charger/sy21612.h b/driver/charger/sy21612.h deleted file mode 100644 index befb8e6a35..0000000000 --- a/driver/charger/sy21612.h +++ /dev/null @@ -1,164 +0,0 @@ -/* Copyright 2017 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. - * - * SILERGY SY21612 buck-boost converter driver. - */ - -#ifndef __CROS_EC_SY21612_H -#define __CROS_EC_SY21612_H - -#include "gpio.h" - -#ifndef SY21612_ADDR_FLAGS -#define SY21612_ADDR_FLAGS 0x71 -#endif - -enum sy21612_switching_freq { - SY21612_FREQ_250KHZ = 0, - SY21612_FREQ_500KHZ, - SY21612_FREQ_750KHZ, - SY21612_FREQ_1MHZ -}; - -enum sy21612_vbus_volt { - SY21612_VBUS_5V = 2, - SY21612_VBUS_7V, - SY21612_VBUS_9V, - SY21612_VBUS_12V, - SY21612_VBUS_15V, - SY21612_VBUS_20V, -}; - -enum sy21612_vbus_adj { - SY21612_VBUS_M2_5 = 0, - SY21612_VBUS_M1_25, - SY21612_VBUS_0, - SY21612_VBUS_1_25, - SY21612_VBUS_2_5, - SY21612_VBUS_3_75, - SY21612_VBUS_5, -}; - -#define SY21612_CTRL1 0x00 -#define SY21612_CTRL1_REG_EN BIT(7) -#define SY21612_CTRL1_LOW_BAT_MASK (7 << 4) -#define SY21612_CTRL1_LOW_BAT_10_2V (0 << 4) -#define SY21612_CTRL1_LOW_BAT_10_7V BIT(4) -#define SY21612_CTRL1_LOW_BAT_11_2V (2 << 4) -#define SY21612_CTRL1_LOW_BAT_11_7V (3 << 4) -#define SY21612_CTRL1_LOW_BAT_22_0V (4 << 4) -#define SY21612_CTRL1_LOW_BAT_22_5V (5 << 4) -#define SY21612_CTRL1_LOW_BAT_23_0V (6 << 4) -#define SY21612_CTRL1_LOW_BAT_23_5V (7 << 4) -#define SY21612_CTRL1_ADC_EN BIT(3) -#define SY21612_CTRL1_ADC_AUTO_MODE BIT(2) -#define SY21612_CTRL1_VBUS_NDISCHG BIT(1) - -#define SY21612_CTRL2 0x01 -#define SY21612_CTRL2_FREQ_MASK (3 << 6) -#define SY21612_CTRL2_FREQ_SHIFT 6 -#define SY21612_CTRL2_FREQ_250K (0 << 6) -#define SY21612_CTRL2_FREQ_500K BIT(6) -#define SY21612_CTRL2_FREQ_750K (2 << 6) -#define SY21612_CTRL2_FREQ_1M (3 << 6) -#define SY21612_CTRL2_VBUS_MASK (7 << 3) -#define SY21612_CTRL2_VBUS_SHIFT 3 -#define SY21612_CTRL2_VBUS_5V (2 << 3) -#define SY21612_CTRL2_VBUS_7V (3 << 3) -#define SY21612_CTRL2_VBUS_9V (4 << 3) -#define SY21612_CTRL2_VBUS_12V (5 << 3) -#define SY21612_CTRL2_VBUS_15V (6 << 3) -#define SY21612_CTRL2_VBUS_20V (7 << 3) -#define SY21612_CTRL2_VBUS_ADJ_MASK 7 -#define SY21612_CTRL2_VBUS_ADJ_SHIFT 0 -#define SY21612_CTRL2_VBUS_ADJ_M2_5 0 -#define SY21612_CTRL2_VBUS_ADJ_M1_25 1 -#define SY21612_CTRL2_VBUS_ADJ_0 2 -#define SY21612_CTRL2_VBUS_ADJ_1_25 3 -#define SY21612_CTRL2_VBUS_ADJ_2_5 4 -#define SY21612_CTRL2_VBUS_ADJ_3_75 5 -#define SY21612_CTRL2_VBUS_ADJ_5 6 - -#define SY21612_PROT1 0x02 -#define SY21612_PROT1_I_THRESH_MASK (7 << 5) -#define SY21612_PROT1_I_THRESH_18MV (0 << 5) -#define SY21612_PROT1_I_THRESH_22MV BIT(5) -#define SY21612_PROT1_I_THRESH_27MV (2 << 5) -#define SY21612_PROT1_I_THRESH_31MV (3 << 5) -#define SY21612_PROT1_I_THRESH_36MV (4 << 5) -#define SY21612_PROT1_I_THRESH_45MV (5 << 5) -#define SY21612_PROT1_I_THRESH_54MV (6 << 5) -#define SY21612_PROT1_I_THRESH_64MV (7 << 5) -#define SY21612_PROT1_OVP_THRESH_MASK (3 << 3) -#define SY21612_PROT1_OVP_THRESH_110 (0 << 3) -#define SY21612_PROT1_OVP_THRESH_115 BIT(3) -#define SY21612_PROT1_OVP_THRESH_120 (2 << 3) -#define SY21612_PROT1_OVP_THRESH_125 (3 << 3) -#define SY21612_PROT1_UVP_THRESH_MASK (3 << 1) -#define SY21612_PROT1_UVP_THRESH_50 (0 << 1) -#define SY21612_PROT1_UVP_THRESH_60 BIT(1) -#define SY21612_PROT1_UVP_THRESH_70 (2 << 1) -#define SY21612_PROT1_UVP_THRESH_80 (3 << 1) - -#define SY21612_PROT2 0x03 -#define SY21612_PROT2_I_LIMIT_MASK (3 << 6) -#define SY21612_PROT2_I_LIMIT_6A (0 << 6) -#define SY21612_PROT2_I_LIMIT_8A (2 << 6) -#define SY21612_PROT2_I_LIMIT_10A (3 << 6) -#define SY21612_PROT2_OCP_AUTORECOVER BIT(5) -#define SY21612_PROT2_UVP_AUTORECOVER BIT(4) -#define SY21612_PROT2_OTP_AUTORECOVER BIT(3) -#define SY21612_PROT2_SINK_MODE BIT(2) - -#define SY21612_STATE 0x04 -#define SY21612_STATE_POWER_GOOD BIT(7) -#define SY21612_STATE_VBAT_LT_VBUS BIT(6) -#define SY21612_STATE_VBAT_LOW BIT(5) - -#define SY21612_INT 0x05 -#define SY21612_INT_ADC_READY BIT(7) -#define SY21612_INT_VBUS_OCP BIT(6) -#define SY21612_INT_INDUCTOR_OCP BIT(5) -#define SY21612_INT_UVP BIT(4) -#define SY21612_INT_OTP BIT(3) - -/* Battery voltage range: 0 ~ 25V */ -#define SY21612_VBAT_VOLT 0x06 - -/* VBUS voltage range: 0 ~ 25V */ -#define SY21612_VBUS_VOLT 0x07 - -/* Output current sense voltage range 0 ~ 67mV */ -#define SY21612_VBUS_CURRENT 0x08 - -/* Enable or disable the regulator */ -int sy21612_enable_regulator(int enable); -/* Enable internal adc */ -int sy21612_enable_adc(int enable); -/* Set ADC mode to single or auto */ -int sy21612_set_adc_mode(int auto_mode); -/* Enable VBUS auto discharge when regulator is disabled */ -int sy21612_set_vbus_discharge(int auto_discharge); -/* Set buck-boost switching frequency */ -int sy21612_set_switching_freq(enum sy21612_switching_freq freq); -/* Set VBUS output voltage */ -int sy21612_set_vbus_volt(enum sy21612_vbus_volt volt); -/* Adjust VBUS output voltage */ -int sy21612_set_vbus_adj(enum sy21612_vbus_adj adj); -/* Set bidirection mode */ -int sy21612_set_sink_mode(int sink_mode); -/* Get power good status */ -int sy21612_is_power_good(void); -/* Read and clear interrupt flags */ -int sy21612_read_clear_int(void); -/* Get VBUS voltage in mV */ -int sy21612_get_vbat_voltage(void); -/* Get VBUS voltage in mV */ -int sy21612_get_vbus_voltage(void); -/* Get VBUS current in mA */ -int sy21612_get_vbus_current(void); -/* Interrupt handler */ -void sy21612_int(enum gpio_signal signal); - -#endif /* __CROS_EC_SY21612_H */ diff --git a/driver/fingerprint/OWNERS b/driver/fingerprint/OWNERS deleted file mode 100644 index ba92c193e0..0000000000 --- a/driver/fingerprint/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include ../../common/fpsensor/OWNERS diff --git a/driver/fingerprint/build.mk b/driver/fingerprint/build.mk deleted file mode 100644 index 6cb9dc7adb..0000000000 --- a/driver/fingerprint/build.mk +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2019 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. - -# Build fingerprint drivers - -# Note that this variable includes the trailing "/" -_fingerprint_cur_dir:=$(dir $(lastword $(MAKEFILE_LIST))) - -include $(_fingerprint_cur_dir)elan/build.mk -include $(_fingerprint_cur_dir)fpc/build.mk diff --git a/driver/fingerprint/elan/build.mk b/driver/fingerprint/elan/build.mk deleted file mode 100644 index 2e4ad2d46f..0000000000 --- a/driver/fingerprint/elan/build.mk +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright 2021 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. - -# Build for ELAN fingerprint drivers - -# Note that this variable includes the trailing "/" -_elan_cur_dir:=$(dir $(lastword $(MAKEFILE_LIST))) - -ifneq (,$(filter rw,$(CONFIG_FP_SENSOR_ELAN80) $(CONFIG_FP_SENSOR_ELAN515))) - -# Make sure output directory is created (in build directory) -dirs-y+="$(_elan_cur_dir)" - -include $(_elan_cur_dir)../../../private/fingerprint/elan/build.mk - -all-obj-rw+=$(_elan_cur_dir)elan_private.o -all-obj-rw+=$(_elan_cur_dir)elan_sensor_pal.o - -endif diff --git a/driver/fingerprint/elan/elan_private.c b/driver/fingerprint/elan/elan_private.c deleted file mode 100644 index 555ad14ba0..0000000000 --- a/driver/fingerprint/elan/elan_private.c +++ /dev/null @@ -1,247 +0,0 @@ -/* Copyright 2021 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 <stddef.h> -#include "common.h" -#include "console.h" -#include "endian.h" -#include "gpio.h" -#include "link_defs.h" -#include "spi.h" -#include "system.h" -#include "timer.h" -#include "util.h" -#include "shared_mem.h" -#include "math_util.h" -#include "fpsensor.h" -#include "cryptoc/util.h" - -#include "elan_sensor.h" -#include "elan_setting.h" -#include "elan_sensor_pal.h" - -static uint16_t errors; - -#define CPRINTF(format, args...) cprintf(CC_FP, format, ##args) - -/* Sensor description */ -static struct ec_response_fp_info ec_fp_sensor_info = { - /* Sensor identification */ - .vendor_id = VID, - .product_id = PID, - .model_id = MID, - .version = VERSION, - /* Image frame characteristics */ - .frame_size = FP_SENSOR_RES_X * FP_SENSOR_RES_Y, - .pixel_format = V4L2_PIX_FMT_GREY, - .width = FP_SENSOR_RES_X, - .height = FP_SENSOR_RES_Y, - .bpp = FP_SENSOR_RES_BPP, -}; - -/** - * set fingerprint sensor into power saving mode - */ -void fp_sensor_low_power(void) -{ - elan_woe_mode(); -} - -/** - * Reset and initialize the sensor IC - */ -int fp_sensor_init(void) -{ - CPRINTF("========%s=======\n", __func__); - - errors = 0; - elan_execute_reset(); - algorithm_parameter_setting(); - if (elan_execute_calibration() < 0) - errors |= FP_ERROR_INIT_FAIL; - if (elan_woe_mode() != 0) - errors |= FP_ERROR_SPI_COMM; - - return EC_SUCCESS; -} - -/** - * Deinitialize the sensor IC - */ -int fp_sensor_deinit(void) -{ - CPRINTF("========%s=======\n", __func__); - return elan_fp_deinit(); -} - -/** - * Fill the 'ec_response_fp_info' buffer with the sensor information - * - * @param[out] resp retrieve the version, sensor and template information - * - * @return EC_SUCCESS on success otherwise error. - */ -int fp_sensor_get_info(struct ec_response_fp_info *resp) -{ - int ret = 0; - - CPRINTF("========%s=======\n", __func__); - memcpy(resp, &ec_fp_sensor_info, sizeof(struct ec_response_fp_info)); - elan_sensor_get_alg_info(resp); - resp->errors |= errors; - CPRINTF("##%s## FrameSize=%d, errors=0x%04x\n", __func__, - resp->frame_size, resp->errors); - - return ret; -} - -/** - * Compares given finger image against enrolled templates. - * - * @param[in] templ a pointer to the array of template buffers. - * @param[in] templ_count the number of buffers in the array of templates. - * @param[in] image the buffer containing the finger image - * @param[out] match_index index of the matched finger in the template - * array if any. - * @param[out] update_bitmap contains one bit per template, the bit is set if - * the match has updated the given template. - * - * @return negative value on error, else one of the following code : - * - EC_MKBP_FP_ERR_MATCH_NO on non-match - * - EC_MKBP_FP_ERR_MATCH_YES for match when template was not updated with - * new data - * - EC_MKBP_FP_ERR_MATCH_YES_UPDATED for match when template was updated - * - EC_MKBP_FP_ERR_MATCH_YES_UPDATE_FAILED match, but update failed (not saved) - * - EC_MKBP_FP_ERR_MATCH_LOW_QUALITY when matching could not be performed due - * to low image quality - * - EC_MKBP_FP_ERR_MATCH_LOW_COVERAGE when matching could not be performed - * due to finger covering too little area of the sensor - */ -int fp_finger_match(void *templ, uint32_t templ_count, uint8_t *image, - int32_t *match_index, uint32_t *update_bitmap) -{ - CPRINTF("========%s=======\n", __func__); - return elan_match(templ, templ_count, image, match_index, - update_bitmap); -} - -/** - * start a finger enrollment session and initialize enrollment data - * - * @return 0 on success. - * - */ -int fp_enrollment_begin(void) -{ - CPRINTF("========%s=======\n", __func__); - return elan_enrollment_begin(); -} - -/** - * Generate a template from the finger whose enrollment has just being - * completed. - * - * @param templ the buffer which will receive the template. - * templ can be set to NULL to abort the current enrollment - * process. - * - * @return 0 on success or a negative error code. - */ -int fp_enrollment_finish(void *templ) -{ - CPRINTF("========%s=======\n", __func__); - return elan_enrollment_finish(templ); -} - -/** - * Adds fingerprint image to the current enrollment session. - * - * @param[in] image fingerprint image data - * @param[out] completion retrieve percentage of current enrollment - * - * @return a negative value on error or one of the following codes: - * - EC_MKBP_FP_ERR_ENROLL_OK when image was successfully enrolled - * - EC_MKBP_FP_ERR_ENROLL_IMMOBILE when image added, but user should be - * advised to move finger - * - EC_MKBP_FP_ERR_ENROLL_LOW_QUALITY when image could not be used due to - * low image quality - * - EC_MKBP_FP_ERR_ENROLL_LOW_COVERAGE when image could not be used due to - * finger covering too little area of the sensor - */ -int fp_finger_enroll(uint8_t *image, int *completion) -{ - CPRINTF("========%s=======\n", __func__); - return elan_enroll(image, completion); -} - -/** - * Put the sensor in its lowest power state. - * - * fp_sensor_configure_detect needs to be called to restore finger detection - * functionality. - */ -void fp_sensor_configure_detect(void) -{ - CPRINTF("========%s=======\n", __func__); - elan_woe_mode(); -} - -/** - * Acquires a fingerprint image with specific capture mode. - * - * @param[out] image_data Memory buffer to retrieve fingerprint image data - * Image_data is allocated by the caller and the size - * is FP_SENSOR_IMAGE_SIZE. - * @param[in] mode one of the FP_CAPTURE_ constants to get a specific - * image type - * - FP_CAPTURE_VENDOR_FORMAT: Full blown vendor-defined capture - * - FP_CAPTURE_SIMPLE_IMAGE: Simple raw image capture - * - FP_CAPTURE_PATTERN0: Self test pattern - * - FP_CAPTURE_PATTERN1: Self test pattern - * - FP_CAPTURE_QUALITY_TEST - * - FP_CAPTURE_RESET_TEST - * - FP_CAPTURE_TYPE_MAX - * - * @return - * - 0 on success - * - negative value on error - * - FP_SENSOR_LOW_IMAGE_QUALITY on image captured but quality is too low - * - FP_SENSOR_TOO_FAST on finger removed before image was captured - * - FP_SENSOR_LOW_SENSOR_COVERAGE on sensor not fully covered by finger - */ -int fp_sensor_acquire_image_with_mode(uint8_t *image_data, int mode) -{ - CPRINTF("========%s=======\n", __func__); - return elan_sensor_acquire_image_with_mode(image_data, mode); -} - -/** - * Returns the status of the finger on the sensor. - * - * @return one of the following codes: - * - FINGER_NONE - * - FINGER_PARTIAL - * - FINGER_PRESENT - */ -enum finger_state fp_sensor_finger_status(void) -{ - CPRINTF("========%s=======\n", __func__); - return elan_sensor_finger_status(); -} - -/** - * Runs a test for defective pixels. - * - * Should be triggered periodically by the client. The maintenance command can - * take several hundred milliseconds to run. - * - * @return EC_ERROR_HW_INTERNAL on error (such as finger on sensor) - * @return EC_SUCCESS on success - */ -int fp_maintenance(void) -{ - CPRINTF("========%s=======\n", __func__); - return elan_fp_maintenance(&errors); -} diff --git a/driver/fingerprint/elan/elan_sensor.h b/driver/fingerprint/elan/elan_sensor.h deleted file mode 100644 index 490b1acf16..0000000000 --- a/driver/fingerprint/elan/elan_sensor.h +++ /dev/null @@ -1,179 +0,0 @@ -/* Copyright 2021 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. - */ - -#ifndef CROS_EC_DRIVER_FINGERPRINT_ELAN_ELAN_SENSOR_H -#define CROS_EC_DRIVER_FINGERPRINT_ELAN_ELAN_SENSOR_H -#include "common.h" - -/* Sensor pixel resolution */ -#if defined(CONFIG_FP_SENSOR_ELAN80) -#define FP_SENSOR_IMAGE_SIZE (80 * 80) -#define FP_SENSOR_RES_X 80 -#define FP_SENSOR_RES_Y 80 -#if defined(CHIP_FAMILY_STM32F4) -#define FP_ALGORITHM_TEMPLATE_SIZE 15000 -#elif defined(CHIP_FAMILY_STM32H7) -#define FP_ALGORITHM_TEMPLATE_SIZE 40960 -#endif -#define FP_MAX_FINGER_COUNT 3 -#elif defined(CONFIG_FP_SENSOR_ELAN515) -#define FP_SENSOR_IMAGE_SIZE (52 * 150) -#define FP_SENSOR_RES_X 52 -#define FP_SENSOR_RES_Y 150 -#if defined(CHIP_FAMILY_STM32F4) -#define FP_ALGORITHM_TEMPLATE_SIZE 15000 -#elif defined(CHIP_FAMILY_STM32H7) -#define FP_ALGORITHM_TEMPLATE_SIZE 67000 -#endif -#define FP_MAX_FINGER_COUNT 3 -#endif -#define FP_SENSOR_RES_BPP (8) - -/** - * Set ELAN fingerprint sensor into finger touch detects and power saving mode - * - * @return 0 on success. - * negative value on error. - */ -int elan_woe_mode(void); - -/** - * Set ELAN fingerprint sensor into the image sensing mode - * - * @return 0 on success. - * negative value on error. - */ -int elan_sensing_mode(void); - -/** - * To initialize parameters of the ELAN matching algorithm - * - */ -void algorithm_parameter_setting(void); - -/** - * Compares given finger image against enrolled templates. - * - * @param[in] templ a pointer to the array of template buffers. - * @param[in] templ_count the number of buffers in the array of templates. - * @param[in] image the buffer containing the finger image - * @param[out] match_index index of the matched finger in the template - * array if any. - * @param[out] update_bitmap contains one bit per template, the bit is set if - * the match has updated the given template. - * - * @return negative value on error, else one of the following code : - * - EC_MKBP_FP_ERR_MATCH_NO on non-match - * - EC_MKBP_FP_ERR_MATCH_YES for match when template was not updated with - * new data - * - EC_MKBP_FP_ERR_MATCH_YES_UPDATED for match when template was updated - * - EC_MKBP_FP_ERR_MATCH_YES_UPDATE_FAILED match, but update failed (not saved) - * - EC_MKBP_FP_ERR_MATCH_LOW_QUALITY when matching could not be performed due - * to low image quality - * - EC_MKBP_FP_ERR_MATCH_LOW_COVERAGE when matching could not be performed - * due to finger covering too little area of the sensor - */ -int elan_match(void *templ, uint32_t templ_count, uint8_t *image, - int32_t *match_index, uint32_t *update_bitmap); - -/** - * start a finger enrollment session and initialize enrollment data - * - * @return 0 on success. - * - */ -int elan_enrollment_begin(void); - -/** - * Adds fingerprint image to the current enrollment session. - * - * @param[in] image fingerprint image data - * @param[out] completion retrieve percentage of current enrollment - * - * @return a negative value on error or one of the following codes: - * - EC_MKBP_FP_ERR_ENROLL_OK when image was successfully enrolled - * - EC_MKBP_FP_ERR_ENROLL_IMMOBILE when image added, but user should be - advised to move finger - * - EC_MKBP_FP_ERR_ENROLL_LOW_QUALITY when image could not be used due to - * low image quality - * - EC_MKBP_FP_ERR_ENROLL_LOW_COVERAGE when image could not be used due to - * finger covering too little area of the sensor - */ -int elan_enroll(uint8_t *image, int *completion); - -/** - * Acquires a fingerprint image with specific capture mode. - * - * @param[out] image_data Memory buffer to retrieve fingerprint image data - * Image_data is allocated by the caller and the size - * is FP_SENSOR_IMAGE_SIZE. - * @param[in] mode one of the FP_CAPTURE_ constants to get a - * specific image type - * - FP_CAPTURE_VENDOR_FORMAT: Full blown vendor-defined capture - * - FP_CAPTURE_SIMPLE_IMAGE: Simple raw image capture - * - FP_CAPTURE_PATTERN0: Self test pattern - * - FP_CAPTURE_PATTERN1: Self test pattern - * - FP_CAPTURE_QUALITY_TEST - * - FP_CAPTURE_RESET_TEST - * - FP_CAPTURE_TYPE_MAX - * - * @return - * - 0 on success - * - negative value on error - * - FP_SENSOR_LOW_IMAGE_QUALITY on image captured but quality is too low - * - FP_SENSOR_TOO_FAST on finger removed before image was captured - * - FP_SENSOR_LOW_SENSOR_COVERAGE on sensor not fully covered by finger - */ -int elan_sensor_acquire_image_with_mode(uint8_t *image_data, int mode); - -/** - * Returns the status of the finger on the sensor. - * - * @return one of the following codes: - * - FINGER_NONE - * - FINGER_PARTIAL - * - FINGER_PRESENT - */ -enum finger_state elan_sensor_finger_status(void); - -/** - * Generate a template from the finger whose enrollment has just being - * completed. - * - * @param templ the buffer which will receive the template. - * templ can be set to NULL to abort the current enrollment - * process. - * - * @return 0 on success or a negative error code. - */ -int elan_enrollment_finish(void *templ); - -/** - * Fill the 'ec_response_fp_alg_info' buffer with the sensor alg information - * - * @param[out] resp retrieve the algorithm information - * - * @return EC_SUCCESS on success otherwise error. - */ -int elan_sensor_get_alg_info(struct ec_response_fp_info *resp); - -/** - * Runs a test for defective pixels. - * - * Should be triggered periodically by the client. The maintenance command can - * take several hundred milliseconds to run. - * - * @return EC_ERROR_HW_INTERNAL on error (such as finger on sensor) - * @return EC_SUCCESS on success - */ -int elan_fp_maintenance(uint16_t *error_state); - -/** - * Deinitialize the sensor IC. - * - * @return EC_SUCCESS on success otherwise error. - */ -int elan_fp_deinit(void); -#endif diff --git a/driver/fingerprint/elan/elan_sensor_pal.c b/driver/fingerprint/elan/elan_sensor_pal.c deleted file mode 100644 index b59368b835..0000000000 --- a/driver/fingerprint/elan/elan_sensor_pal.c +++ /dev/null @@ -1,253 +0,0 @@ -/* Copyright 2021 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. - */ -/* ELAN Platform Abstraction Layer callbacks */ - -#include <stddef.h> -#include "common.h" -#include "console.h" -#include "endian.h" -#include "fpsensor.h" -#include "gpio.h" -#include "link_defs.h" -#include "spi.h" -#include "system.h" -#include "timer.h" -#include "util.h" -#include "shared_mem.h" -#include "math_util.h" -#include "cryptoc/util.h" - -#include "elan_setting.h" -#include "elan_sensor.h" -#include "elan_sensor_pal.h" - -static uint8_t tx_buf[CONFIG_SPI_TX_BUF_SIZE] __uncached; -static uint8_t rx_buf[CONFIG_SPI_RX_BUF_SIZE] __uncached; - -int elan_write_cmd(uint8_t fp_cmd) -{ - int rc = 0; - - memset(tx_buf, 0, CONFIG_SPI_TX_BUF_SIZE); - memset(rx_buf, 0, CONFIG_SPI_RX_BUF_SIZE); - - tx_buf[0] = fp_cmd; - rc = spi_transaction(&spi_devices[0], tx_buf, 2, rx_buf, - SPI_READBACK_ALL); - return rc; -} - -int elan_read_cmd(uint8_t fp_cmd, uint8_t *regdata) -{ - int ret = 0; - - memset(tx_buf, 0, CONFIG_SPI_TX_BUF_SIZE); - memset(rx_buf, 0, CONFIG_SPI_RX_BUF_SIZE); - - tx_buf[0] = fp_cmd; /* one byte data read */ - ret = spi_transaction(&spi_devices[0], tx_buf, 2, rx_buf, - SPI_READBACK_ALL); - *regdata = rx_buf[1]; - - return ret; -} - -int elan_spi_transaction(uint8_t *tx, int tx_len, uint8_t *rx, int rx_len) -{ - int ret = 0; - - memset(tx_buf, 0, CONFIG_SPI_TX_BUF_SIZE); - memset(rx_buf, 0, CONFIG_SPI_RX_BUF_SIZE); - - memcpy(tx_buf, tx, tx_len); - ret = spi_transaction(&spi_devices[0], tx_buf, tx_len, rx_buf, rx_len); - memcpy(rx, rx_buf, rx_len); - - return ret; -} - -int elan_write_register(uint8_t regaddr, uint8_t regdata) -{ - int ret = 0; - - memset(tx_buf, 0, CONFIG_SPI_TX_BUF_SIZE); - memset(rx_buf, 0, CONFIG_SPI_RX_BUF_SIZE); - - tx_buf[0] = WRITE_REG_HEAD + regaddr; /* one byte data write */ - tx_buf[1] = regdata; - ret = spi_transaction(&spi_devices[0], tx_buf, 2, rx_buf, - SPI_READBACK_ALL); - return ret; -} - -int elan_write_page(uint8_t page) -{ - int ret = 0; - - memset(tx_buf, 0, CONFIG_SPI_TX_BUF_SIZE); - memset(rx_buf, 0, CONFIG_SPI_RX_BUF_SIZE); - - tx_buf[0] = PAGE_SEL; - tx_buf[1] = page; - ret = spi_transaction(&spi_devices[0], tx_buf, 2, rx_buf, - SPI_READBACK_ALL); - - return ret; -} - -int elan_write_reg_vector(const uint8_t *reg_table, int length) -{ - int ret = 0; - int i = 0; - uint8_t write_regaddr; - uint8_t write_regdata; - - for (i = 0; i < length; i = i + 2) { - write_regaddr = reg_table[i]; - write_regdata = reg_table[i + 1]; - ret = elan_write_register(write_regaddr, write_regdata); - if (ret < 0) - break; - } - return ret; -} - -int raw_capture(uint16_t *short_raw) -{ - int ret = 0, i = 0, image_index = 0, index = 0; - int cnt_timer = 0; - int dma_loop = 0, dma_len = 0; - uint8_t regdata[4] = { 0 }; - char *img_buf; - - memset(short_raw, 0, sizeof(uint16_t) * IMAGE_TOTAL_PIXEL); - - ret = shared_mem_acquire(sizeof(uint8_t) * IMG_BUF_SIZE, &img_buf); - if (ret) { - LOGE_SA("%s Can't get shared mem\n", __func__); - return ret; - } - memset(img_buf, 0, sizeof(uint8_t) * IMG_BUF_SIZE); - - /* Write start scans command to fp sensor */ - if (elan_write_cmd(START_SCAN) < 0) { - ret = ELAN_ERROR_SPI; - LOGE_SA("%s SPISendCommand( SSP2, START_SCAN ) fail ret = %d", - __func__, ret); - goto exit; - } - - /* Polling scan status */ - cnt_timer = 0; - while (1) { - usleep(1000); - cnt_timer++; - regdata[0] = SENSOR_STATUS; - elan_spi_transaction(regdata, 2, regdata, 2); - if (regdata[0] & 0x04) - break; - - if (cnt_timer > POLLING_SCAN_TIMER) { - ret = ELAN_ERROR_SCAN; - LOGE_SA("%s regdata = 0x%x, fail ret = %d", __func__, - regdata[0], ret); - goto exit; - } - } - - /* Read the image from fp sensor */ - dma_loop = 4; - dma_len = IMG_BUF_SIZE / dma_loop; - - for (i = 0; i < dma_loop; i++) { - memset(tx_buf, 0, CONFIG_SPI_TX_BUF_SIZE); - memset(rx_buf, 0, CONFIG_SPI_RX_BUF_SIZE); - tx_buf[0] = START_READ_IMAGE; - ret = spi_transaction(&spi_devices[0], tx_buf, 2, rx_buf, - dma_len); - memcpy(&img_buf[dma_len * i], rx_buf, dma_len); - } - - /* Remove dummy byte */ - for (image_index = 1; image_index < IMAGE_WIDTH; image_index++) - memcpy(&img_buf[RAW_PIXEL_SIZE * image_index], - &img_buf[RAW_DATA_SIZE * image_index], RAW_PIXEL_SIZE); - - for (index = 0; index < IMAGE_TOTAL_PIXEL; index++) - short_raw[index] = - (img_buf[index * 2] << 8) + img_buf[index * 2 + 1]; - -exit: - if (img_buf != NULL) { - always_memset(img_buf, 0, sizeof(uint8_t) * IMG_BUF_SIZE); - shared_mem_release(img_buf); - } - - if (ret != 0) - LOGE_SA("%s error = %d", __func__, ret); - - return ret; -} - -int elan_execute_calibration(void) -{ - int retry_time = 0; - int ret = 0; - - while (retry_time < REK_TIMES) { - elan_write_cmd(SRST); - elan_write_cmd(FUSE_LOAD); - register_initialization(); - elan_sensing_mode(); - - ret = calibration(); - if (ret == 0) - break; - - retry_time++; - } - - return ret; -} - -int elan_fp_maintenance(uint16_t *error_state) -{ - int rv; - fp_sensor_info_t sensor_info; - timestamp_t start = get_time(); - - if (error_state == NULL) - return EC_ERROR_INVAL; - - /* Initial status */ - *error_state &= 0xFC00; - sensor_info.num_defective_pixels = 0; - sensor_info.sensor_error_code = 0; - rv = fp_sensor_maintenance(&sensor_info); - LOGE_SA("Maintenance took %d ms", time_since32(start) / MSEC); - - if (rv != 0) { - /* - * Failure can occur if any of the fingerprint detection zones - * are covered (i.e., finger is on sensor). - */ - LOGE_SA("Failed to run maintenance: %d", rv); - return EC_ERROR_HW_INTERNAL; - } - if (sensor_info.num_defective_pixels >= FP_ERROR_DEAD_PIXELS_UNKNOWN) - *error_state = FP_ERROR_DEAD_PIXELS_UNKNOWN; - else - *error_state |= - FP_ERROR_DEAD_PIXELS(sensor_info.num_defective_pixels); - LOGE_SA("num_defective_pixels: %d", sensor_info.num_defective_pixels); - LOGE_SA("sensor_error_code: %d", sensor_info.sensor_error_code); - - return EC_SUCCESS; -} - -void __unused elan_sensor_set_rst(bool state) -{ - gpio_set_level(GPIO_FP_RST_ODL, state ? 0 : 1); -} diff --git a/driver/fingerprint/elan/elan_sensor_pal.h b/driver/fingerprint/elan/elan_sensor_pal.h deleted file mode 100644 index 067b693245..0000000000 --- a/driver/fingerprint/elan/elan_sensor_pal.h +++ /dev/null @@ -1,141 +0,0 @@ -/* Copyright 2021 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. - */ -/* ELAN Platform Abstraction Layer callbacks */ - -#ifndef ELAN_SENSOR_PAL_H_ -#define ELAN_SENSOR_PAL_H_ - -/* ELAN error codes */ -enum elan_error_code { - ELAN_ERROR_NONE = 0, - ELAN_ERROR_SPI = 1, - ELAN_ERROR_SCAN = 2, - ELAN_ERROR_CAL = 3, - ELAN_ERROR_DEFECT_NUM = 4, - ELAN_ERROR_DEFECT_X = 5, - ELAN_ERROR_DEFECT_Y = 6 -}; - -/* ELAN error info */ -typedef struct { - uint32_t num_defective_pixels; - uint16_t sensor_error_code; -} fp_sensor_info_t; - -/** - * @brief Write fp command to the sensor - * - * @param[in] fp_cmd One byte fp command to write - * - * @return 0 on success. - * negative value on error. - */ -int elan_write_cmd(uint8_t fp_cmd); - -/** - * @brief Read fp register data from the sensor - * - * @param[in] fp_cmd One byte fp command to read - * @param[out] regdata One byte data where register's data will be stored - * - * @return 0 on success. - * negative value on error. - */ -int elan_read_cmd(uint8_t fp_cmd, uint8_t *regdata); - -/** - * @brief Transfers and receives SPI data. - * - * @param[in] tx The buffer to transfer - * @param[in] tx_len The length to transfer - * @param[out] rx The buffer where read data will be stored - * @param[in] rx_len The length to receive - * @return 0 on success. - * negative value on error. - */ -int elan_spi_transaction(uint8_t *tx, int tx_len, uint8_t *rx, int rx_len); - -/** - * @brief Write fp register data to sensor - * - * @param[in] regaddr One byte register address to write - * @param[in] regdata Data to write to register - * - * @return 0 on success. - * negative value on error. - */ -int elan_write_register(uint8_t regaddr, uint8_t regdata); - -/** - * @brief Select sensor RAM page of register - * - * @param[in] page The number of RAM page control registers - * - * @return 0 on success. - * negative value on error. - */ -int elan_write_page(uint8_t page); - -/** - * @brief Write register table to fp sensor - * - * Using a table to write data to sensor register. - * This table contains multiple pairs of address and data to - * be written. - * - * @param[in] reg_table The register address to write - * @param[in] length The data to write to register - * - * @return 0 on success. - * negative value on error. - */ -int elan_write_reg_vector(const uint8_t *reg_table, int length); - -/** - * Get 14bits raw image data from ELAN fingerprint sensor - * - * @param[out] short_raw The memory buffer to receive fingerprint image - * raw data, buffer length is: - * (IMAGE_WIDTH*IMAGE_HEIGHT)*sizeof(uint16_t) - * - * @return 0 on success. - * negative value on error. - */ -int raw_capture(uint16_t *short_raw); - -/** - * Execute calibrate ELAN fingerprint sensor flow. - * - * @return 0 on success. - * negative value on error. - */ -int elan_execute_calibration(void); - -/** - * Execute reset ELAN fingerprint sensor flow. - */ -void elan_execute_reset(void); - -/** - * Runs a test for defective pixels. - * - * @param[out] fp_sensor_info Structure containing output data. - * - * @return 0 on success. - * negative value on error. - */ -int fp_sensor_maintenance(fp_sensor_info_t *fp_sensor_info); - -/** - * @brief Set sensor reset state. - * - * Set sensor reset state. - * - * @param[in] state Reset state. - * true => reset sensor, i.e. low GPIO state - * false => normal operation, i.e. high GPIO state - */ -void __unused elan_sensor_set_rst(bool state); -#endif diff --git a/driver/fingerprint/elan/elan_setting.h b/driver/fingerprint/elan/elan_setting.h deleted file mode 100644 index feaf5e1550..0000000000 --- a/driver/fingerprint/elan/elan_setting.h +++ /dev/null @@ -1,101 +0,0 @@ -/* Copyright 2021 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. - */ - -#ifndef ELAN_SETTING_H -#define ELAN_SETTING_H - -#include <stdint.h> - -/* The hardware ID information and FW version */ -#define VID 0x04F3 -#define PID 0x0903 -#define MID 0x01 -#define VERSION 0x100B - -/* SPI tx and rx buffer size */ -#define CONFIG_SPI_TX_BUF_SIZE 1024 -#define CONFIG_SPI_RX_BUF_SIZE 5120 - -/** - * Elan sensor operation is controlled by sending commands and receiving - * through the SPI interface. There are several SPI command codes for - * controlling FP sensor: - * - * - START_SCAN Start scan - * - START_READ_IMAGE Start read the image - * - SRST Software reset - * - FUSE_LOAD Load OTP trims data to control registers - * - READ_REG_HEAD Register single read - * - WRITE_REG_HEAD Register burst write - * - READ_SERIER_REG_HEAD Register burst read - * - PAGE_SEL Register page selection - * - SENSOR_STATUS Read sensor status - */ -#define START_SCAN 0x01 -#define START_READ_IMAGE 0x10 -#define SRST 0x31 -#define FUSE_LOAD 0x04 -#define READ_REG_HEAD 0x40 -#define WRITE_REG_HEAD 0x80 -#define READ_SERIER_REG_HEAD 0xC0 -#define PAGE_SEL 0x07 -#define SENSOR_STATUS 0x03 - -/* Sensor type name */ -#define EFSA515 1 -#define EFSA80SC 2 -#if defined(CONFIG_FP_SENSOR_ELAN80) -#define IC_SELECTION EFSA80SC -#elif defined(CONFIG_FP_SENSOR_ELAN515) -#define IC_SELECTION EFSA515 -#endif - -/* Sensor pixel resolution */ -#if (IC_SELECTION == EFSA80SC) -#define IMAGE_WIDTH 80 -#define IMAGE_HEIGHT 80 -#elif (IC_SELECTION == EFSA515) -#define IMAGE_WIDTH 150 -#define IMAGE_HEIGHT 52 -#endif - -/** - * Sensor real image size: - * ((IMAGE_HEIGHT * ONE_PIXEL_BYTE) + FP_DUMMY_BYTE) * IMAGE_WIDTH - */ -#define FP_DUMMY_BYTE 2 -#define ONE_PIXEL_BYTE 2 -#define IMAGE_TOTAL_PIXEL (IMAGE_WIDTH * IMAGE_HEIGHT) -#define RAW_PIXEL_SIZE (IMAGE_HEIGHT * ONE_PIXEL_BYTE) -#define RAW_DATA_SIZE (RAW_PIXEL_SIZE + FP_DUMMY_BYTE) -#define IMG_BUF_SIZE (RAW_DATA_SIZE * IMAGE_WIDTH) - -/* Polling scan status counter */ -#define POLLING_SCAN_TIMER 10000 - -/* Re-calibration timer */ -#define REK_TIMES 3 - -/* Console output macros */ -#define LOGE_SA(format, args...) cprints(CC_FP, format, ##args) - -/** - * Set ELAN fingerprint sensor register initialization - * - * @return 0 on success. - * negative value on error. - */ -int register_initialization(void); - -/** - * To calibrate ELAN fingerprint sensor and keep the calibration results - * for correcting fingerprint image data - * - * @return 0 on success. - * negative value on error. - */ -int calibration(void); - -#endif /* _ELAN_SETTING_H */ diff --git a/driver/fingerprint/fpc/bep/build.mk b/driver/fingerprint/fpc/bep/build.mk deleted file mode 100644 index ac7f05fb60..0000000000 --- a/driver/fingerprint/fpc/bep/build.mk +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright 2019 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. - -# FPC BEP source files build - -# Note that this variable includes the trailing "/" -_bep_cur_dir:=$(dir $(lastword $(MAKEFILE_LIST))) - -# Make sure output directory is created (in build directory) -dirs-y+="$(_bep_cur_dir)" - -# Only build for these objects for the RW image -all-obj-rw+=$(_bep_cur_dir)fpc_misc.o \ - $(_bep_cur_dir)fpc_private.o \ - $(_bep_cur_dir)fpc_sensor_spi.o \ - $(_bep_cur_dir)fpc_timebase.o diff --git a/driver/fingerprint/fpc/bep/fpc1025_private.h b/driver/fingerprint/fpc/bep/fpc1025_private.h deleted file mode 100644 index 2da127741f..0000000000 --- a/driver/fingerprint/fpc/bep/fpc1025_private.h +++ /dev/null @@ -1,49 +0,0 @@ -/* Copyright 2019 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. - */ - -#ifndef __CROS_EC_FPC1025_PRIVATE_H -#define __CROS_EC_FPC1025_PRIVATE_H - -/* The 16-bit hardware ID is 0x021y */ -#define FP_SENSOR_HWID 0x021 - -/* Sensor type name */ -#define FP_SENSOR_NAME "FPC1025" - -/* Sensor pixel resolution */ -#define FP_SENSOR_RES_X (160) /**< Sensor width */ -#define FP_SENSOR_RES_Y (160) /**< Sensor height */ -#define FP_SENSOR_RES_BPP (8) /**< Resolution bits per pixel */ - -/* - * Sensor image size - * - * Value from fpc_bep_image_get_buffer_size(): (160*160)+660 - */ -#define FP_SENSOR_IMAGE_SIZE (26260) -#define FP_SENSOR_REAL_IMAGE_SIZE (FP_SENSOR_RES_X * FP_SENSOR_RES_Y) -/* Offset of image data in fp_buffer */ -#define FP_SENSOR_IMAGE_OFFSET (400) - -/* - * Constant value for the enrollment data size - * - * Size of private fp_bio_enrollment_t - */ -#define FP_ALGORITHM_ENROLLMENT_SIZE (4) - -/* - * Constant value corresponding to the maximum template size - * for FPC1025 sensor. Client template memory allocation must - * have this size. This includes extra memory for template update. - * - * Template size + alignment padding + size of template size variable - */ -#define FP_ALGORITHM_TEMPLATE_SIZE (5088 + 0 + 4) - -/* Max number of templates stored / matched against */ -#define FP_MAX_FINGER_COUNT (5) - -#endif /* __CROS_EC_FPC1025_PRIVATE_H */ diff --git a/driver/fingerprint/fpc/bep/fpc1035_private.h b/driver/fingerprint/fpc/bep/fpc1035_private.h deleted file mode 100644 index 695228898b..0000000000 --- a/driver/fingerprint/fpc/bep/fpc1035_private.h +++ /dev/null @@ -1,49 +0,0 @@ -/* Copyright 2019 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. - */ - -#ifndef __CROS_EC_FPC1035_PRIVATE_H -#define __CROS_EC_FPC1035_PRIVATE_H - -/* The 16-bit hardware ID is 0x011y */ -#define FP_SENSOR_HWID 0x011 - -/* Sensor type name */ -#define FP_SENSOR_NAME "FPC1035" - -/* Sensor pixel resolution */ -#define FP_SENSOR_RES_X (112) /**< Sensor width */ -#define FP_SENSOR_RES_Y (88) /**< Sensor height */ -#define FP_SENSOR_RES_BPP (8) /**< Resolution bits per pixel */ - -/* - * Sensor image size - * - * Value from fpc_bep_image_get_buffer_size(): (112*88)+660 - */ -#define FP_SENSOR_IMAGE_SIZE (10516) -#define FP_SENSOR_REAL_IMAGE_SIZE (FP_SENSOR_RES_X * FP_SENSOR_RES_Y) -/* Offset of image data in fp_buffer */ -#define FP_SENSOR_IMAGE_OFFSET (400) - -/* - * Constant value for the enrollment data size - * - * Size of private fp_bio_enrollment_t - */ -#define FP_ALGORITHM_ENROLLMENT_SIZE (4) - -/* - * Constant value corresponding to the maximum template size - * for FPC1035 sensor. Client template memory allocation must - * have this size. This includes extra memory for template update. - * - * Template size + alignment padding + size of template size variable - */ -#define FP_ALGORITHM_TEMPLATE_SIZE (14373 + 3 + 4) - -/* Max number of templates stored / matched against */ -#define FP_MAX_FINGER_COUNT (5) - -#endif /* __CROS_EC_FPC1035_PRIVATE_H */ diff --git a/driver/fingerprint/fpc/bep/fpc_bio_algorithm.h b/driver/fingerprint/fpc/bep/fpc_bio_algorithm.h deleted file mode 100644 index 1bf598a3ee..0000000000 --- a/driver/fingerprint/fpc/bep/fpc_bio_algorithm.h +++ /dev/null @@ -1,136 +0,0 @@ -/* Copyright 2019 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. - */ - -#ifndef __CROS_EC_FPC_BIO_ALGORITHM_H -#define __CROS_EC_FPC_BIO_ALGORITHM_H - -#include <stdint.h> - -/* - * An opaque pointer representing an image (scan). - */ -typedef void *bio_image_t; -/* - * An opaque pointer representing/uniquely identifying an (serialized) enrolled - * template. - */ -typedef void *bio_template_t; -/* - * An opaque pointer representing/uniquely identifying enrollment attempt. - */ -typedef void *bio_enrollment_t; -/* - * An opaque struct representing algorithm. - */ -typedef struct fpc_bep_algorithm fpc_bep_algorithm_t; -/* - * Struct with biometric algorithm information. - */ -typedef struct { - const fpc_bep_algorithm_t *algorithm; - uint32_t template_size; -} fpc_bio_info_t; -/* - * Initializes biometric algorithm library. Should be the very first function - * to be invoked by the biometric daemon. - * - * Returns 0 on success, negative error code (such as -ENOMEM) on failure. - */ -int bio_algorithm_init(void); -/* - * Instructs the biometric library to release all resources in preparation - * for the process termination (or unloading the library). Regardless of - * the returned error code the action is considered unrecoverable. - * - * Returns 0 on success, negative error code (such as -ENOMEM) on failure. - */ -int bio_algorithm_exit(void); -/* - * Compares given biometric image against a list of enrolled template(s). - * In case the image match a template the match_index will indicate which - * template in the list that matched. - * The algorithm library can update templates with additional biometric data - * from the image, if it chooses to do so. The updated template(s) will be - * indicated by the out parameter 'updated_templates', a bit-field where - * updated template(s) indicated by the corresponding bit being set - * Returns: - * - negative value on error - * - BIO_TEMPLATE_NO_MATCH on non-match - * - BIO_TEMPLATE_MATCH for match when template was not updated with new data - * - BIO_TEMPLATE_MATCH_UPDATED for match when template was updated - * - BIO_TEMPLATE_MATCH_UPDATE_FAILED match, but update failed (do not save) - * - BIO_TEMPLATE_LOW_QUALITY when matching could not be performed due to low - * image quality - * - BIO_TEMPLATE_LOW_COVERAGE when matching could not be performed due to - * finger covering too little area of the sensor - */ -#define BIO_TEMPLATE_NO_MATCH 0 -#define BIO_TEMPLATE_MATCH 1 -#define BIO_TEMPLATE_MATCH_UPDATED 3 -#define BIO_TEMPLATE_MATCH_UPDATE_FAILED 5 -#define BIO_TEMPLATE_LOW_QUALITY 2 -#define BIO_TEMPLATE_LOW_COVERAGE 4 - -int bio_template_image_match_list(bio_template_t templ, uint32_t num_templ, - bio_image_t image, int32_t *match_index, - uint32_t *updated_templ); -/* - * Initiates biometric data enrollment process. Algorithm library returns - * 'enrollment handle' that is used for all subsequent enrollment operations. - * - * Returns 0 on success, negative error code (such as -ENOMEM) on failure. - */ -int bio_enrollment_begin(bio_enrollment_t *enrollment); -/* - * Adds fingerprint image to an enrollment. - * - * The library should expect to copy any relevant data from the “image” - * as it is likely to be destroyed (via bio_image_destroy() call) shortly after - * this call completes. - * - * Returns: - * - negative value on error - * - BIO_ENROLLMENT_OK when image was successfully enrolled - * - BIO_ENROLLMENT_LOW_QUALITY when image could not be used due to low - * image quality - * - BIO_ENROLLMENT_IMMOBILE when image added, but user should be advised - * to move finger - * - BIO_ENROLLMENT_LOW_COVERAGE when image could not be used due to - * finger covering too little area of the sensor - * - BIO_ENROLLMENT_INTERNAL_ERROR when an internal error occurred - */ -#define BIO_ENROLLMENT_OK 0 -#define BIO_ENROLLMENT_LOW_QUALITY 1 -#define BIO_ENROLLMENT_IMMOBILE 2 -#define BIO_ENROLLMENT_LOW_COVERAGE 3 -#define BIO_ENROLLMENT_INTERNAL_ERROR 5 - -/* Can be used to detect if image was usable for enrollment or not. */ -#define BIO_ENROLLMENT_PROBLEM_MASK 1 -int bio_enrollment_add_image(bio_enrollment_t enrollment, bio_image_t image); -/* - * Returns percent of coverage accumulated during enrollment process. - * Optional method. Regardless of value returned by this call user should call - * bio_enrollment_is_complete() to check if algorithm library accumulated enough - * data to create a template. - * - * Returns value in the range 0..100, or negative error (such as -EINVAL); - */ -int bio_enrollment_get_percent_complete(bio_enrollment_t enrollment); -/* - * Indicates that given enrollment process is complete, and algorithm library - * should generate an active template that can be used in subsequent calls - * to bio_image_match() and bio_template_serialize() from enrollment data. - * After the template is created the library should release all resources - * associated with this enrollment. - * - * Argument 'templ' is optional and can be set to NULL if caller wishes to - * abort enrollment process. - * - * Returns 0 on success, negative error code (such as -EINVAL) on failure. - */ -int bio_enrollment_finish(bio_enrollment_t enrollment, bio_template_t *templ); - -#endif /* __CROS_EC_FPC_BIO_ALGORITHM_H */ diff --git a/driver/fingerprint/fpc/bep/fpc_misc.c b/driver/fingerprint/fpc/bep/fpc_misc.c deleted file mode 100644 index c4c779b702..0000000000 --- a/driver/fingerprint/fpc/bep/fpc_misc.c +++ /dev/null @@ -1,51 +0,0 @@ -/* Copyright 2019 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. - */ - -/* FPC Platform Abstraction Layer */ - -#include <stdint.h> -#include <stddef.h> - -#include "shared_mem.h" -#include "uart.h" - -void __unused *fpc_malloc(uint32_t size) -{ - char *data; - int rc; - - rc = shared_mem_acquire(size, (char **)&data); - - if (rc == 0) - return data; - else - return NULL; -} - -void __unused fpc_free(void *data) -{ - shared_mem_release(data); -} - -/* Not in release */ -void __unused fpc_assert_fail(const char *file, uint32_t line, const char *func, - const char *expr) -{ -} - -void __unused fpc_log_var(const char *source, uint8_t level, const char *format, - ...) -{ - va_list args; - - va_start(args, format); - uart_vprintf(format, args); - va_end(args); -} - -uint32_t abs(int32_t a) -{ - return (a < 0) ? (uint32_t)(-a) : (uint32_t)a; -} diff --git a/driver/fingerprint/fpc/bep/fpc_private.c b/driver/fingerprint/fpc/bep/fpc_private.c deleted file mode 100644 index a94ba2ab06..0000000000 --- a/driver/fingerprint/fpc/bep/fpc_private.c +++ /dev/null @@ -1,268 +0,0 @@ -/* Copyright 2019 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 <stdint.h> -#include <stddef.h> - -#include "fpc_bio_algorithm.h" -#include "fpsensor.h" -#include "gpio.h" -#include "spi.h" -#include "system.h" -#include "util.h" - -#include "driver/fingerprint/fpc/fpc_sensor.h" - -/* Console output macros */ -#define CPRINTF(format, args...) cprintf(CC_FP, format, ## args) -#define CPRINTS(format, args...) cprints(CC_FP, format, ## args) - -static uint8_t enroll_ctx[FP_ALGORITHM_ENROLLMENT_SIZE] __aligned(4) = {0}; - -/* Recorded error flags */ -static uint16_t errors; - -/* FPC specific initialization and de-initialization functions */ -int fp_sensor_open(void); -int fp_sensor_close(void); - -/* Get FPC library version code.*/ -const char *fp_sensor_get_version(void); - -/* Get FPC library build info.*/ -const char *fp_sensor_get_build_info(void); - -/* Sensor description */ -static struct ec_response_fp_info ec_fp_sensor_info = { - /* Sensor identification */ - .vendor_id = FOURCC('F', 'P', 'C', ' '), - .product_id = 9, - .model_id = 1, - .version = 1, - /* Image frame characteristics */ - .frame_size = FP_SENSOR_IMAGE_SIZE, - .pixel_format = V4L2_PIX_FMT_GREY, - .width = FP_SENSOR_RES_X, - .height = FP_SENSOR_RES_Y, - .bpp = FP_SENSOR_RES_BPP, -}; - -typedef struct fpc_bep_sensor fpc_bep_sensor_t; - -typedef struct { - const fpc_bep_sensor_t *sensor; - uint32_t image_buffer_size; -} fpc_sensor_info_t; - -#if defined(CONFIG_FP_SENSOR_FPC1025) - -extern const fpc_bep_sensor_t fpc_bep_sensor_1025; -extern const fpc_bep_algorithm_t fpc_bep_algorithm_pfe_1025; - -const fpc_sensor_info_t fpc_sensor_info = { - .sensor = &fpc_bep_sensor_1025, - .image_buffer_size = FP_SENSOR_IMAGE_SIZE, -}; - -const fpc_bio_info_t fpc_bio_info = { - .algorithm = &fpc_bep_algorithm_pfe_1025, - .template_size = FP_ALGORITHM_TEMPLATE_SIZE, -}; - -#elif defined(CONFIG_FP_SENSOR_FPC1035) - -extern const fpc_bep_sensor_t fpc_bep_sensor_1035; -extern const fpc_bep_algorithm_t fpc_bep_algorithm_pfe_1035; - -const fpc_sensor_info_t fpc_sensor_info = { - .sensor = &fpc_bep_sensor_1035, - .image_buffer_size = FP_SENSOR_IMAGE_SIZE, -}; - -const fpc_bio_info_t fpc_bio_info = { - .algorithm = &fpc_bep_algorithm_pfe_1035, - .template_size = FP_ALGORITHM_TEMPLATE_SIZE, -}; -#else -#error "Sensor type not defined!" -#endif - -/* Sensor IC commands */ -enum fpc_cmd { - FPC_CMD_DEEPSLEEP = 0x2C, - FPC_CMD_HW_ID = 0xFC, -}; - -/* Maximum size of a sensor command SPI transfer */ -#define MAX_CMD_SPI_TRANSFER_SIZE 3 - -/* Memory for the SPI transfer buffer */ -static uint8_t spi_buf[MAX_CMD_SPI_TRANSFER_SIZE]; - -static int fpc_send_cmd(const uint8_t cmd) -{ - spi_buf[0] = cmd; - - return spi_transaction(SPI_FP_DEVICE, spi_buf, 1, spi_buf, - SPI_READBACK_ALL); -} - -void fp_sensor_low_power(void) -{ - fpc_send_cmd(FPC_CMD_DEEPSLEEP); -} - -int fpc_check_hwid(void) -{ - uint16_t id; - int rc; - - spi_buf[0] = FPC_CMD_HW_ID; - - rc = spi_transaction(SPI_FP_DEVICE, spi_buf, 3, spi_buf, - SPI_READBACK_ALL); - if (rc) { - CPRINTS("FPC HW ID read failed %d", rc); - return FP_ERROR_SPI_COMM; - } - - id = (spi_buf[1] << 8) | spi_buf[2]; - if ((id >> 4) != FP_SENSOR_HWID) { - CPRINTS("FPC unknown silicon 0x%04x", id); - return FP_ERROR_BAD_HWID; - } - CPRINTS(FP_SENSOR_NAME " id 0x%04x", id); - - return EC_SUCCESS; -} - -/* Reset and initialize the sensor IC */ -int fp_sensor_init(void) -{ - int rc; - - /* Print the binary libfpbep.a library version */ - CPRINTS("FPC libfpbep.a %s", fp_sensor_get_version()); - - /* Print the BEP version and build time of the library */ - CPRINTS("Build information - %s", fp_sensor_get_build_info()); - - errors = FP_ERROR_DEAD_PIXELS_UNKNOWN; - - rc = fp_sensor_open(); - if (rc) { - errors |= FP_ERROR_INIT_FAIL; - CPRINTS("Error: fp_sensor_open() failed, result=%d", rc); - } - - errors |= fpc_check_hwid(); - - rc = bio_algorithm_init(); - if (rc < 0) { - errors |= FP_ERROR_INIT_FAIL; - CPRINTS("Error: bio_algorithm_init() failed, result=%d", rc); - } - - /* Go back to low power */ - fp_sensor_low_power(); - - return EC_SUCCESS; -} - -/* Deinitialize the sensor IC */ -int fp_sensor_deinit(void) -{ - int rc; - - rc = bio_algorithm_exit(); - if (rc < 0) - CPRINTS("Error: bio_algorithm_exit() failed, result=%d", rc); - - rc = fp_sensor_close(); - if (rc < 0) - CPRINTS("Error: fp_sensor_close() failed, result=%d", rc); - - return rc; -} - -int fp_sensor_get_info(struct ec_response_fp_info *resp) -{ - int rc; - - spi_buf[0] = FPC_CMD_HW_ID; - - memcpy(resp, &ec_fp_sensor_info, sizeof(struct ec_response_fp_info)); - - rc = spi_transaction(SPI_FP_DEVICE, spi_buf, 3, spi_buf, - SPI_READBACK_ALL); - if (rc) - return EC_RES_ERROR; - - resp->model_id = (spi_buf[1] << 8) | spi_buf[2]; - resp->errors = errors; - - return EC_SUCCESS; -} - -int fp_finger_match(void *templ, uint32_t templ_count, uint8_t *image, - int32_t *match_index, uint32_t *update_bitmap) -{ - int rc; - - rc = bio_template_image_match_list(templ, templ_count, image, - match_index, update_bitmap); - if (rc < 0) - CPRINTS("Error: bio_template_image_match_list() failed, result=%d", - rc); - - return rc; -} - -int fp_enrollment_begin(void) -{ - int rc; - bio_enrollment_t bio_enroll = enroll_ctx; - - rc = bio_enrollment_begin(&bio_enroll); - if (rc < 0) - CPRINTS("Error: bio_enrollment_begin() failed, result=%d", rc); - - return rc; -} - -int fp_enrollment_finish(void *templ) -{ - int rc; - bio_enrollment_t bio_enroll = enroll_ctx; - bio_template_t bio_templ = templ; - - rc = bio_enrollment_finish(bio_enroll, templ ? &bio_templ : NULL); - if (rc < 0) - CPRINTS("Error: bio_enrollment_finish() failed, result=%d", rc); - - return rc; -} - -int fp_finger_enroll(uint8_t *image, int *completion) -{ - int rc; - bio_enrollment_t bio_enroll = enroll_ctx; - - rc = bio_enrollment_add_image(bio_enroll, image); - if (rc < 0) { - CPRINTS("Error: bio_enrollment_add_image() failed, result=%d", - rc); - return rc; - } - - *completion = bio_enrollment_get_percent_complete(bio_enroll); - - return rc; -} - -int fp_maintenance(void) -{ - return fpc_fp_maintenance(&errors); -} diff --git a/driver/fingerprint/fpc/bep/fpc_private.h b/driver/fingerprint/fpc/bep/fpc_private.h deleted file mode 100644 index 9a9acfd42a..0000000000 --- a/driver/fingerprint/fpc/bep/fpc_private.h +++ /dev/null @@ -1,40 +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. - */ - -/* Private sensor interface */ - -#ifndef __CROS_EC_FPC_PRIVATE_H -#define __CROS_EC_FPC_PRIVATE_H - -#include <stdint.h> - -typedef struct { - uint32_t num_defective_pixels; -} fp_sensor_info_t; - -/** - * fp_sensor_maintenance runs a test for defective pixels and should - * be triggered periodically by the client. Internally, a defective - * pixel list is maintained and the algorithm will compensate for - * any defect pixels when matching towards a template. - * - * The defective pixel update will abort and return an error if any of - * the finger detect zones are covered. A client can call - * fp_sensor_finger_status to determine the current status. - * - * @param[in] image_data pointer to FP_SENSOR_IMAGE_SIZE bytes of memory - * @param[out] fp_sensor_info Structure containing output data. - * - * @return - * - 0 on success - * - negative value on error - */ -int fp_sensor_maintenance(uint8_t *image_data, - fp_sensor_info_t *fp_sensor_info); - -/* Read the HWID from the sensor. */ -int fpc_check_hwid(void); - -#endif /* __CROS_EC_FPC_PRIVATE_H */ diff --git a/driver/fingerprint/fpc/bep/fpc_sensor_spi.c b/driver/fingerprint/fpc/bep/fpc_sensor_spi.c deleted file mode 100644 index 225752bdb6..0000000000 --- a/driver/fingerprint/fpc/bep/fpc_sensor_spi.c +++ /dev/null @@ -1,94 +0,0 @@ -/* Copyright 2019 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. - */ - -/* FPC Platform Abstraction Layer */ - -#include <stdint.h> -#include <stdbool.h> -#include <stddef.h> - -#include "console.h" -#include "fpsensor.h" -#include "fpc_sensor_spi.h" -#include "gpio.h" -#include "spi.h" -#include "util.h" - -#include "driver/fingerprint/fpc/fpc_sensor.h" - -/* Console output macros */ -#define CPRINTF(format, args...) cprintf(CC_FP, format, ##args) -#define CPRINTS(format, args...) cprints(CC_FP, format, ##args) - -#define SPI_BUF_SIZE (1024) - -#define FPC_RESULT_OK (0) -#define FPC_RESULT_IO_ERROR (-8) - -static uint8_t spi_buf[SPI_BUF_SIZE] FP_FRAME_SECTION __aligned(4); - -int __unused fpc_sensor_spi_write_read(uint8_t *write, uint8_t *read, - size_t size, bool leave_cs_asserted) -{ - int rc = 0; - - if (size == FP_SENSOR_REAL_IMAGE_SIZE) { - rc |= spi_transaction(SPI_FP_DEVICE, write, size, read, - SPI_READBACK_ALL); - spi_transaction_flush(SPI_FP_DEVICE); - } else if (size <= SPI_BUF_SIZE) { - memcpy(spi_buf, write, size); - rc |= spi_transaction_async(SPI_FP_DEVICE, spi_buf, size, - spi_buf, SPI_READBACK_ALL); - - /* De-asserting the sensor chip-select will clear the sensor - * internal command state. To run multiple sensor transactions - * in the same command state (typically image capture), leave - * chip-select asserted. Make sure chip-select is de-asserted - * when all transactions are finished. - */ - if (!leave_cs_asserted) - spi_transaction_flush(SPI_FP_DEVICE); - else - spi_transaction_wait(SPI_FP_DEVICE); - - memcpy(read, spi_buf, size); - } else { - rc = -1; - } - - if (rc == 0) { - return FPC_RESULT_OK; - } else { - CPRINTS("Error: spi_transaction()/spi_transaction_async() failed, result=%d", - rc); - return FPC_RESULT_IO_ERROR; - } -} - -bool __unused fpc_sensor_spi_check_irq(void) -{ - return (gpio_get_level(GPIO_FPS_INT) == 1); -} - -bool __unused fpc_sensor_spi_read_irq(void) -{ - return (gpio_get_level(GPIO_FPS_INT) == 1); -} - -void __unused fpc_sensor_spi_reset(bool state) -{ - gpio_set_level(GPIO_FP_RST_ODL, state ? 0 : 1); -} - -void __unused fpc_sensor_spi_init(uint32_t speed_hz) -{ -} - -int __unused fpc_sensor_wfi(uint16_t timeout_ms, fpc_wfi_check_t enter_wfi, - bool enter_wfi_mode) -{ - return FPC_RESULT_OK; -} diff --git a/driver/fingerprint/fpc/bep/fpc_sensor_spi.h b/driver/fingerprint/fpc/bep/fpc_sensor_spi.h deleted file mode 100644 index 25d29d77a3..0000000000 --- a/driver/fingerprint/fpc/bep/fpc_sensor_spi.h +++ /dev/null @@ -1,99 +0,0 @@ -/* Copyright 2019 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. - */ - -#ifndef __CROS_EC_FPC_SENSOR_SPI_H -#define __CROS_EC_FPC_SENSOR_SPI_H - -/** - * @file fpc_sensor_spi.h - * @brief Driver for SPI controller. - * - * Driver for SPI controller. Intended for communication with - * fingerprint sensor. - */ - -#include <stdint.h> -#include <stdbool.h> - -typedef bool (*fpc_wfi_check_t)(void); - -/** - * @brief Writes and reads SPI data. - * - * Writes data to SPI interface and reads data from SPI interface, with chip - * select control. The caller is blocked until the operation is complete. By use - * of the chip select control parameter a single SPI transaction can be split in - * several calls. - * - * @param[in] write Data to write. Must not be NULL if size > 0. - * @param[in,out] read Receive data buffer. The caller is responsible for - * allocating buffer. NULL => response is thrown away. - * @param[in] size Number of bytes to write (same as bytes received). - * 0 => Only chip select control. - * @param[in] leave_cs_asserted True => chip select is left in asserted - * state. - * False => chip select is de-asserted before - * return. - * @return ::fpc_bep_result_t - */ -int __unused fpc_sensor_spi_write_read(uint8_t *write, uint8_t *read, - size_t size, bool leave_cs_asserted); - -/** - * @brief Read sensor IRQ status. - * - * Returns status of the sensor IRQ. - * - * @return true if the sensor IRQ is currently active, otherwise false. - */ -bool __unused fpc_sensor_spi_check_irq(void); - -/** - * @brief Read sensor IRQ status and then set status to false. - * - * Returns status of the sensor IRQ and sets the status to false. - * - * @return true if the sensor IRQ has been active, otherwise false. - */ -bool __unused fpc_sensor_spi_read_irq(void); - -/** - * @brief Set sensor reset state. - * - * Set sensor reset state. - * - * @param[in] state Reset state. - * true => reset sensor, i.e. low GPIO state - * false => normal operation, i.e. high GPIO state - */ -void __unused fpc_sensor_spi_reset(bool state); - -/** - * @brief Initializes SPI controller. - * - * @param[in] speed_hz Maximum SPI clock speed according to sensor HW spec - * (unit Hz). - * - */ -void __unused fpc_sensor_spi_init(uint32_t speed_hz); - -/** - * @brief Set system in WFI mode while waiting sensor IRQ. - * - * @note This mode only requires the system to be able to wake up from Sensor - * IRQ pin, all other peripheral can be turned off. - * - * @note The system time must be adjusted upon WFI return. - * - * @param[in] timeout_ms Time in ms before waking up, 0 if no timeout. - * @param[in] enter_wfi Function pointer to check WFI entry. - * @param[in] enter_wfi_mode Bool that is used when comparing the value returned - * by enter_wfi. - * @return FPC_RESULT_OK, FPC_RESULT_TIMEOUT - */ -int __unused fpc_sensor_wfi(uint16_t timeout_ms, fpc_wfi_check_t enter_wfi, - bool enter_wfi_mode); - -#endif /* __CROS_EC_FPC_SENSOR_SPI_H */ diff --git a/driver/fingerprint/fpc/bep/fpc_timebase.c b/driver/fingerprint/fpc/bep/fpc_timebase.c deleted file mode 100644 index 113e150ed9..0000000000 --- a/driver/fingerprint/fpc/bep/fpc_timebase.c +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright 2019 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. - */ - -/* FPC Platform Abstraction Layer */ - -#include <stdint.h> - -#include "fpc_timebase.h" -#include "timer.h" - -uint32_t __unused fpc_timebase_get_tick(void) -{ - clock_t time; - - time = clock(); - - return (uint32_t)time; -} - -void __unused fpc_timebase_busy_wait(uint32_t ms) -{ - udelay(ms * 1000); -} - -void __unused fpc_timebase_init(void) -{ -} diff --git a/driver/fingerprint/fpc/bep/fpc_timebase.h b/driver/fingerprint/fpc/bep/fpc_timebase.h deleted file mode 100644 index 388d13293e..0000000000 --- a/driver/fingerprint/fpc/bep/fpc_timebase.h +++ /dev/null @@ -1,48 +0,0 @@ -/* Copyright 2019 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. - */ - -#ifndef __CROS_EC_FPC_TIMEBASE_H -#define __CROS_EC_FPC_TIMEBASE_H - -/** - * @file fpc_timebase.h - * @brief Timebase based on a system tick. - * - * Supplies tick counter and wait operation(s). - */ - -#include <stdint.h> - -#include "common.h" - -/** - * @brief Reads the system tick counter. - * - * @details To handle tick counter wrap around when checking for timeout, make - * sure to do the calculation in the following manner: - * "if ((current_tick - old_tick) > timeout) {" - * Example: current time (uint32_t) = 10 ticks - * old time (uint32_t) = 30 ticks before overflow of uint32_t - * current_time - old_time = 10 - (2**32 - 30) -> wraps around to 40 - * - * @return Tick count since fpc_timebase_init() call. [ms] - */ -uint32_t __unused fpc_timebase_get_tick(void); - -/** - * @brief Busy wait. - * - * @param[in] ms Time to wait [ms]. - * 0 => return immediately - * 1 => wait at least 1ms etc. - */ -void __unused fpc_timebase_busy_wait(uint32_t ms); - -/** - * @brief Initializes timebase. Starts system tick counter. - */ -void __unused fpc_timebase_init(void); - -#endif /* __CROS_EC_FPC_TIMEBASE_H */ diff --git a/driver/fingerprint/fpc/build.mk b/driver/fingerprint/fpc/build.mk deleted file mode 100644 index 5c18a1f096..0000000000 --- a/driver/fingerprint/fpc/build.mk +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright 2019 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. - -# Build for FPC fingerprint drivers - -# Note that this variable includes the trailing "/" -_fpc_cur_dir:=$(dir $(lastword $(MAKEFILE_LIST))) - -# Only build if FPC sensor is configured. -ifneq (,$(filter rw,$(CONFIG_FP_SENSOR_FPC1145) $(CONFIG_FP_SENSOR_FPC1025) \ - $(CONFIG_FP_SENSOR_FPC1035))) - -ifeq ($(CONFIG_FP_SENSOR_FPC1145),rw) -include $(_fpc_cur_dir)libfp/build.mk -else ifeq ($(CONFIG_FP_SENSOR_FPC1025),rw) -include $(_fpc_cur_dir)bep/build.mk -else ifeq ($(CONFIG_FP_SENSOR_FPC1035),rw) -include $(_fpc_cur_dir)bep/build.mk -endif - -ifneq ($(CONFIG_FINGERPRINT_MCU),) -# Make sure output directory is created (in build directory) -dirs-rw+="$(_fpc_cur_dir)" - -# Only build these objects for the RW image -all-obj-rw+=$(_fpc_cur_dir)fpc_sensor.o -endif - -endif diff --git a/driver/fingerprint/fpc/fpc_sensor.c b/driver/fingerprint/fpc/fpc_sensor.c deleted file mode 100644 index a15502521f..0000000000 --- a/driver/fingerprint/fpc/fpc_sensor.c +++ /dev/null @@ -1,52 +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 <stddef.h> -#include <include/fpsensor.h> -#include <include/fpsensor_state.h> -#include <common/fpsensor/fpsensor_private.h> -#if defined(CONFIG_FP_SENSOR_FPC1025) || defined(CONFIG_FP_SENSOR_FPC1035) -#include "bep/fpc_private.h" -#elif defined(CONFIG_FP_SENSOR_FPC1145) -#include "libfp/fpc_private.h" -#else -#error "Sensor type not defined!" -#endif - -/* - * TODO(b/164174822): We cannot include fpc_sensor.h here, since - * the parent fpsensor.h header conditionally excludes fpc_sensor.h - * and replaces its content with default macros. - * Fix this header discrepancy. - * - * #include "fpc_sensor.h" - */ - -int fpc_fp_maintenance(uint16_t *error_state) -{ - int rv; - fp_sensor_info_t sensor_info; - timestamp_t start = get_time(); - - if (error_state == NULL) - return EC_ERROR_INVAL; - - rv = fp_sensor_maintenance(fp_buffer, &sensor_info); - CPRINTS("Maintenance took %d ms", time_since32(start) / MSEC); - - if (rv != 0) { - /* - * Failure can occur if any of the fingerprint detection zones - * are covered (i.e., finger is on sensor). - */ - CPRINTS("Failed to run maintenance: %d", rv); - return EC_ERROR_HW_INTERNAL; - } - - *error_state |= FP_ERROR_DEAD_PIXELS(sensor_info.num_defective_pixels); - CPRINTS("num_defective_pixels: %d", sensor_info.num_defective_pixels); - - return EC_SUCCESS; -} diff --git a/driver/fingerprint/fpc/fpc_sensor.h b/driver/fingerprint/fpc/fpc_sensor.h deleted file mode 100644 index 2ab9248eeb..0000000000 --- a/driver/fingerprint/fpc/fpc_sensor.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright 2019 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. - */ - -#ifndef __CROS_EC_DRIVER_FINGERPRINT_FPC_FPC_SENSOR_H_ -#define __CROS_EC_DRIVER_FINGERPRINT_FPC_FPC_SENSOR_H_ - -#include "common.h" - -#if defined(CONFIG_FP_SENSOR_FPC1025) -#include "bep/fpc1025_private.h" -#elif defined(CONFIG_FP_SENSOR_FPC1035) -#include "bep/fpc1035_private.h" -#elif defined(CONFIG_FP_SENSOR_FPC1145) -#include "libfp/fpc1145_private.h" -#else -#error "Sensor type not defined!" -#endif - -int fpc_fp_maintenance(uint16_t *error_state); - -#endif /* __CROS_EC_DRIVER_FINGERPRINT_FPC_FPC_SENSOR_H_ */ diff --git a/driver/fingerprint/fpc/libfp/build.mk b/driver/fingerprint/fpc/libfp/build.mk deleted file mode 100644 index 3fabab38e9..0000000000 --- a/driver/fingerprint/fpc/libfp/build.mk +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright 2019 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. - -# FPC libfp source files build - -# Note that this variable includes the trailing "/" -libfp_cur_dir:=$(dir $(lastword $(MAKEFILE_LIST))) - -# Make sure output directory is created (in build directory) -dirs-y+="$(libfp_cur_dir)" - -# Only build for these objects for the RW image -all-obj-rw+=$(libfp_cur_dir)fpc_sensor_pal.o \ - $(libfp_cur_dir)fpc_private.o diff --git a/driver/fingerprint/fpc/libfp/fpc1145_private.h b/driver/fingerprint/fpc/libfp/fpc1145_private.h deleted file mode 100644 index 399c75118b..0000000000 --- a/driver/fingerprint/fpc/libfp/fpc1145_private.h +++ /dev/null @@ -1,51 +0,0 @@ -/* Copyright 2017 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. - */ - -#ifndef __CROS_EC_FPC1145_PRIVATE_H -#define __CROS_EC_FPC1145_PRIVATE_H - -#include <stdint.h> - -/** - * The hardware ID is 16-bits. All 114x FPC sensors (including FPC1145) are - * detected with the pattern 0x1400 and mask 0xFFF0. All supported variants of - * the 1145 (0x140B, 0x140C, and 0x1401) should be detected as part of the FPC - * 1140 family with identical functionality. - * See http://b/150407388 for additional details. - */ -#define FP_SENSOR_HWID 0x140 - -/* Sensor type name */ -#define FP_SENSOR_NAME "FPC1145" - -/* Sensor pixel resolution */ -#define FP_SENSOR_RES_Y 192 -#define FP_SENSOR_RES_X 56 -#define FP_SENSOR_RES_BPP 8 - -/* Acquired finger frame definitions */ -#define FP_SENSOR_IMAGE_SIZE_MODE_VENDOR (35460) -#define FP_SENSOR_IMAGE_SIZE_MODE_SIMPLE (13356) -/* - * Size of the captured image in MQT mode. If you this is modified the - * corresponding value in the MQT tool fputils.py must be changed too. - * See b/111443750 for context. - */ -#define FP_SENSOR_IMAGE_SIZE_MODE_QUAL (24408) - -#define FP_SENSOR_IMAGE_SIZE FP_SENSOR_IMAGE_SIZE_MODE_VENDOR -#define FP_SENSOR_IMAGE_OFFSET 2340 - -/* Opaque FPC context */ -#define FP_SENSOR_CONTEXT_SIZE 4944 - -/* Algorithm buffer sizes */ -#define FP_ALGORITHM_ENROLLMENT_SIZE 28 -#define FP_ALGORITHM_TEMPLATE_SIZE 47552 - -/* Max number of templates stored / matched against */ -#define FP_MAX_FINGER_COUNT 5 - -#endif /* __CROS_EC_FPC1145_PRIVATE_H */ diff --git a/driver/fingerprint/fpc/libfp/fpc_bio_algorithm.h b/driver/fingerprint/fpc/libfp/fpc_bio_algorithm.h deleted file mode 100644 index 9c00b14640..0000000000 --- a/driver/fingerprint/fpc/libfp/fpc_bio_algorithm.h +++ /dev/null @@ -1,265 +0,0 @@ -/* Copyright 2016 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. - */ -#ifndef BIOD_BIO_ALGORITHM_H_ -#define BIOD_BIO_ALGORITHM_H_ - -#include <stdint.h> - -enum bio_algorithm_type { - BIO_ALGORITHM_FINGERPRINT, - BIO_ALGORITHM_IRIS, -}; -/* - * An opaque pointer representing/uniquely identifying a sensor. - */ -typedef void *bio_sensor_t; -/* - * An opaque pointer representing an image (scan). - */ -typedef void *bio_image_t; -/* - * An opaque pointer representing/uniquely identifying an (serialized) enrolled - * template. - */ -typedef void *bio_template_t; -/* - * An opaque pointer representing/uniquely identifying enrollment attempt. - */ -typedef void *bio_enrollment_t; -/* - * Initializes biometric algorithm library. Should be the very first function - * to be invoked by the biometric daemon. - * - * Returns 0 on success, negative error code (such as -ENOMEM) on failure. - */ -int bio_algorithm_init(void); -/* - * Instructs the biometric library to release all resources in preparation - * for the process termination (or unloading the library). Regardless of - * the returned error code the action is considered unrecoverable. - * - * Returns 0 on success, negative error code (such as -ENOMEM) on failure. - */ -int bio_algorithm_exit(void); -/* - * Used to retrieve type of the algorithm library. Might be used by - * configuration processor module to match sensors and algorithm libraries. - */ -enum bio_algorithm_type bio_algorithm_get_type(void); -/* - * Used to retrieve name of the algorithm library, to be used in diagnostics. - * Also might be used by configuration processor module to match sensors and - * algorithm libraries. - */ -const char *bio_algorithm_get_name(void); -/* - * Used to retrieve version of the algorithm library, to be used in diagnostics. - */ -const char *bio_algorithm_get_version(void); -/* - * Used to retrieve additional information from the algorithm library, to be - * used in diagnostics. - */ -const char *bio_algorithm_get_banner(void); -/* - * Initializes a new sensor structure and returns its handle that will be used - * in other calls to identify the sensor involved in the operation. - * - * Returns 0 on success, negative error code (such as -ENOMEM) on failure. - */ -int bio_sensor_create(bio_sensor_t *sensor); -/* - * Releases all resources held by the library in conjunction with given sensor. - * - * Returns 0 on success, negative error code (such as -EINVAL) on failure. - */ -int bio_sensor_destroy(bio_sensor_t sensor); -/* - * Communicates particulars of a given sensor so that algorithm library can - * adjust its behavior as needed. - * - * Returns 0 on success, negative error code (such as -EINVAL) on failure. - */ -int bio_sensor_set_model(bio_sensor_t sensor, uint32_t vendor_id, - uint32_t product_id, uint32_t model_id, - uint32_t version); -/* - * Communicates format of data used by given sensor to the algorithm library. - * This is a fourcc value defined by V4L2 API. - * Could be a new define for biometric sensors or V4L2_PIX_FMT_GREY. - * Algorithm library will return error if it can not work with given format. - * - * Returns 0 on success, negative error code (such as -EINVAL) on failure. - */ -int bio_sensor_set_format(bio_sensor_t sensor, uint32_t pixel_format); -/* - * Communicates dimensions of given sensor to the algorithm library. - * - * Returns 0 on success, negative error code (such as -EINVAL) on failure. - */ -int bio_sensor_set_size(bio_sensor_t sensor, uint32_t width, uint32_t height); -/* - * Instructs the algorithm library to initialize a new structure to hold - * biometric image of given dimensions acquired from given sensor. - * It will return image handle that will be used in other calls to identify - * the image involved in the operation. - * - * Returns 0 on success, negative error code (such as -ENOMEM) on failure. - */ -int bio_image_create(bio_sensor_t sensor, uint32_t width, uint32_t height, - bio_image_t *image); -/* - * Communicates dimensions of image to the algorithm library. - * Can be used if image is less than full sensor resolution. - * - * Returns 0 on success, negative error code (such as -EINVAL) on failure. - */ -int bio_image_set_size(bio_image_t image, uint32_t width, uint32_t height); -/* - * Attaches data from biometric sensor to image structure. The caller must - * ensure that there is enough of data for given image dimensions for given - * format used by the sensor. - * - * It is assumes that the data pointer stays valid until bio_image_destroy() - * is called. - * - * Returns 0 on success, negative error code (such as -EINVAL) on failure. - */ -int bio_image_set_data(bio_image_t image, const uint8_t *data, size_t size); -/* - * Releases all resources held by the library in conjunction with given image. - * - * Returns 0 on success, negative error code (such as -EINVAL) on failure. - */ -int bio_image_destroy(bio_image_t image); - -/* - * Compares given biometric image against a list of enrolled template(s). - * In case the image match a template the match_index will indicate which - * template in the list that matched. - * The algorithm library can update templates with additional biometric data - * from the image, if it chooses to do so. The updated template(s) will be - * indicated by the out parameter 'updated_templates', a bit-field where - * updated template(s) indicated by the corresponding bit being set - * Returns: - * - negative value on error - * - BIO_TEMPLATE_NO_MATCH on non-match - * - BIO_TEMPLATE_MATCH for match when template was not updated with new data - * - BIO_TEMPLATE_MATCH_UPDATED for match when template was updated - * - BIO_TEMPLATE_MATCH_UPDATE_FAILED match, but update failed (do not save) - * - BIO_TEMPLATE_LOW_QUALITY when matching could not be performed due to low - * image quality - * - BIO_TEMPLATE_LOW_COVERAGE when matching could not be performed due to - * finger covering too little area of the sensor - */ -int bio_template_image_match_list(bio_template_t tmpl, uint32_t num_templates, - bio_image_t image, int32_t *match_index, - uint32_t *updated_templates); -int bio_template_image_match(bio_template_t tmpl, bio_image_t image); -/* - * Returns size of template data in serialized form. - * - * Returns negative error code (such as -EINVAL) on failure, or size of the - * serialized form in bytes. - */ -ssize_t bio_template_get_serialized_size(bio_template_t tmpl); -/* - * Releases all resources held by the library in conjunction with given - * template. - * - * Returns 0 on success, negative error code (such as -EINVAL) on failure. - */ -int bio_template_destroy(bio_template_t tmpl); -/* - * Initiates biometric data enrollment process. Algorithm library returns - * 'enrollment handle' that is used for all subsequent enrollment operations. - * - * Returns 0 on success, negative error code (such as -ENOMEM) on failure. - */ -int bio_enrollment_begin(bio_sensor_t sensor, bio_enrollment_t *enrollment); -/* - * Adds fingerprint image to an enrollment. - * - * The library should expect to copy any relevant data from the “image” - * as it is likely to be destroyed (via bio_image_destroy() call) shortly after - * this call completes. - * - * Returns: - * - negative value on error - * - BIO_ENROLLMENT_OK when image was successfully enrolled - * - BIO_ENROLLMENT_IMMOBILE when image added, but user should be advised - * to move finger - * - BIO_ENROLLMENT_LOW_QUALITY when image could not be used due to low - * image quality - * - BIO_ENROLLMENT_LOW_COVERAGE when image could not be used due to - * finger covering too little area of the sensor - */ -#define BIO_ENROLLMENT_OK 0 -#define BIO_ENROLLMENT_IMMOBILE 2 -#define BIO_ENROLLMENT_LOW_QUALITY 1 -#define BIO_ENROLLMENT_LOW_COVERAGE 3 -/* Can be used to detect if image was usable for enrollment or not. */ -#define BIO_ENROLLMENT_PROBLEM_MASK 1 -int bio_enrollment_add_image(bio_enrollment_t enrollment, bio_image_t image); -/* - * Indicates whether there is enough data in the enrollment for it to be - * converted into a template to be used for identification. - * - * Returns 0 for if enrollment does not have enough data yet, 1 if enrollment - * is complete, or negative error code (such as -EINVAL) on failure. - * - */ -int bio_enrollment_is_complete(bio_enrollment_t enrollment); -/* - * Returns percent of coverage accumulated during enrollment process. - * Optional method. Regardless of value returned by this call user should call - * bio_enrollment_is_complete() to check if algorithm library accumulated enough - * data to create a template. - * - * Returns value in the range 0..100, or negative error (such as -EINVAL); - */ -int bio_enrollment_get_percent_complete(bio_enrollment_t enrollment); -/* - * Indicates that given enrollment process is complete, and algorithm library - * should generate an active template that can be used in subsequent calls - * to bio_image_match() and bio_template_serialize() from enrollment data. - * After the template is created the library should release all resources - * associated with this enrollment. - * - * Argument 'tmpl' is optional and can be set to NULL if caller wishes to - * abort enrollment process. - * - * Returns 0 on success, negative error code (such as -EINVAL) on failure. - */ -int bio_enrollment_finish(bio_enrollment_t enrollment, bio_template_t *tmpl); - -typedef struct { - int32_t coverage; /* Sensor coverage in range [0..100] */ - int32_t quality; /* Image quality in range [0..100] */ - int32_t min_coverage; /* Minimum coverage accepted by enroll */ - int32_t min_quality; /* Minimum image quality accepted by enroll */ -} bio_image_status_t; - -/* - * Get the image quality and threshold values for a bio_image_t - * - * @param[in] image Image data as acquired by - * fp_sensor_acquire_image_with_mode - * @param[out] image_status Populated structure with quality/coverage values - * and corresponding threshold values - * - * @note This function will alter the internal states of the bio algorithm - * library and must not be used during an enroll sequence. The typical - * use case for this function is to qualify images during image - * collection. - * - * @return negative on error. - * @return 0 if the quality and coverage threshold values aren't reached. - * @return 1 if the quality and coverage threshold values are reached. - */ -int bio_sensor_get_image_status(bio_image_t image, - bio_image_status_t *image_status); - -#endif /* BIOD_BIO_ALGORITHM_H_ */ diff --git a/driver/fingerprint/fpc/libfp/fpc_private.c b/driver/fingerprint/fpc/libfp/fpc_private.c deleted file mode 100644 index 34fc61f66c..0000000000 --- a/driver/fingerprint/fpc/libfp/fpc_private.c +++ /dev/null @@ -1,320 +0,0 @@ -/* Copyright 2017 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 <stddef.h> -#include "common.h" -#include "console.h" -#include "endian.h" -#include "fpc_bio_algorithm.h" -#include "fpc_private.h" -#include "fpsensor.h" -#include "gpio.h" -#include "link_defs.h" -#include "spi.h" -#include "system.h" -#include "timer.h" -#include "util.h" - -#include "driver/fingerprint/fpc/fpc_sensor.h" - -#define CPRINTF(format, args...) cprintf(CC_FP, format, ## args) -#define CPRINTS(format, args...) cprints(CC_FP, format, ## args) - -/* Minimum reset duration */ -#define FP_SENSOR_RESET_DURATION_US (10 * MSEC) -/* Maximum delay for the interrupt to be asserted after the sensor is reset */ -#define FP_SENSOR_IRQ_MAX_DELAY_US (5 * MSEC) -/* Maximum number of attempts to initialise the sensor */ -#define FP_SENSOR_MAX_INIT_ATTEMPTS 10 -/* Delay between failed attempts of fp_sensor_open() */ -#define FP_SENSOR_OPEN_DELAY_US (500 * MSEC) - -/* Decode internal error codes from FPC's sensor library */ -#define FPC_GET_INTERNAL_CODE(res) (((res) & 0x000fc000) >> 14) -/* There was a finger on the sensor when calibrating finger detect */ -#define FPC_INTERNAL_FINGER_DFD FPC_ERROR_INTERNAL_38 - -/* - * The sensor context is uncached as it contains the SPI buffers, - * the binary library assumes that it is aligned. - */ -static uint8_t ctx[FP_SENSOR_CONTEXT_SIZE] __uncached __aligned(4); -static bio_sensor_t bio_sensor; -static uint8_t enroll_ctx[FP_ALGORITHM_ENROLLMENT_SIZE] __aligned(4); - -/* recorded error flags */ -static uint16_t errors; - -/* Sensor description */ -static struct ec_response_fp_info fpc1145_info = { - /* Sensor identification */ - .vendor_id = FOURCC('F', 'P', 'C', ' '), - .product_id = 9, - .model_id = 1, - .version = 1, - /* Image frame characteristics */ - .frame_size = FP_SENSOR_IMAGE_SIZE, - .pixel_format = V4L2_PIX_FMT_GREY, - .width = FP_SENSOR_RES_X, - .height = FP_SENSOR_RES_Y, - .bpp = FP_SENSOR_RES_BPP, -}; - -/* Sensor IC commands */ -enum fpc_cmd { - FPC_CMD_STATUS = 0x14, - FPC_CMD_INT_STS = 0x18, - FPC_CMD_INT_CLR = 0x1C, - FPC_CMD_FINGER_QUERY = 0x20, - FPC_CMD_SLEEP = 0x28, - FPC_CMD_DEEPSLEEP = 0x2C, - FPC_CMD_SOFT_RESET = 0xF8, - FPC_CMD_HW_ID = 0xFC, -}; - -/* Maximum size of a sensor command SPI transfer */ -#define MAX_CMD_SPI_TRANSFER_SIZE 3 - -/* Uncached memory for the SPI transfer buffer */ -static uint8_t spi_buf[MAX_CMD_SPI_TRANSFER_SIZE] __uncached; - -static int fpc_send_cmd(const uint8_t cmd) -{ - spi_buf[0] = cmd; - return spi_transaction(SPI_FP_DEVICE, spi_buf, 1, spi_buf, - SPI_READBACK_ALL); -} - -void fp_sensor_low_power(void) -{ - /* - * TODO(b/117620462): verify that sleep mode is WAI (no increased - * latency, expected power consumption). - */ - if (0) - fpc_send_cmd(FPC_CMD_SLEEP); -} - -int fpc_check_hwid(void) -{ - uint16_t id; - int rc; - - /* Clear previous occurences of relevant |errors| flags. */ - errors &= (~FP_ERROR_SPI_COMM & ~FP_ERROR_BAD_HWID); - - spi_buf[0] = FPC_CMD_HW_ID; - rc = spi_transaction(SPI_FP_DEVICE, spi_buf, 3, spi_buf, - SPI_READBACK_ALL); - if (rc) { - CPRINTS("FPC ID read failed %d", rc); - errors |= FP_ERROR_SPI_COMM; - return EC_ERROR_HW_INTERNAL; - } - id = (spi_buf[1] << 8) | spi_buf[2]; - if ((id >> 4) != FP_SENSOR_HWID) { - CPRINTS("FPC unknown silicon 0x%04x", id); - errors |= FP_ERROR_BAD_HWID; - return EC_ERROR_HW_INTERNAL; - } - CPRINTS(FP_SENSOR_NAME " id 0x%04x", id); - - return EC_SUCCESS; -} - -static uint8_t fpc_read_clear_int(void) -{ - spi_buf[0] = FPC_CMD_INT_CLR; - spi_buf[1] = 0xff; - if (spi_transaction(SPI_FP_DEVICE, spi_buf, 2, spi_buf, - SPI_READBACK_ALL)) - return 0xff; - return spi_buf[1]; -} - -/* - * Toggle the h/w reset pins and clear any pending IRQs before initializing the - * sensor contexts. - * Returns: - * - EC_SUCCESS on success. - * - EC_ERROR_HW_INTERNAL on failure (and |errors| variable is updated where - * appropriate). - */ -static int fpc_pulse_hw_reset(void) -{ - int ret; - int rc = EC_SUCCESS; - /* Clear previous occurrence of possible error flags. */ - errors &= ~FP_ERROR_NO_IRQ; - - /* Ensure we pulse reset low to initiate the startup */ - gpio_set_level(GPIO_FP_RST_ODL, 0); - usleep(FP_SENSOR_RESET_DURATION_US); - gpio_set_level(GPIO_FP_RST_ODL, 1); - /* the IRQ line should be set high by the sensor */ - usleep(FP_SENSOR_IRQ_MAX_DELAY_US); - if (!gpio_get_level(GPIO_FPS_INT)) { - CPRINTS("Sensor IRQ not ready"); - errors |= FP_ERROR_NO_IRQ; - rc = EC_ERROR_HW_INTERNAL; - } - - /* Check the Hardware ID */ - ret = fpc_check_hwid(); - if (ret != EC_SUCCESS) { - CPRINTS("Failed to verify HW ID"); - rc = EC_ERROR_HW_INTERNAL; - } - - /* clear the pending 'ready' IRQ before enabling interrupts */ - fpc_read_clear_int(); - - return rc; -} - -/* Reset and initialize the sensor IC */ -int fp_sensor_init(void) -{ - int res; - int attempt; - - errors = FP_ERROR_DEAD_PIXELS_UNKNOWN; - - /* Release any previously held resources from earlier iterations */ - res = bio_sensor_destroy(bio_sensor); - if (res) - CPRINTS("FPC Sensor resources release failed: %d", res); - bio_sensor = NULL; - - res = bio_algorithm_exit(); - if (res) - CPRINTS("FPC Algorithm resources release failed: %d", res); - - /* Print the binary libfpsensor.a library version */ - CPRINTF("FPC libfpsensor.a v%s\n", fp_sensor_get_version()); - cflush(); - - attempt = 0; - do { - attempt++; - - res = fpc_pulse_hw_reset(); - if (res != EC_SUCCESS) { - /* In case of failure, retry after a delay. */ - CPRINTS("H/W sensor reset failed, error flags: 0x%x", - errors); - cflush(); - usleep(FP_SENSOR_OPEN_DELAY_US); - continue; - } - - /* - * Ensure that any previous context data is obliterated in case - * of a sensor reset. - */ - memset(ctx, 0, FP_SENSOR_CONTEXT_SIZE); - - res = fp_sensor_open(ctx, FP_SENSOR_CONTEXT_SIZE); - /* Flush messages from the PAL if any */ - cflush(); - CPRINTS("Sensor init (attempt %d): 0x%x", attempt, res); - /* - * Retry on failure. This typically happens if the user has left - * their finger on the sensor after powering up the device, DFD - * will fail in that case. We've seen other error modes in the - * field, retry in all cases to be more resilient. - */ - if (!res) - break; - usleep(FP_SENSOR_OPEN_DELAY_US); - } while (attempt < FP_SENSOR_MAX_INIT_ATTEMPTS); - if (res) - errors |= FP_ERROR_INIT_FAIL; - - res = bio_algorithm_init(); - /* the PAL might have spewed a lot of traces, ensure they are visible */ - cflush(); - CPRINTS("Algorithm init: 0x%x", res); - if (res < 0) - errors |= FP_ERROR_INIT_FAIL; - res = bio_sensor_create(&bio_sensor); - CPRINTS("Sensor create: 0x%x", res); - if (res < 0) - errors |= FP_ERROR_INIT_FAIL; - - /* Go back to low power */ - fp_sensor_low_power(); - - return EC_SUCCESS; -} - -/* Deinitialize the sensor IC */ -int fp_sensor_deinit(void) -{ - /* - * TODO(tomhughes): libfp doesn't have fp_sensor_close like BEP does. - * We'll need FPC to either add it or verify that we don't have the same - * problem with the libfp library as described in: - * b/124773209#comment46 - */ - return EC_SUCCESS; -} - -int fp_sensor_get_info(struct ec_response_fp_info *resp) -{ - int rc; - - memcpy(resp, &fpc1145_info, sizeof(*resp)); - - spi_buf[0] = FPC_CMD_HW_ID; - rc = spi_transaction(SPI_FP_DEVICE, spi_buf, 3, spi_buf, - SPI_READBACK_ALL); - if (rc) - return EC_RES_ERROR; - resp->model_id = (spi_buf[1] << 8) | spi_buf[2]; - resp->errors = errors; - - return EC_SUCCESS; -} - -int fp_finger_match(void *templ, uint32_t templ_count, uint8_t *image, - int32_t *match_index, uint32_t *update_bitmap) -{ - return bio_template_image_match_list(templ, templ_count, image, - match_index, update_bitmap); -} - -int fp_enrollment_begin(void) -{ - int rc; - bio_enrollment_t p = enroll_ctx; - - rc = bio_enrollment_begin(bio_sensor, &p); - if (rc < 0) - CPRINTS("begin failed %d", rc); - return rc; -} - -int fp_enrollment_finish(void *templ) -{ - bio_template_t pt = templ; - - return bio_enrollment_finish(enroll_ctx, templ ? &pt : NULL); -} - -int fp_finger_enroll(uint8_t *image, int *completion) -{ - int rc = bio_enrollment_add_image(enroll_ctx, image); - - if (rc < 0) - return rc; - *completion = bio_enrollment_get_percent_complete(enroll_ctx); - return rc; -} - -int fp_maintenance(void) -{ - return fpc_fp_maintenance(&errors); -} diff --git a/driver/fingerprint/fpc/libfp/fpc_private.h b/driver/fingerprint/fpc/libfp/fpc_private.h deleted file mode 100644 index 95313726f6..0000000000 --- a/driver/fingerprint/fpc/libfp/fpc_private.h +++ /dev/null @@ -1,131 +0,0 @@ -/* Copyright 2018 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. - */ - -/* Private sensor interface */ - -#ifndef __CROS_EC_FPC_PRIVATE_H -#define __CROS_EC_FPC_PRIVATE_H - -/* External error codes from FPC's sensor library */ -enum fpc_error_code_external { - FPC_ERROR_NONE = 0, - FPC_ERROR_NOT_FOUND = 1, - FPC_ERROR_CAN_BE_USED_2 = 2, - FPC_ERROR_CAN_BE_USED_3 = 3, - FPC_ERROR_CAN_BE_USED_4 = 4, - FPC_ERROR_PAL = 5, - FPC_ERROR_IO = 6, - FPC_ERROR_CANCELLED = 7, - FPC_ERROR_UNKNOWN = 8, - FPC_ERROR_MEMORY = 9, - FPC_ERROR_PARAMETER = 10, - FPC_ERROR_TEST_FAILED = 11, - FPC_ERROR_TIMEDOUT = 12, - FPC_ERROR_SENSOR = 13, - FPC_ERROR_SPI = 14, - FPC_ERROR_NOT_SUPPORTED = 15, - FPC_ERROR_OTP = 16, - FPC_ERROR_STATE = 17, - FPC_ERROR_PN = 18, - FPC_ERROR_DEAD_PIXELS = 19, - FPC_ERROR_TEMPLATE_CORRUPTED = 20, - FPC_ERROR_CRC = 21, - FPC_ERROR_STORAGE = 22, /**< Errors related to storage **/ - FPC_ERROR_MAXIMUM_REACHED = 23, /**< The allowed maximum has been reached **/ - FPC_ERROR_MINIMUM_NOT_REACHED = 24, /**< The required minimum was not reached **/ - FPC_ERROR_SENSOR_LOW_COVERAGE = 25, /**< Minimum sensor coverage was not reached **/ - FPC_ERROR_SENSOR_LOW_QUALITY = 26, /**< Sensor image is considered low quality **/ - FPC_ERROR_SENSOR_FINGER_NOT_STABLE = 27, /**< Finger was not stable during image capture **/ -}; - -/* Internal error codes from FPC's sensor library */ -enum fpc_error_code_internal { - FPC_ERROR_INTERNAL_0 = 0, /* Indicates that no internal code was set. */ - FPC_ERROR_INTERNAL_1 = 1, /* Not supported by sensor. */ - FPC_ERROR_INTERNAL_2 = 2, /* Sensor got a NULL response (from other module). */ - FPC_ERROR_INTERNAL_3 = 3, /* Runtime config not supported by firmware. */ - FPC_ERROR_INTERNAL_4 = 4, /* CAC has not been created. */ - FPC_ERROR_INTERNAL_5 = 5, /* CAC returned an error to the sensor. */ - FPC_ERROR_INTERNAL_6 = 6, /* CAC fasttap image capture failed. */ - FPC_ERROR_INTERNAL_7 = 7, /* CAC fasttap image capture failed. */ - FPC_ERROR_INTERNAL_8 = 8, /* CAC Simple image capture failed. */ - FPC_ERROR_INTERNAL_9 = 9, /* CAC custom image capture failed. */ - FPC_ERROR_INTERNAL_10 = 10, /* CAC MQT image capture failed. */ - FPC_ERROR_INTERNAL_11 = 11, /* CAC PN image capture failed. */ - FPC_ERROR_INTERNAL_12 = 12, /* Reading CAC context size. */ - FPC_ERROR_INTERNAL_13 = 13, /* Reading CAC context size. */ - FPC_ERROR_INTERNAL_14 = 14, /* Sensor context invalid. */ - FPC_ERROR_INTERNAL_15 = 15, /* Buffer reference is invalid. */ - FPC_ERROR_INTERNAL_16 = 16, /* Buffer size reference is invalid. */ - FPC_ERROR_INTERNAL_17 = 17, /* Image data reference is invalid. */ - FPC_ERROR_INTERNAL_18 = 18, /* Capture type specified is invalid. */ - FPC_ERROR_INTERNAL_19 = 19, /* Capture config specified is invalid. */ - FPC_ERROR_INTERNAL_20 = 20, /* Sensor type in hw desc could not be extracted. */ - FPC_ERROR_INTERNAL_21 = 21, /* Failed to create BNC component. */ - FPC_ERROR_INTERNAL_22 = 22, /* BN calibration failed. */ - FPC_ERROR_INTERNAL_23 = 23, /* BN memory allocation failed. */ - FPC_ERROR_INTERNAL_24 = 24, /* Companion type in hw desc could not be extracted. */ - FPC_ERROR_INTERNAL_25 = 25, /* Coating type in hw desc could not be extracted. */ - FPC_ERROR_INTERNAL_26 = 26, /* Sensor mode type is invalid. */ - FPC_ERROR_INTERNAL_27 = 27, /* Wrong Sensor state in OTP read. */ - FPC_ERROR_INTERNAL_28 = 28, /* Mismatch of register size in overlay vs rrs. */ - FPC_ERROR_INTERNAL_29 = 29, /* Checkerboard capture failed. */ - FPC_ERROR_INTERNAL_30 = 30, /* Error converting to fpc_image in dp calibration. */ - FPC_ERROR_INTERNAL_31 = 31, /* Failed to capture reset pixel image. */ - FPC_ERROR_INTERNAL_32 = 32, /* API level not support in dp calibration. */ - FPC_ERROR_INTERNAL_33 = 33, /* The image data in parameter is invalid. */ - FPC_ERROR_INTERNAL_34 = 34, /* PAL delay function has failed. */ - FPC_ERROR_INTERNAL_35 = 35, /* AFD sensor commad did not complete. */ - FPC_ERROR_INTERNAL_36 = 36, /* AFD wrong runlevel detected after calibration. */ - FPC_ERROR_INTERNAL_37 = 37, /* Wrong rrs size. */ - FPC_ERROR_INTERNAL_38 = 38, /* There was a finger on the sensor when calibrating finger detect. */ - FPC_ERROR_INTERNAL_39 = 39, /* The calculated calibration value is larger than max. */ - FPC_ERROR_INTERNAL_40 = 40, /* The sensor fifo always underflows */ - FPC_ERROR_INTERNAL_41 = 41, /* The oscillator calibration resulted in a too high or low value */ - FPC_ERROR_INTERNAL_42 = 42, /* Sensor driver was opened with NULL configuration */ - FPC_ERROR_INTERNAL_43 = 43, /* Sensor driver as opened with NULL hw descriptor */ - FPC_ERROR_INTERNAL_44 = 44, /* Error occured during image drive test */ -}; - -/* FPC specific initialization function to fill their context */ -int fp_sensor_open(void *ctx, uint32_t ctx_size); - -/* - * Get library version code. - * version code contains three digits. x.y.z - * x - major version - * y - minor version - * z - build index - */ -const char *fp_sensor_get_version(void); - -typedef struct { - uint32_t num_defective_pixels; -} fp_sensor_info_t; - -/** - * fp_sensor_maintenance runs a test for defective pixels and should - * be triggered periodically by the client. Internally, a defective - * pixel list is maintained and the algorithm will compensate for - * any defect pixels when matching towards a template. - * - * The defective pixel update will abort and return an error if any of - * the finger detect zones are covered. A client can call - * fp_sensor_finger_status to determine the current status. - * - * @param[in] image_data pointer to FP_SENSOR_IMAGE_SIZE bytes of memory - * @param[out] fp_sensor_info Structure containing output data. - * - * @return - * - 0 on success - * - negative value on error - */ -int fp_sensor_maintenance(uint8_t *image_data, - fp_sensor_info_t *fp_sensor_info); - -/* Read the HWID from the sensor. */ -int fpc_check_hwid(void); - -#endif /* __CROS_EC_FPC_PRIVATE_H */ diff --git a/driver/fingerprint/fpc/libfp/fpc_sensor_pal.c b/driver/fingerprint/fpc/libfp/fpc_sensor_pal.c deleted file mode 100644 index 35c07b464a..0000000000 --- a/driver/fingerprint/fpc/libfp/fpc_sensor_pal.c +++ /dev/null @@ -1,60 +0,0 @@ -/* Copyright 2017 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. - */ -/* FPC Platform Abstraction Layer callbacks */ - -#include "common.h" -#include "console.h" -#include "fpsensor.h" -#include "fpc_sensor_pal.h" -#include "shared_mem.h" -#include "spi.h" -#include "timer.h" -#include "uart.h" -#include "util.h" - -#define CPRINTF(format, args...) cprintf(CC_FP, format, ## args) -#define CPRINTS(format, args...) cprints(CC_FP, format, ## args) - -void fpc_pal_log_entry(const char *tag, int log_level, const char *format, ...) -{ - va_list args; - - va_start(args, format); - uart_puts(tag); - uart_vprintf(format, args); - va_end(args); -} - -int fpc_pal_delay_us(uint64_t us) -{ - if (us > 250) - usleep(us); - else - udelay(us); - return 0; -} - -int fpc_pal_spi_writeread(fpc_device_t device, uint8_t *tx_buf, uint8_t *rx_buf, - uint32_t size) -{ - return spi_transaction(SPI_FP_DEVICE, tx_buf, size, rx_buf, - SPI_READBACK_ALL); -} - -int fpc_pal_wait_irq(fpc_device_t device, fpc_pal_irq_t irq_type) -{ - /* TODO: b/72360575 */ - return EC_SUCCESS; /* just lie about it, libfpsensor prefers... */ -} - -int32_t FpcMalloc(void **data, size_t size) -{ - return shared_mem_acquire(size, (char **)data); -} - -void FpcFree(void **data) -{ - shared_mem_release(*data); -} diff --git a/driver/fingerprint/fpc/libfp/fpc_sensor_pal.h b/driver/fingerprint/fpc/libfp/fpc_sensor_pal.h deleted file mode 100644 index 78376863f1..0000000000 --- a/driver/fingerprint/fpc/libfp/fpc_sensor_pal.h +++ /dev/null @@ -1,118 +0,0 @@ -/* Copyright 2017 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. - */ - -#ifndef FPC_PAL_SENSOR_H_ -#define FPC_PAL_SENSOR_H_ - -#include <stdint.h> - -typedef void *fpc_device_t; - -/** - * @brief Used to describe an interrupt - */ -typedef enum { - IRQ_INT_TRIG = 0x01, /**< Internally triggered by sensor (fast interrupt) **/ - IRQ_EXT_TRIG = 0x02 /**< Externally triggered by event outside sensor (may take long time) **/ -} fpc_pal_irq_t; - -/** - * @brief Write sensor access buffer to SPI interface - * - * @param[in] device Client's device handle. - * @param[in] access_buffer Buffer holding data to write. - * @param[in] access_buffer_size Size of the access buffer. - * - * @return 0 on success. - * negative value on error. - */ -int fpc_pal_spi_write(fpc_device_t device, uint8_t *access_buffer, - uint32_t access_buffer_size); - -/** - * @brief Write and read sensor access buffer to SPI interface - * - * SPI transfers always write the same number of bytes as they read, - * hence the size of tx_buffer and rx_buffer must be the same. - * - * @param[in] device Client's device handle. - * @param[in] tx_buffer Buffer holding data to write. - * @param[in] rx_buffer Buffer where read data will be stored. - * @param[in] size Size of tx and rx buffer. - * - * @return 0 on success. - * negative value on error. - */ -int fpc_pal_spi_writeread(fpc_device_t device, uint8_t *tx_buffer, - uint8_t *rx_buffer, uint32_t size); - -/** - * @brief Wait for IRQ - * - * @param[in] device Client's device handle. - * @param[in] irq_type The expected IRQ type. - * - * @return 0 on success. - * negative value on error. - */ -int fpc_pal_wait_irq(fpc_device_t device, fpc_pal_irq_t irq_type); - -/** - * @brief Get time - * - * @param[out] time_us Timestamp in microseconds. - * - * Not all platforms have microsecond resolution. These should - * return time in terms of hole milliseconds. - * - * @return 0 on success. - * negative value on error. - */ -int fpc_pal_get_time(uint64_t *time_us); - -/** - * @brief Delay function - * - * @param[in] us Delay in microseconds. - * - * Not all platforms have microsecond resolution. These should - * delay in terms of hole milliseconds. - * - * @return 0 on success. - * negative value on error. - */ -int fpc_pal_delay_us(uint64_t us); - -/** - * @brief Get platform SPI clock frequency - * - * @param[in] device Client's device handle. - * @param[out] speed_hz SPI frequency in hertz. - * - * Required by platform for adaptive SPI calculations. - * - * @return 0 on success. - * negative value on error. - */ -int fpc_pal_spi_get_speed_hz(fpc_device_t device, uint32_t *speed_hz); - -/** - * @brief Print SDK log strings - * - * @param[in] tag sensor sdk log prefix - * @param[in] log_level FPC_SENSOR_SDK_LOG_LEVEL_DEBUG - debug print - * FPC_SENSOR_SDK_LOG_LEVEL_INFO - information print - * FPC_SENSOR_SDK_LOG_LEVEL_ERROR - error print - * @param[in] format the format specifier. - * @param[in] ... additional arguments. - * - */ -#define FPC_SENSOR_SDK_LOG_LEVEL_DEBUG (1) -#define FPC_SENSOR_SDK_LOG_LEVEL_INFO (2) -#define FPC_SENSOR_SDK_LOG_LEVEL_ERROR (3) -#define FPC_SENSOR_SDK_LOG_LEVEL_DISABLED (4) -void fpc_pal_log_entry(const char *tag, int log_level, const char *format, ...); - -#endif // FPC_PAL_SENSOR_H_ diff --git a/driver/fingerprint/fpsensor.h b/driver/fingerprint/fpsensor.h deleted file mode 100644 index ac7e31fb6a..0000000000 --- a/driver/fingerprint/fpsensor.h +++ /dev/null @@ -1,33 +0,0 @@ -/* Copyright 2019 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. - */ - -#ifndef __CROS_EC_DRIVER_FINGERPRINT_FPSENSOR_H_ -#define __CROS_EC_DRIVER_FINGERPRINT_FPSENSOR_H_ - -#if defined(HAVE_PRIVATE) && !defined(EMU_BUILD) -#define HAVE_FP_PRIVATE_DRIVER -#if defined(CONFIG_FP_SENSOR_ELAN80) || defined(CONFIG_FP_SENSOR_ELAN515) -#include "elan/elan_sensor.h" -#else -#include "fpc/fpc_sensor.h" -#endif -#else -/* These values are used by the host (emulator) tests. */ -#define FP_SENSOR_IMAGE_SIZE 0 -#define FP_SENSOR_RES_X 0 -#define FP_SENSOR_RES_Y 0 -#define FP_ALGORITHM_TEMPLATE_SIZE 0 -#define FP_MAX_FINGER_COUNT 5 -#endif - -#if defined(HAVE_PRIVATE) && defined(TEST_BUILD) -/* - * For unittest in a private build, enable driver-related code in - * common/fpsensor/ so that they can be tested (with fp_sensor_mock). - */ -#define HAVE_FP_PRIVATE_DRIVER -#endif - -#endif /* __CROS_EC_DRIVER_FINGERPRINT_FPSENSOR_H_ */ diff --git a/driver/gl3590.c b/driver/gl3590.c deleted file mode 100644 index cb8d914d8c..0000000000 --- a/driver/gl3590.c +++ /dev/null @@ -1,346 +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 "console.h" -#include "hooks.h" -#include "i2c.h" -#include "system.h" -#include "util.h" -#include "pwr_defs.h" - -#include "gl3590.h" - -#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_I2C, format, ## args) - -/* GL3590 is unique in terms of i2c_read, since it doesn't support repeated - * start sequence. One need to issue two separate transactions - first is write - * with a register offset, then after a delay second transaction is actual read. - */ -int gl3590_read(int hub, uint8_t reg, uint8_t *data, int count) -{ - int rv; - struct uhub_i2c_iface_t *uhub_p = &uhub_config[hub]; - - i2c_lock(uhub_p->i2c_host_port, 1); - rv = i2c_xfer_unlocked(uhub_p->i2c_host_port, - uhub_p->i2c_addr, - ®, 1, - NULL, 0, - I2C_XFER_SINGLE); - i2c_lock(uhub_p->i2c_host_port, 0); - - if (rv) - return rv; - - /* GL3590 requires at least 1ms between consecutive i2c transactions */ - udelay(MSEC); - - i2c_lock(uhub_p->i2c_host_port, 1); - rv = i2c_xfer_unlocked(uhub_p->i2c_host_port, - uhub_p->i2c_addr, - NULL, 0, - data, count, - I2C_XFER_SINGLE); - i2c_lock(uhub_p->i2c_host_port, 0); - - /* - * GL3590 requires at least 1ms between consecutive i2c transactions. - * Make sure that we are safe across API calls. - */ - udelay(MSEC); - - return rv; -}; - -int gl3590_write(int hub, uint8_t reg, uint8_t *data, int count) -{ - int rv; - uint8_t buf[5]; - struct uhub_i2c_iface_t *uhub_p = &uhub_config[hub]; - - /* GL3590 registers accept 4 bytes at max */ - if (count > (sizeof(buf) - 1)) { - ccprintf("Too many bytes to write"); - return EC_ERROR_INVAL; - } - - buf[0] = reg; - memcpy(&buf[1], data, count); - - i2c_lock(uhub_p->i2c_host_port, 1); - rv = i2c_xfer_unlocked(uhub_p->i2c_host_port, - uhub_p->i2c_addr, - buf, count + 1, - NULL, 0, - I2C_XFER_SINGLE); - i2c_lock(uhub_p->i2c_host_port, 0); - - /* - * GL3590 requires at least 1ms between consecutive i2c transactions. - * Make sure that we are safe across API calls. - */ - udelay(MSEC); - - return rv; -} - -/* - * Basic initialization of GL3590 I2C interface. - * - * Please note, that I2C interface is online not earlier than ~50ms after - * RESETJ# is deasserted. Platform should check that PGREEN_A_SMD pin is - * asserted. This init function shouldn't be invoked until that time. - */ -void gl3590_init(int hub) -{ - uint8_t tmp; - struct uhub_i2c_iface_t *uhub_p = &uhub_config[hub]; - - if (uhub_p->initialized) - return; - - if (gl3590_read(hub, GL3590_HUB_MODE_REG, &tmp, 1)) { - CPRINTF("GL3590: Cannot read HUB_MODE register"); - return; - } - if ((tmp & GL3590_HUB_MODE_I2C_READY) == 0) - CPRINTF("GL3590 interface isn't ready, consider deferring " - "this init\n"); - - /* Deassert INTR# signal */ - tmp = GL3590_INT_CLEAR; - if (gl3590_write(hub, GL3590_INT_REG, &tmp, 1)) { - CPRINTF("GL3590: Cannot write to INT register"); - return; - }; - - uhub_p->initialized = 1; -} - -/* - * GL3590 chip may drive I2C_SDA and I2C_SCL lines for 200ms (max) after it is - * released from reset (through gpio de-assertion in main()). In order to avoid - * broken I2C transactions, we need to add an extra delay before any activity on - * the I2C bus in the system. - */ -static void gl3590_delay_on_init(void) -{ - CPRINTS("Applying 200ms delay for GL3590 to release I2C lines"); - udelay(200 * MSEC); -} -DECLARE_HOOK(HOOK_INIT, gl3590_delay_on_init, HOOK_PRIO_INIT_I2C - 1); - -void gl3590_irq_handler(int hub) -{ - uint8_t buf = 0; - uint8_t res_reg[2]; - struct uhub_i2c_iface_t *uhub_p = &uhub_config[hub]; - - if (!uhub_p->initialized) - return; - - /* Verify that irq is pending */ - if (gl3590_read(hub, GL3590_INT_REG, &buf, sizeof(buf))) { - ccprintf("Cannot read from the host hub i2c\n"); - goto exit; - } - - if ((buf & GL3590_INT_PENDING) == 0) { - ccprintf("Invalid hub event\n"); - goto exit; - } - - /* Get the hub event reason */ - if (gl3590_read(hub, GL3590_RESPONSE_REG, res_reg, sizeof(res_reg))) { - ccprintf("Cannot read from the host hub i2c\n"); - goto exit; - } - - if ((res_reg[0] & GL3590_RESPONSE_REG_SYNC_MASK) == 0) - ccprintf("Host hub response: "); - else - ccprintf("Host hub event! "); - - switch(res_reg[0]) { - case 0x0: - ccprintf("No response"); - break; - case 0x1: - ccprintf("Successful"); - break; - case 0x2: - ccprintf("Invalid command"); - break; - case 0x3: - ccprintf("Invalid arguments"); - break; - case 0x4: - ccprintf("Invalid port: %d", res_reg[1]); - break; - case 0x5: - ccprintf("Command not completed"); - break; - case 0x80: - ccprintf("Reset complete"); - break; - case 0x81: - ccprintf("Power operation mode change"); - break; - case 0x82: - ccprintf("Connect change"); - break; - case 0x83: - ccprintf("Error on the specific port"); - break; - case 0x84: - ccprintf("Hub state change"); - break; - case 0x85: - ccprintf("SetFeature PORT_POWER failure"); - break; - default: - ccprintf("Unknown value: 0x%0x", res_reg[0]); - } - ccprintf("\n"); - - if (res_reg[1]) - ccprintf("Affected port %d\n", res_reg[1]); - -exit: - /* Try to clear interrupt */ - buf = GL3590_INT_CLEAR; - gl3590_write(hub, GL3590_INT_REG, &buf, sizeof(buf)); -} - -enum ec_error_list gl3590_ufp_pwr(int hub, struct pwr_con_t *pwr) -{ - uint8_t hub_sts, hub_mode; - int rv = 0; - struct uhub_i2c_iface_t *uhub_p = &uhub_config[hub]; - - if (!uhub_p->initialized) - return EC_ERROR_HW_INTERNAL; - - if (gl3590_read(hub, GL3590_HUB_STS_REG, &hub_sts, sizeof(hub_sts))) { - CPRINTF("Error reading HUB_STS %d\n", rv); - return EC_ERROR_BUSY; - } - - pwr->volts = 5; - - switch ((hub_sts & GL3590_HUB_STS_HOST_PWR_MASK) >> - GL3590_HUB_STS_HOST_PWR_SHIFT) { - case GL3590_DEFAULT_HOST_PWR_SRC: - if (gl3590_read(hub, GL3590_HUB_MODE_REG, &hub_mode, - sizeof(hub_mode))) { - CPRINTF("Error reading HUB_MODE %d\n", rv); - return EC_ERROR_BUSY; - } - if (hub_mode & GL3590_HUB_MODE_USB3_EN) { - pwr->milli_amps = 900; - return EC_SUCCESS; - } else if (hub_mode & GL3590_HUB_MODE_USB2_EN) { - pwr->milli_amps = 500; - return EC_SUCCESS; - } else { - CPRINTF("GL3590: Neither USB3 nor USB2 hubs " - "configured\n"); - return EC_ERROR_HW_INTERNAL; - } - case GL3590_1_5_A_HOST_PWR_SRC: - pwr->milli_amps = 1500; - return EC_SUCCESS; - case GL3590_3_0_A_HOST_PWR_SRC: - pwr->milli_amps = 3000; - return EC_SUCCESS; - default: - CPRINTF("GL3590: Unkown host power source %d\n", hub_sts); - return EC_ERROR_UNKNOWN; - } -} - -#define GL3590_EN_PORT_MAX_RETRY_COUNT 10 - -int gl3590_enable_ports(int hub, uint8_t port_mask, bool enable) -{ - uint8_t buf[4] = {0}; - uint8_t en_mask = 0; - uint8_t tmp; - int rv, i; - struct uhub_i2c_iface_t *uhub_p = &uhub_config[hub]; - - if (!uhub_p->initialized) - return EC_ERROR_HW_INTERNAL; - - if (!enable) - en_mask = port_mask; - - buf[0] = en_mask; - buf[2] = port_mask; - - for (i = 1; i <= GL3590_EN_PORT_MAX_RETRY_COUNT; i++) { - rv = gl3590_write(hub, GL3590_PORT_DISABLED_REG, buf, - sizeof(buf)); - if (rv) - return rv; - - usleep(200 * MSEC); - - /* Verify whether port is enabled/disabled */ - rv = gl3590_read(hub, GL3590_PORT_EN_STS_REG, &tmp, 1); - if (rv) - return rv; - - if (enable && ((tmp & port_mask) == port_mask)) - break; - if (!enable && ((tmp & port_mask) == 0)) - break; - - if (i > GL3590_EN_PORT_MAX_RETRY_COUNT) { - CPRINTF("GL3590: Failed to %s port 0x%x\n", - enable ? "enable" : "disable", port_mask); - return EC_ERROR_HW_INTERNAL; - } - - CPRINTF("GL3590: Port %s retrying.. %d/%d\n" - "Port status is 0x%x\n", enable ? "enable" : "disable", - i, GL3590_EN_PORT_MAX_RETRY_COUNT, tmp); - } - - return EC_SUCCESS; -} - -#ifdef CONFIG_CMD_GL3590 -static int command_gl3590(int argc, char **argv) -{ - char *e; - int port; - - if (argc < 2) - return EC_ERROR_PARAM_COUNT; - - port = strtoi(argv[2], &e, 0); - if (*e) - return EC_ERROR_PARAM2; - - if (strcasecmp(argv[1], "enable") == 0) { - if (!gl3590_enable_ports(0, port, 1)) - return EC_SUCCESS; - else - return EC_ERROR_HW_INTERNAL; - } else if (strcasecmp(argv[1], "disable") == 0) { - if (!gl3590_enable_ports(0, port, 0)) - return EC_SUCCESS; - else - return EC_ERROR_HW_INTERNAL; - } - - return EC_ERROR_PARAM1; -} -DECLARE_CONSOLE_COMMAND(gl3590, command_gl3590, - "<enable | disable> <port_bitmask>", - "Manage GL3590 USB3.1 hub and its ports"); -#endif /* CONFIG_CMD_GL3590 */ diff --git a/driver/gl3590.h b/driver/gl3590.h deleted file mode 100644 index 931035d95e..0000000000 --- a/driver/gl3590.h +++ /dev/null @@ -1,63 +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 "pwr_defs.h" -#include "stdbool.h" - -/* Registers definitions */ -#define GL3590_HUB_MODE_REG 0x0 -#define GL3590_HUB_MODE_I2C_READY 0x1 -#define GL3590_HUB_MODE_USB2_EN 0x2 -#define GL3590_HUB_MODE_USB3_EN 0x4 -#define GL3590_INT_REG 0x1 -#define GL3590_INT_PENDING 0x1 -#define GL3590_INT_CLEAR 0x1 -#define GL3590_RESPONSE_REG 0x2 -#define GL3590_RESPONSE_REG_SYNC_MASK 0x80 -#define GL3590_PORT_DISABLED_REG 0x4 -#define GL3590_PORT_EN_STS_REG 0x8 -#define GL3590_HUB_STS_REG 0xA -#define GL3590_HUB_STS_HOST_PWR_MASK 0x30 -#define GL3590_HUB_STS_HOST_PWR_SHIFT 4 -#define GL3590_DEFAULT_HOST_PWR_SRC 0x0 -#define GL3590_1_5_A_HOST_PWR_SRC 0x1 -#define GL3590_3_0_A_HOST_PWR_SRC 0x2 - -#define GL3590_I2C_ADDR0 0x50 - -/* Read GL3590 I2C register */ -int gl3590_read(int hub, uint8_t reg, uint8_t *data, int count); - -/* Write to GL3590 I2C register */ -int gl3590_write(int hub, uint8_t reg, uint8_t *data, int count); - -/* Initialize GL3590 I2C interface */ -void gl3590_init(int hub); - -/* Generic handler for GL3590 IRQ, can be registered/invoked by platform */ -void gl3590_irq_handler(int hub); - -/* Get power capabilities of UFP host connection */ -enum ec_error_list gl3590_ufp_pwr(int hub, struct pwr_con_t *pwr); - -#define GL3590_DFP1 BIT(0) -#define GL3590_DFP2 BIT(1) -#define GL3590_DFP3 BIT(2) -#define GL3590_DFP4 BIT(3) -#define GL3590_DFP5 BIT(4) -#define GL3590_DFP6 BIT(5) -#define GL3590_DFP7 BIT(6) -#define GL3590_DFP8 BIT(7) - -/* Enable/disable power to particular downstream facing ports */ -int gl3590_enable_ports(int hub, uint8_t port_mask, bool enable); - -/* Generic USB HUB I2C interface */ -struct uhub_i2c_iface_t { - int i2c_host_port; - int i2c_addr; - int initialized; -}; -extern struct uhub_i2c_iface_t uhub_config[]; diff --git a/driver/gyro_l3gd20h.c b/driver/gyro_l3gd20h.c deleted file mode 100644 index 77dd888542..0000000000 --- a/driver/gyro_l3gd20h.c +++ /dev/null @@ -1,392 +0,0 @@ -/* 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. - */ - -/** - * L3GD20H gyro module for Chrome EC 3D digital gyroscope. - */ - -#include "accelgyro.h" -#include "common.h" -#include "console.h" -#include "driver/gyro_l3gd20h.h" -#include "hooks.h" -#include "i2c.h" -#include "task.h" -#include "util.h" - -#define CPUTS(outstr) cputs(CC_ACCEL, outstr) -#define CPRINTS(format, args...) cprints(CC_ACCEL, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_ACCEL, format, ## args) - -/* - * Struct for pairing an engineering value with the register value for a - * parameter. - */ -struct gyro_param_pair { - int val; /* Value in engineering units. */ - int reg_val; /* Corresponding register value. */ -}; - -/* - * List of angular rate range values in +/-dps's - * and their associated register values. - */ -const struct gyro_param_pair dps_ranges[] = { - {245, L3GD20_DPS_SEL_245}, - {500, L3GD20_DPS_SEL_500}, - {2000, L3GD20_DPS_SEL_2000_0}, - {2000, L3GD20_DPS_SEL_2000_1} -}; - -static inline const struct gyro_param_pair *get_range_table( - enum motionsensor_type type, int *psize) -{ - if (psize) - *psize = ARRAY_SIZE(dps_ranges); - return dps_ranges; -} - -/* List of ODR values in mHz and their associated register values. */ -const struct gyro_param_pair gyro_odr[] = { - {0, L3GD20_ODR_PD | L3GD20_LOW_ODR_MASK}, - {12500, L3GD20_ODR_12_5HZ | L3GD20_ODR_PD_MASK | L3GD20_LOW_ODR_MASK}, - {25000, L3GD20_ODR_25HZ | L3GD20_ODR_PD_MASK | L3GD20_LOW_ODR_MASK}, - {50000, L3GD20_ODR_50HZ_0 | L3GD20_ODR_PD_MASK | L3GD20_LOW_ODR_MASK}, - {50000, L3GD20_ODR_50HZ_1 | L3GD20_ODR_PD_MASK | L3GD20_LOW_ODR_MASK}, - {100000, L3GD20_ODR_100HZ | L3GD20_ODR_PD_MASK}, - {200000, L3GD20_ODR_200HZ | L3GD20_ODR_PD_MASK}, - {400000, L3GD20_ODR_400HZ | L3GD20_ODR_PD_MASK}, - {800000, L3GD20_ODR_800HZ | L3GD20_ODR_PD_MASK}, -}; - -static inline const struct gyro_param_pair *get_odr_table( - enum motionsensor_type type, int *psize) -{ - if (psize) - *psize = ARRAY_SIZE(gyro_odr); - return gyro_odr; -} - -static inline int get_ctrl_reg(enum motionsensor_type type) -{ - return L3GD20_CTRL_REG1; -} - -static inline int get_xyz_reg(enum motionsensor_type type) -{ - return L3GD20_OUT_X_L | BIT(7); -} - -/** - * @return reg value that matches the given engineering value passed in. - * The round_up flag is used to specify whether to round up or down. - * Note, this function always returns a valid reg value. If the request is - * outside the range of values, it returns the closest valid reg value. - */ -static int get_reg_val(const int eng_val, const int round_up, - const struct gyro_param_pair *pairs, const int size) -{ - int i; - for (i = 0; i < size - 1; i++) { - if (eng_val <= pairs[i].val) - break; - - if (eng_val < pairs[i+1].val) { - if (round_up) - i += 1; - break; - } - } - return pairs[i].reg_val; -} - -/** - * @return engineering value that matches the given reg val - */ -static int get_engineering_val(const int reg_val, - const struct gyro_param_pair *pairs, const int size) -{ - int i; - for (i = 0; i < size; i++) { - if (reg_val == pairs[i].reg_val) - break; - } - return pairs[i].val; -} - -/** - * Read register from Gyrometer. - */ -static inline int raw_read8(const int port, const int addr, const int reg, - int *data_ptr) -{ - return i2c_read8(port, addr, reg, data_ptr); -} - -/** - * Write register from Gyrometer. - */ -static inline int raw_write8(const int port, const int addr, const int reg, - int data) -{ - return i2c_write8(port, addr, reg, data); -} - -static int set_range(struct motion_sensor_t *s, - int range, - int rnd) -{ - int ret, ctrl_val, range_tbl_size; - uint8_t ctrl_reg, reg_val; - const struct gyro_param_pair *ranges; - - ctrl_reg = L3GD20_CTRL_REG4; - ranges = get_range_table(s->type, &range_tbl_size); - - reg_val = get_reg_val(range, rnd, ranges, range_tbl_size); - - /* - * Lock Gyro resource to prevent another task from attempting - * to write Gyro parameters until we are done. - */ - mutex_lock(s->mutex); - - ret = raw_read8(s->port, s->addr, ctrl_reg, &ctrl_val); - if (ret != EC_SUCCESS) - goto gyro_cleanup; - - ctrl_val = (ctrl_val & ~L3GD20_RANGE_MASK) | reg_val; - ret = raw_write8(s->port, s->addr, ctrl_reg, ctrl_val); - - /* Now that we have set the range, update the driver's value. */ - if (ret == EC_SUCCESS) - s->current_range = get_engineering_val(reg_val, ranges, - range_tbl_size); - -gyro_cleanup: - mutex_unlock(s->mutex); - return EC_SUCCESS; -} - -static int get_resolution(const struct motion_sensor_t *s) -{ - return L3GD20_RESOLUTION; -} - -static int set_data_rate(const struct motion_sensor_t *s, - int rate, - int rnd) -{ - int ret, val, odr_tbl_size; - uint8_t ctrl_reg, reg_val; - const struct gyro_param_pair *data_rates; - struct l3gd20_data *data = s->drv_data; - - ctrl_reg = get_ctrl_reg(s->type); - data_rates = get_odr_table(s->type, &odr_tbl_size); - reg_val = get_reg_val(rate, rnd, data_rates, odr_tbl_size); - - /* - * Lock gyro resource to prevent another task from attempting - * to write gyro parameters until we are done. - */ - mutex_lock(s->mutex); - - ret = raw_read8(s->port, s->addr, ctrl_reg, &val); - if (ret != EC_SUCCESS) - goto gyro_cleanup; - - val = (val & ~(L3GD20_ODR_MASK | L3GD20_ODR_PD_MASK)) | - (reg_val & ~L3GD20_LOW_ODR_MASK); - ret = raw_write8(s->port, s->addr, ctrl_reg, val); - - /* Now that we have set the odr, update the driver's value. */ - if (ret == EC_SUCCESS) - data->base.odr = get_engineering_val(reg_val, data_rates, - odr_tbl_size); - - ret = raw_read8(s->port, s->addr, L3GD20_LOW_ODR, &val); - if (ret != EC_SUCCESS) - goto gyro_cleanup; - - /* We need to clear low_ODR bit for higher data rates */ - if (reg_val & L3GD20_LOW_ODR_MASK) - val |= 1; - else - val &= ~1; - - ret = raw_write8(s->port, s->addr, L3GD20_LOW_ODR, val); - if (ret != EC_SUCCESS) - goto gyro_cleanup; - - /* CTRL_REG5 24h - * [7] low-power mode = 0; - * [6] fifo disabled = 0; - * [5] Stop on fth = 0; - * [4] High pass filter enable = 1; - * [3:2] int1_sel = 0; - * [1:0] out_sel = 1; - */ - ret = raw_read8(s->port, s->addr, L3GD20_CTRL_REG5, &val); - if (ret != EC_SUCCESS) - goto gyro_cleanup; - - val |= BIT(4); /* high-pass filter enabled */ - val |= BIT(0); /* data in data reg are high-pass filtered */ - ret = raw_write8(s->port, s->addr, L3GD20_CTRL_REG5, val); - if (ret != EC_SUCCESS) - goto gyro_cleanup; - - ret = raw_read8(s->port, s->addr, L3GD20_CTRL_REG2, &val); - if (ret != EC_SUCCESS) - goto gyro_cleanup; - - /* - * Table 25. High pass filter mode configuration - * Table 26. High pass filter cut off frequency configuration - */ - val &= 0xf0; - val |= 0x04; - ret = raw_write8(s->port, s->addr, L3GD20_CTRL_REG2, val); - -gyro_cleanup: - mutex_unlock(s->mutex); - return ret; -} - -static int get_data_rate(const struct motion_sensor_t *s) -{ - struct l3gd20_data *data = (struct l3gd20_data *)s->drv_data; - - return data->base.odr; -} - -static int set_offset(const struct motion_sensor_t *s, - const int16_t *offset, - int16_t temp) -{ - /* temperature is ignored */ - struct l3gd20_data *data = s->drv_data; - data->offset[X] = offset[X]; - data->offset[Y] = offset[Y]; - data->offset[Z] = offset[Z]; - return EC_SUCCESS; -} - -static int get_offset(const struct motion_sensor_t *s, - int16_t *offset, - int16_t *temp) -{ - struct l3gd20_data *data = s->drv_data; - offset[X] = data->offset[X]; - offset[Y] = data->offset[Y]; - offset[Z] = data->offset[Z]; - *temp = EC_MOTION_SENSE_INVALID_CALIB_TEMP; - return EC_SUCCESS; -} - -static int is_data_ready(const struct motion_sensor_t *s, int *ready) -{ - int ret, tmp; - - ret = raw_read8(s->port, s->addr, L3GD20_STATUS_REG, &tmp); - - if (ret != EC_SUCCESS) { - CPRINTS("%s type:0x%X RS Error", s->name, s->type); - return ret; - } - - *ready = (tmp & L3GD20_STS_ZYXDA_MASK) ? 1 : 0; - - return EC_SUCCESS; -} - -static int read(const struct motion_sensor_t *s, intv3_t v) -{ - uint8_t raw[6]; - uint8_t xyz_reg; - int ret, range, i, tmp = 0; - struct l3gd20_data *data = s->drv_data; - - ret = is_data_ready(s, &tmp); - if (ret != EC_SUCCESS) - return ret; - - /* - * If sensor data is not ready, return the previous read data. - * Note: return success so that motion senor task can read again - * to get the latest updated sensor data quickly. - */ - if (!tmp) { - if (v != s->raw_xyz) - memcpy(v, s->raw_xyz, sizeof(s->raw_xyz)); - return EC_SUCCESS; - } - - xyz_reg = get_xyz_reg(s->type); - - /* Read 6 bytes starting at xyz_reg */ - i2c_block_read(s->port, s->addr, xyz_reg, raw, 6); - - if (ret != EC_SUCCESS) { - CPRINTS("%s type:0x%X RD XYZ Error", s->name, s->type); - return ret; - } - - for (i = X; i <= Z; i++) - v[i] = ((int16_t)((raw[i * 2 + 1] << 8) | raw[i * 2])); - - rotate(v, *s->rot_standard_ref, v); - - /* apply offset in the device coordinates */ - range = s->current_range; - for (i = X; i <= Z; i++) - v[i] += (data->offset[i] << 5) / range; - - return EC_SUCCESS; -} - -static int init(struct motion_sensor_t *s) -{ - int ret = 0, tmp; - - ret = raw_read8(s->port, s->addr, L3GD20_WHO_AM_I_REG, &tmp); - if (ret) - return ret; - - if (tmp != L3GD20_WHO_AM_I) - return EC_ERROR_ACCESS_DENIED; - - /* All axes are enabled */ - ret = raw_write8(s->port, s->addr, L3GD20_CTRL_REG1, 0x0f); - if (ret) - return ret; - - mutex_lock(s->mutex); - ret = raw_read8(s->port, s->addr, L3GD20_CTRL_REG4, &tmp); - if (ret) { - mutex_unlock(s->mutex); - return ret; - } - - tmp |= L3GD20_BDU_ENABLE; - ret = raw_write8(s->port, s->addr, L3GD20_CTRL_REG4, tmp); - mutex_unlock(s->mutex); - if (ret) - return ret; - - return sensor_init_done(s); -} - -const struct accelgyro_drv l3gd20h_drv = { - .init = init, - .read = read, - .set_range = set_range, - .get_resolution = get_resolution, - .set_data_rate = set_data_rate, - .get_data_rate = get_data_rate, - .set_offset = set_offset, - .get_offset = get_offset, -}; diff --git a/driver/gyro_l3gd20h.h b/driver/gyro_l3gd20h.h deleted file mode 100644 index 7a7ed6b7da..0000000000 --- a/driver/gyro_l3gd20h.h +++ /dev/null @@ -1,107 +0,0 @@ -/* 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. - */ - -/* L3GD20H gyro module for Chrome EC */ - -#ifndef __CROS_EC_GYRO_L3GD20H_H -#define __CROS_EC_GYRO_L3GD20H_H - -#include "accelgyro.h" -#include "task.h" - -/* - * 7-bit address is 110101Xb. Where 'X' is determined - * by the voltage on the ADDR pin. - */ -#define L3GD20_ADDR0_FLAGS 0x6a -#define L3GD20_ADDR1_FLAGS 0x6b - -/* who am I */ -#define L3GD20_WHO_AM_I 0xd7 - -/* Chip specific registers. */ -#define L3GD20_WHO_AM_I_REG 0x0f -#define L3GD20_CTRL_REG1 0x20 -#define L3GD20_CTRL_REG2 0x21 -#define L3GD20_CTRL_REG3 0x22 -#define L3GD20_CTRL_REG4 0x23 -#define L3GD20_CTRL_REG5 0x24 -#define L3GD20_CTRL_REFERENCE 0x25 -#define L3GD20_OUT_TEMP 0x26 -#define L3GD20_STATUS_REG 0x27 -#define L3GD20_OUT_X_L 0x28 -#define L3GD20_OUT_X_H 0x29 -#define L3GD20_OUT_Y_L 0x2a -#define L3GD20_OUT_Y_H 0x2b -#define L3GD20_OUT_Z_L 0x2c -#define L3GD20_OUT_Z_H 0x2d -#define L3GD20_FIFO_CTRL_REG 0x2e -#define L3GD20_FIFO_SRC_REG 0x2f -#define L3GD20_INT1_CFG 0x30 -#define L3GD20_INT1_SRC 0x31 -#define L3GD20_INT1_TSH_XH 0x32 -#define L3GD20_INT1_TSH_XL 0x33 -#define L3GD20_INT1_TSH_YH 0x34 -#define L3GD20_INT1_TSH_YL 0x35 -#define L3GD20_INT1_TSH_ZH 0x36 -#define L3GD20_INT1_TSH_ZL 0x37 -#define L3GD20_INT1_DURATION 0x38 -#define L3GD20_LOW_ODR 0x39 - -#define L3GD20_DPS_SEL_245 (0 << 4) -#define L3GD20_DPS_SEL_500 BIT(4) -#define L3GD20_DPS_SEL_2000_0 (2 << 4) -#define L3GD20_DPS_SEL_2000_1 (3 << 4) - -#define L3GD20_ODR_PD (0 << 3) -#define L3GD20_ODR_12_5HZ (0 << 6) -#define L3GD20_ODR_25HZ BIT(6) -#define L3GD20_ODR_50HZ_0 (2 << 6) -#define L3GD20_ODR_50HZ_1 (3 << 6) -#define L3GD20_ODR_100HZ (0 << 6) -#define L3GD20_ODR_200HZ BIT(6) -#define L3GD20_ODR_400HZ (2 << 6) -#define L3GD20_ODR_800HZ (3 << 6) - -#define L3GD20_ODR_MASK (3 << 6) -#define L3GD20_STS_ZYXDA_MASK BIT(3) -#define L3GD20_RANGE_MASK (3 << 4) -#define L3GD20_LOW_ODR_MASK BIT(0) -#define L3GD20_ODR_PD_MASK BIT(3) - -/* Min and Max sampling frequency in mHz */ -#define L3GD20_GYRO_MIN_FREQ 12500 -#define L3GD20_GYRO_MAX_FREQ \ - MOTION_MAX_SENSOR_FREQUENCY(800000, L3GD20_GYRO_MIN_FREQ) - -/* - * Register : STATUS_REG - * Address : 0X27 - */ -enum l3gd20_status { - L3GD20_STS_DOWN = 0x00, - L3GD20_STS_ZYXDA_UP = 0x08, -}; - -/* - * Register : CTRL_REG4 - * Address : 0X23 - * Bit Group Name: BDU - */ -enum l3gd20_bdu { - L3GD20_BDU_DISABLE = 0x00, - L3GD20_BDU_ENABLE = 0x80, -}; - -/* Sensor resolution in number of bits. This sensor has fixed resolution. */ -#define L3GD20_RESOLUTION 16 - -extern const struct accelgyro_drv l3gd20h_drv; -struct l3gd20_data { - struct accelgyro_saved_data_t base; - int16_t offset[3]; -}; - -#endif /* __CROS_EC_GYRO_L3GD20H_H */ diff --git a/driver/ina2xx.c b/driver/ina2xx.c deleted file mode 100644 index cf4389ba49..0000000000 --- a/driver/ina2xx.c +++ /dev/null @@ -1,167 +0,0 @@ -/* Copyright 2014 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. - * - * TI INA219/231 Current/Power monitor driver. - */ - -#include "console.h" -#include "hooks.h" -#include "i2c.h" -#include "system.h" -#include "timer.h" -#include "ina2xx.h" -#include "util.h" - -/* Console output macros */ -#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) - -/* I2C base address */ -#define INA2XX_I2C_ADDR_FLAGS 0x40 - -uint16_t ina2xx_read(uint8_t idx, uint8_t reg) -{ - int res; - int val; - - res = i2c_read16(I2C_PORT_MASTER, INA2XX_I2C_ADDR_FLAGS | idx, - reg, &val); - if (res) { - CPRINTS("INA2XX I2C read failed"); - return 0x0bad; - } - return (val >> 8) | ((val & 0xff) << 8); -} - -int ina2xx_write(uint8_t idx, uint8_t reg, uint16_t val) -{ - int res; - uint16_t be_val = (val >> 8) | ((val & 0xff) << 8); - - res = i2c_write16(I2C_PORT_MASTER, INA2XX_I2C_ADDR_FLAGS | idx, - reg, be_val); - if (res) - CPRINTS("INA2XX I2C write failed"); - return res; -} - -int ina2xx_init(uint8_t idx, uint16_t config, uint16_t calib) -{ - int res; - - res = ina2xx_write(idx, INA2XX_REG_CONFIG, config); - /* TODO(crosbug.com/p/29730): assume 1mA/LSB, revisit later */ - res |= ina2xx_write(idx, INA2XX_REG_CALIB, calib); - - return res; -} - -int ina2xx_get_voltage(uint8_t idx) -{ - uint16_t bv = ina2xx_read(idx, INA2XX_REG_BUS_VOLT); - return INA2XX_BUS_MV((int)bv); -} - -int ina2xx_get_current(uint8_t idx) -{ - int16_t curr = ina2xx_read(idx, INA2XX_REG_CURRENT); - /* Current calibration: LSB = 1mA/bit */ - return (int)curr; -} - -int ina2xx_get_power(uint8_t idx) -{ - uint16_t pow = ina2xx_read(idx, INA2XX_REG_POWER); - return INA2XX_POW_MW((int)pow); -} - -int ina2xx_get_mask(uint8_t idx) -{ - return ina2xx_read(idx, INA2XX_REG_MASK); -} - -int ina2xx_set_mask(uint8_t idx, uint16_t mask) -{ - return ina2xx_write(idx, INA2XX_REG_MASK, mask); -} - -int ina2xx_get_alert(uint8_t idx) -{ - return ina2xx_read(idx, INA2XX_REG_ALERT); -} - -int ina2xx_set_alert(uint8_t idx, uint16_t alert) -{ - return ina2xx_write(idx, INA2XX_REG_ALERT, alert); -} - -#ifdef CONFIG_CMD_INA -static void ina2xx_dump(uint8_t idx) -{ - uint16_t cfg = ina2xx_read(idx, INA2XX_REG_CONFIG); - int16_t sv = ina2xx_read(idx, INA2XX_REG_SHUNT_VOLT); - uint16_t bv = ina2xx_read(idx, INA2XX_REG_BUS_VOLT); - uint16_t pow = ina2xx_read(idx, INA2XX_REG_POWER); - int16_t curr = ina2xx_read(idx, INA2XX_REG_CURRENT); - uint16_t calib = ina2xx_read(idx, INA2XX_REG_CALIB); - uint16_t mask = ina2xx_read(idx, INA2XX_REG_MASK); - uint16_t alert = ina2xx_read(idx, INA2XX_REG_ALERT); - - ccprintf("Configuration: %04x\n", cfg); - ccprintf("Shunt voltage: %04x => %d uV\n", sv, - INA2XX_SHUNT_UV((int)sv)); - ccprintf("Bus voltage : %04x => %d mV\n", bv, - INA2XX_BUS_MV((int)bv)); - ccprintf("Power : %04x => %d mW\n", pow, - INA2XX_POW_MW((int)pow)); - ccprintf("Current : %04x => %d mA\n", curr, curr); - ccprintf("Calibration : %04x\n", calib); - ccprintf("Mask/Enable : %04x\n", mask); - ccprintf("Alert limit : %04x\n", alert); -} - -/*****************************************************************************/ -/* Console commands */ - -static int command_ina(int argc, char **argv) -{ - char *e; - int idx; - uint16_t val; - - if (argc < 2) - return EC_ERROR_PARAM_COUNT; - - idx = strtoi(argv[1], &e, 10); - if (*e) - return EC_ERROR_PARAM1; - - if (2 == argc) { /* dump all registers */ - ina2xx_dump(idx); - return EC_SUCCESS; - } else if (4 == argc) { - val = strtoi(argv[3], &e, 16); - if (*e) - return EC_ERROR_PARAM3; - - if (!strcasecmp(argv[2], "config")) { - ina2xx_write(idx, INA2XX_REG_CONFIG, val); - } else if (!strcasecmp(argv[2], "calib")) { - ina2xx_write(idx, INA2XX_REG_CALIB, val); - } else if (!strcasecmp(argv[2], "mask")) { - ina2xx_write(idx, INA2XX_REG_MASK, val); - } else if (!strcasecmp(argv[2], "alert")) { - ina2xx_write(idx, INA2XX_REG_ALERT, val); - } else { /* read one register */ - ccprintf("Invalid register: %s\n", argv[1]); - return EC_ERROR_INVAL; - } - return EC_SUCCESS; - } - - return EC_ERROR_INVAL; -} -DECLARE_CONSOLE_COMMAND(ina, command_ina, - "<index> [config|calib|mask|alert <val>]", - "INA2XX power/current sensing"); -#endif diff --git a/driver/ina2xx.h b/driver/ina2xx.h deleted file mode 100644 index ec1e1ed92f..0000000000 --- a/driver/ina2xx.h +++ /dev/null @@ -1,123 +0,0 @@ -/* Copyright 2014 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. - * - * TI INA219/231 Current/Power monitor driver. - */ - -#ifndef __CROS_EC_INA2XX_H -#define __CROS_EC_INA2XX_H - -#define INA2XX_REG_CONFIG 0x00 -#define INA2XX_REG_SHUNT_VOLT 0x01 -#define INA2XX_REG_BUS_VOLT 0x02 -#define INA2XX_REG_POWER 0x03 -#define INA2XX_REG_CURRENT 0x04 -#define INA2XX_REG_CALIB 0x05 -#define INA2XX_REG_MASK 0x06 -#define INA2XX_REG_ALERT 0x07 - -#define INA2XX_CONFIG_MODE_MASK (7 << 0) -#define INA2XX_CONFIG_MODE_PWRDWN (0 << 0) -#define INA2XX_CONFIG_MODE_SHUNT BIT(0) -#define INA2XX_CONFIG_MODE_BUS BIT(1) -#define INA2XX_CONFIG_MODE_TRG (0 << 2) -#define INA2XX_CONFIG_MODE_CONT BIT(2) - -/* Conversion time for bus and shunt in micro-seconds */ -enum ina2xx_conv_time { - INA2XX_CONV_TIME_140 = 0x00, - INA2XX_CONV_TIME_204 = 0x01, - INA2XX_CONV_TIME_332 = 0x02, - INA2XX_CONV_TIME_588 = 0x03, - INA2XX_CONV_TIME_1100 = 0x04, - INA2XX_CONV_TIME_2116 = 0x05, - INA2XX_CONV_TIME_4156 = 0x06, - INA2XX_CONV_TIME_8244 = 0x07, -}; -#define INA2XX_CONV_TIME_MASK 0x7 -#define INA2XX_CONFIG_SHUNT_CONV_TIME(t) ((t) << 3) -#define INA2XX_CONFIG_BUS_CONV_TIME(t) ((t) << 6) - -#define INA2XX_CONFIG_AVG_1 (0 << 9) -#define INA2XX_CONFIG_AVG_4 BIT(9) -#define INA2XX_CONFIG_AVG_16 (2 << 9) -#define INA2XX_CONFIG_AVG_64 (3 << 9) -#define INA2XX_CONFIG_AVG_128 (4 << 9) -#define INA2XX_CONFIG_AVG_256 (5 << 9) -#define INA2XX_CONFIG_AVG_512 (6 << 9) -#define INA2XX_CONFIG_AVG_1024 (7 << 9) - -#define INA2XX_MASK_EN_LEN BIT(0) -#define INA2XX_MASK_EN_APOL BIT(1) -#define INA2XX_MASK_EN_OVF BIT(2) -#define INA2XX_MASK_EN_CVRF BIT(3) -#define INA2XX_MASK_EN_AFF BIT(4) -#define INA2XX_MASK_EN_CNVR BIT(10) -#define INA2XX_MASK_EN_POL BIT(11) -#define INA2XX_MASK_EN_BUL BIT(12) -#define INA2XX_MASK_EN_BOL BIT(13) -#define INA2XX_MASK_EN_SUL BIT(14) -#define INA2XX_MASK_EN_SOL BIT(15) - - -#if defined(CONFIG_INA231) && defined(CONFIG_INA219) -#error CONFIG_INA231 and CONFIG_INA219 must not be both defined. -#endif - -#ifdef CONFIG_INA231 - -/* Calibration value to get current LSB = 1mA */ -#define INA2XX_CALIB_1MA(rsense_mohm) (5120/(rsense_mohm)) -/* Bus voltage: mV per LSB */ -#define INA2XX_BUS_MV(reg) ((reg) * 125 / 100) -/* Shunt voltage: uV per LSB */ -#define INA2XX_SHUNT_UV(reg) ((reg) * 25 / 10) -/* Power LSB: mW per current LSB */ -#define INA2XX_POW_MW(reg) ((reg) * 25 * 1/*Current mA/LSB*/) - -#else /* CONFIG_INA219 */ - -/* Calibration value to get current LSB = 1mA */ -#define INA2XX_CALIB_1MA(rsense_mohm) (40960/(rsense_mohm)) -/* Bus voltage: mV per LSB */ -#define INA2XX_BUS_MV(reg) ((reg) / 2) -/* Shunt voltage: uV */ -#define INA2XX_SHUNT_UV(reg) ((reg) * 10) -/* Power LSB: mW per current LSB */ -#define INA2XX_POW_MW(reg) ((reg) * 20 * 1/*Current mA/LSB*/) - -#endif - - -/* Read INA2XX register. */ -uint16_t ina2xx_read(uint8_t idx, uint8_t reg); - -/* Write INA2XX register. */ -int ina2xx_write(uint8_t idx, uint8_t reg, uint16_t val); - -/* Set measurement parameters */ -int ina2xx_init(uint8_t idx, uint16_t config, uint16_t calib); - -/* Return bus voltage in milliVolts */ -int ina2xx_get_voltage(uint8_t idx); - -/* Return current in milliAmps */ -int ina2xx_get_current(uint8_t idx); - -/* Return power in milliWatts */ -int ina2xx_get_power(uint8_t idx); - -/* Return content of mask register */ -int ina2xx_get_mask(uint8_t idx); - -/* Set mask register to desired value */ -int ina2xx_set_mask(uint8_t idx, uint16_t mask); - -/* Return alert register value */ -int ina2xx_get_alert(uint8_t idx); - -/* Set alert register to desired value */ -int ina2xx_set_alert(uint8_t idx, uint16_t alert); - -#endif /* __CROS_EC_INA2XX_H */ diff --git a/driver/ina3221.c b/driver/ina3221.c deleted file mode 100644 index 5b89f9694e..0000000000 --- a/driver/ina3221.c +++ /dev/null @@ -1,162 +0,0 @@ -/* Copyright 2019 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. - * - * TI INA3221 Power monitor driver. - */ - -#include "console.h" -#include "hooks.h" -#include "i2c.h" -#include "system.h" -#include "timer.h" -#include "ina3221.h" -#include "util.h" - -/* Console output macros */ -#define CPRINTS(format, args...) cprints(CC_I2C, format, ## args) - -const static uint8_t ina3221_reg_map[INA3221_CHAN_COUNT][INA3221_MAX_REG] = { -{ 1, 2, 7, 8 }, /* Chan 1 */ -{ 3, 4, 9, 10 }, /* Chan 2 */ -{ 5, 6, 11, 12 } /* Chan 3 */ -}; - -static uint16_t ina3221_read(unsigned int unit, uint8_t reg) -{ - int res; - int val; - - res = i2c_read16(ina3221[unit].port, ina3221[unit].address, - reg, &val); - if (res) { - CPRINTS("INA3221 I2C read failed"); - return 0x0bad; - } - return (val >> 8) | ((val & 0xff) << 8); -} - -static uint16_t ina3221_chan_read(unsigned int unit, enum ina3221_channel chan, - enum ina3221_register reg) -{ - if (chan >= INA3221_CHAN_COUNT || reg >= INA3221_MAX_REG) { - CPRINTS("INA3221 Bad channel or register value"); - return 0x0bad; - } - return ina3221_read(unit, ina3221_reg_map[chan][reg]); -} - -static int ina3221_write(unsigned int unit, uint8_t reg, uint16_t val) -{ - int res; - uint16_t be_val = (val >> 8) | ((val & 0xff) << 8); - - res = i2c_write16(ina3221[unit].port, ina3221[unit].address, - reg, be_val); - if (res) - CPRINTS("INA3221 I2C write failed"); - return res; -} - -static void ina3221_init(void) -{ - unsigned int unit; - - for (unit = 0; unit < ina3221_count; unit++) { - uint16_t conf = INA3221_CONFIG_BASE; - int chan; - - for (chan = 0; chan < INA3221_CHAN_COUNT; chan++) { - /* Only initialise if channel is used */ - if (ina3221[unit].name[chan] != NULL) - conf |= 0x4000 >> chan; - } - ina3221_write(unit, INA3221_REG_CONFIG, conf); - } -} - -DECLARE_HOOK(HOOK_INIT, ina3221_init, HOOK_PRIO_INIT_EXTPOWER + 1); - -#ifdef CONFIG_CMD_INA -static void ina3221_dump(unsigned int unit) -{ - uint16_t cfg; - int16_t sv[INA3221_CHAN_COUNT]; - uint16_t bv[INA3221_CHAN_COUNT]; - uint16_t crit[INA3221_CHAN_COUNT]; - uint16_t warn[INA3221_CHAN_COUNT]; - uint16_t mask; - int chan; - - cfg = ina3221_read(unit, INA3221_REG_CONFIG); - for (chan = 0; chan < INA3221_CHAN_COUNT; chan++) { - if (ina3221[unit].name[chan] != NULL) { - sv[chan] = ina3221_chan_read(unit, chan, - INA3221_SHUNT_VOLT); - bv[chan] = ina3221_chan_read(unit, chan, - INA3221_BUS_VOLT); - crit[chan] = ina3221_chan_read(unit, chan, - INA3221_CRITICAL); - warn[chan] = ina3221_chan_read(unit, chan, - INA3221_WARNING); - } - } - mask = ina3221_read(unit, INA3221_REG_MASK); - - ccprintf("Unit %d, address: %04x\n", unit, ina3221[unit].address); - ccprintf("Configuration : %04x\n", cfg); - for (chan = 0; chan < INA3221_CHAN_COUNT; chan++) { - if (ina3221[unit].name[chan] != NULL) { - ccprintf("%d: %s:\n", chan, ina3221[unit].name[chan]); - ccprintf(" Shunt voltage: %04x => %d uV\n", - sv[chan], INA3221_SHUNT_UV((int)sv[chan])); - ccprintf(" Bus voltage : %04x => %d mV\n", - bv[chan], INA3221_BUS_MV((int)bv[chan])); - ccprintf(" Warning : %04x\n", warn[chan]); - ccprintf(" Critical : %04x\n", crit[chan]); - } - } - ccprintf("Mask/Enable : %04x\n", mask); -} - -/*****************************************************************************/ -/* Console commands */ - -static int command_ina(int argc, char **argv) -{ - char *e; - unsigned int unit; - uint16_t val; - - if (argc < 2) - return EC_ERROR_PARAM_COUNT; - - unit = strtoi(argv[1], &e, 10); - if (*e || unit >= ina3221_count) - return EC_ERROR_PARAM1; - - if (argc == 2) { /* dump all registers */ - ina3221_dump(unit); - return EC_SUCCESS; - } else if (argc == 4) { - val = strtoi(argv[3], &e, 16); - if (*e) - return EC_ERROR_PARAM3; - - if (!strcasecmp(argv[2], "config")) { - ina3221_write(unit, INA3221_REG_CONFIG, val); - } else if (!strcasecmp(argv[2], "mask")) { - ina3221_write(unit, INA3221_REG_MASK, val); - } else { - ccprintf("Invalid register: %s\n", argv[1]); - return EC_ERROR_INVAL; - } - return EC_SUCCESS; - } - - return EC_ERROR_INVAL; -} -DECLARE_CONSOLE_COMMAND(ina, command_ina, - "<index> [config|mask <val>]", - "INA3221 voltage sensing"); -#endif diff --git a/driver/ina3221.h b/driver/ina3221.h deleted file mode 100644 index 4d8c8211b4..0000000000 --- a/driver/ina3221.h +++ /dev/null @@ -1,55 +0,0 @@ -/* Copyright 2019 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. - * - * TI INA3221 Current/Power monitor driver. - */ - -#ifndef __CROS_EC_INA3221_H -#define __CROS_EC_INA3221_H - -#define INA3221_REG_CONFIG 0x00 -#define INA3221_REG_MASK 0x0F - -/* - * Common bits are: - * Reset - * average = 1 - * conversion time = 1.1 ms - * mode = shunt and bus, continuous. - */ -#define INA3221_CONFIG_BASE 0x8127 - -/* Bus voltage: lower 3 bits clear, LSB = 8 mV */ -#define INA3221_BUS_MV(reg) (reg) -/* Shunt voltage: lower 3 bits clear, LSB = 40 uV */ -#define INA3221_SHUNT_UV(reg) ((reg) * (40/8)) - -enum ina3221_channel { - INA3221_CHAN_1 = 0, - INA3221_CHAN_2 = 1, - INA3221_CHAN_3 = 2, - INA3221_CHAN_COUNT = 3 -}; - -/* Registers for each channel */ -enum ina3221_register { - INA3221_SHUNT_VOLT = 0, - INA3221_BUS_VOLT = 1, - INA3221_CRITICAL = 2, - INA3221_WARNING = 3, - INA3221_MAX_REG = 4 -}; - -/* Configuration table - defined in board file. */ -struct ina3221_t { - int port; /* I2C port index */ - uint8_t address; /* I2C address */ - const char *name[INA3221_CHAN_COUNT]; /* Channel names */ -}; - -/* External config in board file */ -extern const struct ina3221_t ina3221[]; -extern const unsigned int ina3221_count; - -#endif /* __CROS_EC_INA3221_H */ diff --git a/driver/ioexpander/ccgxxf.c b/driver/ioexpander/ccgxxf.c deleted file mode 100644 index ac079d7b2f..0000000000 --- a/driver/ioexpander/ccgxxf.c +++ /dev/null @@ -1,145 +0,0 @@ -/* Copyright 2021 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. - * - * Cypress CCGXXF I/O Port expander (built inside PD chip) driver source - */ - -#include "console.h" -#include "i2c.h" -#include "ioexpander.h" - -/* Add after all include files */ -#include "ccgxxf.h" - -#define CPRINTS(format, args...) cprints(CC_GPIO, format, ## args) - -static inline int ccgxxf_read8(int ioex, int reg, int *data) -{ - return i2c_read8(ioex_config[ioex].i2c_host_port, - ioex_config[ioex].i2c_addr_flags, reg, data); -} - -static inline int ccgxxf_update8(int ioex, int reg, uint8_t mask, - enum mask_update_action action) -{ - return i2c_update8(ioex_config[ioex].i2c_host_port, - ioex_config[ioex].i2c_addr_flags, reg, mask, action); -} - -static inline int ccgxxf_write16(int ioex, uint16_t reg, uint16_t data) -{ - return i2c_write16(ioex_config[ioex].i2c_host_port, - ioex_config[ioex].i2c_addr_flags, reg, data); -} - -static int ccgxxf_get_level(int ioex, int port, int mask, int *val) -{ - int rv; - - rv = ccgxxf_read8(ioex, CCGXXF_REG_GPIO_STATUS(port), val); - if (!rv) - *val = !!(*val & mask); - - return rv; -} - -static int ccgxxf_set_level(int ioex, int port, int mask, int val) -{ - return ccgxxf_update8(ioex, CCGXXF_REG_GPIO_CONTROL(port), mask, val); -} - -/* - * Following type of pins are supported - * - Output pins are supported with open-drain & pull-up - * - Input pins are supported with pull-up & pull-down - * - Analog pins - * - 1.8V level GPIOs are supported per port and outputs can only be - * open-drain pins - */ -static int ccgxxf_set_flags_by_mask(int ioex, int port, int mask, int flags) -{ - uint16_t pin_mode; - int rv; - - /* Push-pull output can't be configured for 1.8V level */ - if ((flags & GPIO_OUTPUT) && (flags & GPIO_SEL_1P8V) && - !(flags & GPIO_OPEN_DRAIN)) { - CPRINTS("Invalid flags: ioex=%d, port=%d, mask=%d, flags=0x%x", - ioex, port, mask, flags); - - return EC_ERROR_INVAL; - } - - if (flags & GPIO_OUTPUT) { - if (flags & GPIO_OPEN_DRAIN) { - if (flags & GPIO_PULL_UP) - pin_mode = CCGXXF_GPIO_MODE_RES_UP; - else - pin_mode = CCGXXF_GPIO_MODE_OD_LOW; - } else { - pin_mode = CCGXXF_GPIO_MODE_STRONG; - } - } else if (flags & GPIO_INPUT) { - if (flags & GPIO_PULL_UP) { - pin_mode = CCGXXF_GPIO_MODE_RES_UP; - flags |= GPIO_HIGH; - } else if (flags & GPIO_PULL_DOWN) { - pin_mode = CCGXXF_GPIO_MODE_RES_DWN; - flags |= GPIO_LOW; - } else { - pin_mode = CCGXXF_GPIO_MODE_HIZ_DIGITAL; - } - } else if (flags & GPIO_ANALOG) { - pin_mode = CCGXXF_GPIO_MODE_HIZ_ANALOG; - } else { - return EC_ERROR_INVAL; - } - - pin_mode = port | (pin_mode << CCGXXF_GPIO_PIN_MODE_SHIFT) | - (mask << CCGXXF_GPIO_PIN_MASK_SHIFT); - - /* Note: once set the 1.8V level affect whole GPIO port */ - if (flags & GPIO_SEL_1P8V) - pin_mode |= CCGXXF_GPIO_1P8V_SEL; - - /* - * Before setting the GPIO mode, initilaize the pins to default value - * to avoid spike on pins. - */ - if (flags & (GPIO_HIGH | GPIO_LOW)) { - rv = ccgxxf_set_level(ioex, port, mask, - flags & GPIO_HIGH ? 1 : 0); - if (rv) - return rv; - } - - return ccgxxf_write16(ioex, CCGXXF_REG_GPIO_MODE, pin_mode); -} - -static int ccgxxf_get_flags_by_mask(int ioex, int port, int mask, int *flags) -{ - /* TODO: Add it after implementing in the CCGXXF firmware. */ - return EC_SUCCESS; -} - -static int ccgxxf_enable_interrupt(int ioex, int port, int mask, int enable) -{ - /* CCGXXF doesn't have interrupt capability on I/O expnader pins */ - return EC_ERROR_UNIMPLEMENTED; -} - -int ccgxxf_init(int ioex) -{ - /* TCPC init of CCGXXF should handle initialization */ - return EC_SUCCESS; -} - -const struct ioexpander_drv ccgxxf_ioexpander_drv = { - .init = &ccgxxf_init, - .get_level = &ccgxxf_get_level, - .set_level = &ccgxxf_set_level, - .get_flags_by_mask = &ccgxxf_get_flags_by_mask, - .set_flags_by_mask = &ccgxxf_set_flags_by_mask, - .enable_interrupt = &ccgxxf_enable_interrupt, -}; diff --git a/driver/ioexpander/ioexpander_nct38xx.c b/driver/ioexpander/ioexpander_nct38xx.c deleted file mode 100644 index 8c87a33d24..0000000000 --- a/driver/ioexpander/ioexpander_nct38xx.c +++ /dev/null @@ -1,470 +0,0 @@ -/* - * Copyright 2019 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. - */ - -/* GPIO expander for Nuvoton NCT38XX. */ - -#include "console.h" -#include "gpio.h" -#include "i2c.h" -#include "ioexpander.h" -#include "nct38xx.h" -#include "tcpm/tcpci.h" - -#define CPRINTF(format, args...) cprintf(CC_GPIO, format, ## args) -#define CPRINTS(format, args...) cprints(CC_GPIO, format, ## args) - -/* - * Store the GPIO_ALERT_MASK_0/1 and chip ID registers locally. In this way, - * we don't have to read it via I2C transaction everytime. - */ -struct nct38xx_chip_data { - uint8_t int_mask[2]; - int chip_id; -}; - -static struct nct38xx_chip_data chip_data[CONFIG_IO_EXPANDER_PORT_COUNT] = { - [0 ... (CONFIG_IO_EXPANDER_PORT_COUNT - 1)] = { {0, 0}, -1 } -}; - -static int nct38xx_ioex_check_is_valid(int ioex, int port, int mask) -{ - if (chip_data[ioex].chip_id == NCT38XX_VARIANT_3808) { - if (port == 1) { - CPRINTF("Port 1 is not support in NCT3808\n"); - return EC_ERROR_INVAL; - } - if (mask & ~NCT38XXX_3808_VALID_GPIO_MASK) { - - CPRINTF("GPIO%02d is not support in NCT3808\n", - __fls(mask)); - return EC_ERROR_INVAL; - } - } - - return EC_SUCCESS; -} - -static int nct38xx_ioex_init(int ioex) -{ - int rv, val; - struct ioexpander_config_t *ioex_p = &ioex_config[ioex]; - - /* - * Check the NCT38xx part number in the register DEVICE_ID[4:2]: - * 000: NCT3807 - * 010: NCT3808 - */ - rv = i2c_read8(ioex_p->i2c_host_port, ioex_p->i2c_addr_flags, - TCPC_REG_BCD_DEV, &val); - - if (rv != EC_SUCCESS) { - CPRINTF("Failed to read NCT38XX DEV ID for IOexpander %d\n", - ioex); - return rv; - } - - chip_data[ioex].chip_id = ((uint8_t)val & NCT38XX_VARIANT_MASK) >> 2; - - /* - * NCT38XX uses the Vendor Define bit in the ALERT event to indicate - * that an IOEX IO's interrupt is triggered. - * Normally, The ALERT MASK for Vendor Define event should be set by - * the NCT38XX TCPCI driver's init function. - * However, it should be also set here if we want to test the interrupt - * function of IOEX when the NCT38XX TCPCI driver is not included. - */ - if (!IS_ENABLED(CONFIG_USB_PD_TCPM_NCT38XX)) { - rv = i2c_write16(ioex_p->i2c_host_port, - ioex_p->i2c_addr_flags, TCPC_REG_ALERT_MASK, - TCPC_REG_ALERT_VENDOR_DEF); - if (rv != EC_SUCCESS) - return rv; - } - return EC_SUCCESS; -} - -static int nct38xx_ioex_get_level(int ioex, int port, int mask, int *val) -{ - int rv, reg; - - rv = nct38xx_ioex_check_is_valid(ioex, port, mask); - if (rv != EC_SUCCESS) - return rv; - - reg = NCT38XX_REG_GPIO_DATA_IN(port); - rv = i2c_read8(ioex_config[ioex].i2c_host_port, - ioex_config[ioex].i2c_addr_flags, reg, val); - if (rv != EC_SUCCESS) - return rv; - - *val = !!(*val & mask); - - return EC_SUCCESS; -} - -static int nct38xx_ioex_set_level(int ioex, int port, int mask, int value) -{ - int rv, reg, val; - - rv = nct38xx_ioex_check_is_valid(ioex, port, mask); - if (rv != EC_SUCCESS) - return rv; - - reg = NCT38XX_REG_GPIO_DATA_OUT(port); - - rv = i2c_read8(ioex_config[ioex].i2c_host_port, - ioex_config[ioex].i2c_addr_flags, reg, &val); - if (rv != EC_SUCCESS) - return rv; - - if (value) - val |= mask; - else - val &= ~mask; - - return i2c_write8(ioex_config[ioex].i2c_host_port, - ioex_config[ioex].i2c_addr_flags, reg, val); -} - -static int nct38xx_ioex_get_flags(int ioex, int port, int mask, int *flags) -{ - int rv, reg, val, i2c_port, i2c_addr; - struct ioexpander_config_t *ioex_p = &ioex_config[ioex]; - - i2c_port = ioex_p->i2c_host_port; - i2c_addr = ioex_p->i2c_addr_flags; - - rv = nct38xx_ioex_check_is_valid(ioex, port, mask); - if (rv != EC_SUCCESS) - return rv; - - reg = NCT38XX_REG_GPIO_DIR(port); - rv = i2c_read8(i2c_port, i2c_addr, reg, &val); - if (rv != EC_SUCCESS) - return rv; - - if (val & mask) - *flags |= GPIO_OUTPUT; - else - *flags |= GPIO_INPUT; - - reg = NCT38XX_REG_GPIO_DATA_IN(port); - rv = i2c_read8(i2c_port, i2c_addr, reg, &val); - if (rv != EC_SUCCESS) - return rv; - - if (val & mask) - *flags |= GPIO_HIGH; - else - *flags |= GPIO_LOW; - - reg = NCT38XX_REG_GPIO_OD_SEL(port); - rv = i2c_read8(i2c_port, i2c_addr, reg, &val); - if (rv != EC_SUCCESS) - return rv; - - if (val & mask) - *flags |= GPIO_OPEN_DRAIN; - - return EC_SUCCESS; -} - -static int nct38xx_ioex_sel_int_type(int i2c_port, int i2c_addr, int port, - int mask, int flags) -{ - int rv; - int reg_rising, reg_falling; - int rising, falling; - - reg_rising = NCT38XX_REG_GPIO_ALERT_RISE(port); - rv = i2c_read8(i2c_port, i2c_addr, reg_rising, &rising); - if (rv != EC_SUCCESS) - return rv; - - reg_falling = NCT38XX_REG_GPIO_ALERT_FALL(port); - rv = i2c_read8(i2c_port, i2c_addr, reg_falling, &falling); - if (rv != EC_SUCCESS) - return rv; - - /* Handle interrupt for level trigger */ - if ((flags & GPIO_INT_F_HIGH) || (flags & GPIO_INT_F_LOW)) { - int reg_level, level; - - reg_level = NCT38XX_REG_GPIO_ALERT_LEVEL(port); - rv = i2c_read8(i2c_port, i2c_addr, reg_level, &level); - if (rv != EC_SUCCESS) - return rv; - /* - * For "level" triggered interrupt, the related bit in - * ALERT_RISE and ALERT_FALL registers must be 0 - */ - rising &= ~mask; - falling &= ~mask; - if (flags & GPIO_INT_F_HIGH) - level |= mask; - else - level &= ~mask; - - rv = i2c_write8(i2c_port, i2c_addr, reg_rising, rising); - if (rv != EC_SUCCESS) - return rv; - rv = i2c_write8(i2c_port, i2c_addr, reg_falling, falling); - if (rv != EC_SUCCESS) - return rv; - rv = i2c_write8(i2c_port, i2c_addr, reg_level, level); - if (rv != EC_SUCCESS) - return rv; - } else if ((flags & GPIO_INT_F_RISING) || - (flags & GPIO_INT_F_FALLING)) { - if (flags & GPIO_INT_F_RISING) - rising |= mask; - else - rising &= ~mask; - if (flags & GPIO_INT_F_FALLING) - falling |= mask; - else - falling &= ~mask; - rv = i2c_write8(i2c_port, i2c_addr, reg_rising, rising); - if (rv != EC_SUCCESS) - return rv; - rv = i2c_write8(i2c_port, i2c_addr, reg_falling, falling); - if (rv != EC_SUCCESS) - return rv; - } - return EC_SUCCESS; -} - -static int nct38xx_ioex_set_flags_by_mask(int ioex, int port, int mask, - int flags) -{ - int rv, reg, val, i2c_port, i2c_addr; - struct ioexpander_config_t *ioex_p = &ioex_config[ioex]; - - i2c_port = ioex_p->i2c_host_port; - i2c_addr = ioex_p->i2c_addr_flags; - - rv = nct38xx_ioex_check_is_valid(ioex, port, mask); - if (rv != EC_SUCCESS) - return rv; - - /* - * GPIO port 0 muxs with alternative function. Disable the alternative - * function before setting flags. - */ - if (port == 0) { - /* GPIO03 in NCT3807 is not muxed with other function. */ - if (!(chip_data[ioex].chip_id == - NCT38XX_VARIANT_3807 && mask & 0x08)) { - reg = NCT38XX_REG_MUX_CONTROL; - rv = i2c_read8(i2c_port, i2c_addr, reg, &val); - if (rv != EC_SUCCESS) - return rv; - - val = (val | mask); - rv = i2c_write8(i2c_port, i2c_addr, reg, val); - if (rv != EC_SUCCESS) - return rv; - } - } - - val = flags & ~NCT38XX_SUPPORT_GPIO_FLAGS; - if (val) { - CPRINTF("Flag 0x%08x is not supported\n", val); - return EC_ERROR_INVAL; - } - - /* Select open drain 0:push-pull 1:open-drain */ - reg = NCT38XX_REG_GPIO_OD_SEL(port); - rv = i2c_read8(i2c_port, i2c_addr, reg, &val); - if (rv != EC_SUCCESS) - return rv; - - if (flags & GPIO_OPEN_DRAIN) - val |= mask; - else - val &= ~mask; - rv = i2c_write8(i2c_port, i2c_addr, reg, val); - if (rv != EC_SUCCESS) - return rv; - - nct38xx_ioex_sel_int_type(i2c_port, i2c_addr, port, mask, flags); - - /* Configure the output level */ - reg = NCT38XX_REG_GPIO_DATA_OUT(port); - rv = i2c_read8(i2c_port, i2c_addr, reg, &val); - if (rv != EC_SUCCESS) - return rv; - - if (flags & GPIO_HIGH) - val |= mask; - else if (flags & GPIO_LOW) - val &= ~mask; - rv = i2c_write8(i2c_port, i2c_addr, reg, val); - if (rv != EC_SUCCESS) - return rv; - - reg = NCT38XX_REG_GPIO_DIR(port); - rv = i2c_read8(i2c_port, i2c_addr, reg, &val); - if (rv != EC_SUCCESS) - return rv; - - if (flags & GPIO_OUTPUT) - val |= mask; - else - val &= ~mask; - - return i2c_write8(i2c_port, i2c_addr, reg, val); -} - -/* - * The following functions are used for IO's interrupt support. - * - * please note that if the system needs to use an IO on NCT38XX to support - * the interrupt, the following two consideration should be taken into account. - * 1. Interrupt latency: - * Because it requires to access the registers of NCT38XX via I2C - * transaction to know the interrupt event, there is some added latency - * for the interrupt handling. If the interrupt requires short latency, - * we do not recommend to connect such a signal to the NCT38XX. - * - * 2. Shared ALERT pin: - * Because the ALERT pin is shared also with the TCPC ALERT, we do not - * recommend to connect any signal that may generate a high rate of - * interrupts so it will not interfere with the normal work of the - * TCPC. - */ -static int nct38xx_ioex_enable_interrupt(int ioex, int port, int mask, - int enable) -{ - int rv, reg, val; - struct ioexpander_config_t *ioex_p = &ioex_config[ioex]; - - rv = nct38xx_ioex_check_is_valid(ioex, port, mask); - if (rv != EC_SUCCESS) - return rv; - - /* Clear the pending bit */ - reg = NCT38XX_REG_GPIO_ALERT_STAT(port); - rv = i2c_read8(ioex_p->i2c_host_port, ioex_p->i2c_addr_flags, - reg, &val); - if (rv != EC_SUCCESS) - return rv; - - val |= mask; - rv = i2c_write8(ioex_p->i2c_host_port, ioex_p->i2c_addr_flags, - reg, val); - if (rv != EC_SUCCESS) - return rv; - - reg = NCT38XX_REG_GPIO_ALERT_MASK(port); - if (enable) { - /* Enable the alert mask */ - chip_data[ioex].int_mask[port] |= mask; - val = chip_data[ioex].int_mask[port]; - } else { - /* Disable the alert mask */ - chip_data[ioex].int_mask[port] &= ~mask; - val = chip_data[ioex].int_mask[port]; - } - - return i2c_write8(ioex_p->i2c_host_port, ioex_p->i2c_addr_flags, - reg, val); -} - -int nct38xx_ioex_event_handler(int ioex) -{ - int reg, int_status, int_mask; - int i, j, total_port; - const struct ioex_info *g; - struct ioexpander_config_t *ioex_p = &ioex_config[ioex]; - int rv = 0; - - int_mask = chip_data[ioex].int_mask[0] | ( - chip_data[ioex].int_mask[1] << 8); - reg = NCT38XX_REG_GPIO_ALERT_STAT(0); - /* - * Read ALERT_STAT_0 and ALERT_STAT_1 register in a single I2C - * transaction to increase efficiency - */ - rv = i2c_read16(ioex_p->i2c_host_port, ioex_p->i2c_addr_flags, - reg, &int_status); - if (rv != EC_SUCCESS) - return rv; - - int_status = int_status & int_mask; - /* - * Clear the changed status bits in ALERT_STAT_0 and ALERT_STAT_1 - * register in a single I2C transaction to increase efficiency - */ - rv = i2c_write16(ioex_p->i2c_host_port, ioex_p->i2c_addr_flags, - reg, int_status); - if (rv != EC_SUCCESS) - return rv; - - /* For NCT3808, only check one port */ - total_port = (chip_data[ioex].chip_id == NCT38XX_VARIANT_3808) ? - NCT38XX_NCT3808_MAX_IO_PORT : - NCT38XX_NCT3807_MAX_IO_PORT; - for (i = 0; i < total_port; i++) { - uint8_t pending; - - pending = int_status >> (i * 8); - - if (!pending) - continue; - - for (j = 0, g = ioex_list; j < ioex_ih_count; j++, g++) { - - if (ioex == g->ioex && i == g->port && - (pending & g->mask)) { - ioex_irq_handlers[j](j + IOEX_SIGNAL_START); - pending &= ~g->mask; - if (!pending) - break; - } - - } - } - - return EC_SUCCESS; -} - -/* - * Normally, the ALERT MASK for Vendor Define event should be checked by - * the NCT38XX TCPCI driver's tcpc_alert function. - * However, it should be checked here if we want to test the interrupt - * function of IOEX when the NCT38XX TCPCI driver is not included. - */ -void nct38xx_ioex_handle_alert(int ioex) -{ - int rv, status; - struct ioexpander_config_t *ioex_p = &ioex_config[ioex]; - - rv = i2c_read16(ioex_p->i2c_host_port, ioex_p->i2c_addr_flags, - TCPC_REG_ALERT, &status); - if (rv != EC_SUCCESS) - CPRINTF("fail to read ALERT register\n"); - - if (status & TCPC_REG_ALERT_VENDOR_DEF) { - rv = i2c_write16(ioex_p->i2c_host_port, - ioex_p->i2c_addr_flags, TCPC_REG_ALERT, - TCPC_REG_ALERT_VENDOR_DEF); - if (rv != EC_SUCCESS) { - CPRINTF("Fail to clear Vendor Define mask\n"); - return; - } - nct38xx_ioex_event_handler(ioex); - } -} - -const struct ioexpander_drv nct38xx_ioexpander_drv = { - .init = &nct38xx_ioex_init, - .get_level = &nct38xx_ioex_get_level, - .set_level = &nct38xx_ioex_set_level, - .get_flags_by_mask = &nct38xx_ioex_get_flags, - .set_flags_by_mask = &nct38xx_ioex_set_flags_by_mask, - .enable_interrupt = &nct38xx_ioex_enable_interrupt, -}; diff --git a/driver/ioexpander/it8300.h b/driver/ioexpander/it8300.h deleted file mode 100644 index 2b47e7f3e1..0000000000 --- a/driver/ioexpander/it8300.h +++ /dev/null @@ -1,106 +0,0 @@ -/* Copyright 2018 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. - * - * ITE IT8300 I/O Port expander driver header - */ - -#ifndef __CROS_EC_IOEXPANDER_IT8300_H -#define __CROS_EC_IOEXPANDER_IT8300_H - -#include "i2c.h" - -/* Gather Interrupt Status Register */ -#define IT8300_GISR 0x0 - -/* Interrupt Status Registers */ -#define IT8300_ISR_A 0x6 -#define IT8300_ISR_B 0x7 -#define IT8300_ISR_C 0x28 -#define IT8300_ISR_D 0x2E -#define IT8300_ISR_E 0x2F - -/* Port Data Register Groups */ -#define IT8300_PDGR_A 0x1 -#define IT8300_PDGR_B 0x2 -#define IT8300_PDGR_C 0x3 -#define IT8300_PDGR_D 0x4 -#define IT8300_PDGR_E 0x5 - -/* GPIO Port Control n Registers */ -#define IT8300_GPCR_A0 0x10 -#define IT8300_GPCR_A1 0x11 -#define IT8300_GPCR_A2 0x12 -#define IT8300_GPCR_A3 0x13 -#define IT8300_GPCR_A4 0x14 -#define IT8300_GPCR_A5 0x15 -#define IT8300_GPCR_A6 0x16 -#define IT8300_GPCR_A7 0x17 - -#define IT8300_GPCR_B0 0x18 -#define IT8300_GPCR_B1 0x19 -#define IT8300_GPCR_B2 0x1A -#define IT8300_GPCR_B3 0x1B -#define IT8300_GPCR_B4 0x1C -#define IT8300_GPCR_B5 0x1D -#define IT8300_GPCR_B6 0x1E - -#define IT8300_GPCR_C0 0x20 -#define IT8300_GPCR_C1 0x21 -#define IT8300_GPCR_C2 0x22 -#define IT8300_GPCR_C3 0x23 -#define IT8300_GPCR_C4 0x24 -#define IT8300_GPCR_C5 0x25 -#define IT8300_GPCR_C6 0x26 - -#define IT8300_GPCR_D0 0x08 -#define IT8300_GPCR_D1 0x09 -#define IT8300_GPCR_D2 0x0A -#define IT8300_GPCR_D3 0x0B -#define IT8300_GPCR_D4 0x0C -#define IT8300_GPCR_D5 0x0D - -#define IT8300_GPCR_E0 0x32 - -#define IT8300_GPCR_E2 0x34 -#define IT8300_GPCR_E3 0x35 -#define IT8300_GPCR_E4 0x36 -#define IT8300_GPCR_E5 0x37 -#define IT8300_GPCR_E6 0x38 - -#define IT8300_GPCR_GPI_MODE BIT(7) -#define IT8300_GPCR_GP0_MODE BIT(6) -#define IT8300_GPCR_PULL_UP_EN BIT(2) -#define IT8300_GPCR_PULL_DN_EN BIT(1) - -/* EXGPIO Clear Alert */ -#define IT8300_ECA 0x30 - -/* EXGPIO Alert Enable */ -#define IT8300_EAE 0x31 - -/* Port Data Mirror Registers */ -#define IT8300_PDMRA_A 0x29 -#define IT8300_PDMRA_B 0x2A -#define IT8300_PDMRA_C 0x2B -#define IT8300_PDMRA_D 0x2C -#define IT8300_PDMRA_E 0x2D - -/* Output Open-Drain Enable Registers */ -#define IT8300_OODER_A 0x39 -#define IT8300_OODER_B 0x3A -#define IT8300_OODER_C 0x3B -#define IT8300_OODER_D 0x3C -#define IT8300_OODER_E 0x3D - -/* IT83200 Port GPIOs */ -#define IT8300_GPX_0 BIT(0) -#define IT8300_GPX_1 BIT(1) -#define IT8300_GPX_2 BIT(2) -#define IT8300_GPX_3 BIT(3) -#define IT8300_GPX_4 BIT(4) -#define IT8300_GPX_5 BIT(5) -#define IT8300_GPX_6 BIT(6) -#define IT8300_GPX_7 BIT(7) - -#endif /* __CROS_EC_IOEXPANDER_IT8300_H */ diff --git a/driver/ioexpander/it8801.c b/driver/ioexpander/it8801.c deleted file mode 100644 index 96070074fb..0000000000 --- a/driver/ioexpander/it8801.c +++ /dev/null @@ -1,683 +0,0 @@ -/* Copyright 2019 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 "common.h" -#include "console.h" -#include "gpio.h" -#include "hooks.h" -#include "i2c.h" -#include "ioexpander.h" -#include "it8801.h" -#include "keyboard_raw.h" -#include "keyboard_scan.h" -#include "registers.h" -#include "task.h" -#include "util.h" -#include "keyboard_backlight.h" - -#define CPRINTS(format, args...) cprints(CC_KEYSCAN, format, ## args) - -static int it8801_ioex_set_level(int ioex, int port, int mask, int value); -static void it8801_ioex_event_handler(void); -DECLARE_DEFERRED(it8801_ioex_event_handler); - -static int it8801_read(int reg, int *data) -{ - return i2c_read8(IT8801_KEYBOARD_PWM_I2C_PORT, - IT8801_KEYBOARD_PWM_I2C_ADDR_FLAGS, reg, data); -} - -__maybe_unused static int it8801_write(int reg, int data) -{ - return i2c_write8(IT8801_KEYBOARD_PWM_I2C_PORT, - IT8801_KEYBOARD_PWM_I2C_ADDR_FLAGS, reg, data); -} - -struct it8801_vendor_id_t { - uint8_t chip_id; - uint8_t reg; -}; - -static const struct it8801_vendor_id_t it8801_vendor_id_verify[] = { - { 0x12, IT8801_REG_HBVIDR}, - { 0x83, IT8801_REG_LBVIDR}, -}; - -static int it8801_check_vendor_id(void) -{ - int i, ret, val; - - /* Verify vendor ID registers(16-bits). */ - for (i = 0; i < ARRAY_SIZE(it8801_vendor_id_verify); i++) { - ret = it8801_read(it8801_vendor_id_verify[i].reg, &val); - - if (ret != EC_SUCCESS) - return ret; - - if (val != it8801_vendor_id_verify[i].chip_id) - return EC_ERROR_UNKNOWN; - } - - return EC_SUCCESS; -} - -/* - * Keyboard and GPIO interrupts are muxed inside the IT8801 chip. - * Interrupt enable register controls the individual pins from - * triggering this global interrupt hence it is okay that this - * pin is enabled all the time. - */ -static void it8801_muxed_kbd_gpio_intr_enable(void) -{ - static bool intr_enabled; - - /* - * Allow enabling this pin either by Keyboard enable code or - * IOEX init code whichever gets called first. - */ - if (!intr_enabled) { - gpio_clear_pending_interrupt(GPIO_IT8801_SMB_INT); - gpio_enable_interrupt(GPIO_IT8801_SMB_INT); - intr_enabled = true; - } -} - -#ifdef CONFIG_KEYBOARD_NOT_RAW -void keyboard_raw_init(void) -{ - int ret; - - /* Verify Vendor ID registers. */ - ret = it8801_check_vendor_id(); - if (ret) { - CPRINTS("Failed to read IT8801 vendor id %x", ret); - return; - } - - /* KSO alternate function switching(KSO[21:20, 18]). */ - it8801_write(IT8801_REG_GPIO01_KSO18, IT8801_REG_MASK_GPIOAFS_FUNC2); - it8801_write(IT8801_REG_GPIO22_KSO21, IT8801_REG_MASK_GPIOAFS_FUNC2); - it8801_write(IT8801_REG_GPIO23_KSO20, IT8801_REG_MASK_GPIOAFS_FUNC2); - - /* Start with KEYBOARD_COLUMN_ALL, KSO[22:11, 6:0] output low. */ - it8801_write(IT8801_REG_KSOMCR, IT8801_REG_MASK_AKSOSC); - - if (IS_ENABLED(CONFIG_KEYBOARD_COL2_INVERTED)) { - /* - * Since most of the KSO pins can't drive up, we'll must use - * a pin capable of being a GPIO instead and use the GPIO - * feature to do the required inverted push pull. - */ - it8801_write(IT8801_REG_GPIO23_KSO20, IT8801_REG_MASK_GPIODIR); - - /* Start with KEYBOARD_COLUMN_ALL, output high(so selected). */ - it8801_ioex_set_level(0, 2, IT8801_REG_GPIO23SOV, 1); - } - - /* Keyboard scan in interrupt enable register */ - it8801_write(IT8801_REG_KSIIER, 0xff); - /* Gather KSI interrupt enable */ - it8801_write(IT8801_REG_GIECR, IT8801_REG_MASK_GKSIIE); - /* Alert response enable */ - it8801_write(IT8801_REG_SMBCR, IT8801_REG_MASK_ARE); - - keyboard_raw_enable_interrupt(0); -} - -void keyboard_raw_task_start(void) -{ - keyboard_raw_enable_interrupt(1); -} - -__overridable const uint8_t it8801_kso_mapping[] = { - 0, 1, 20, 3, 4, 5, 6, 17, 18, 16, 15, 11, 12, -#ifdef CONFIG_KEYBOARD_KEYPAD - 13, 14 -#endif -}; -BUILD_ASSERT(ARRAY_SIZE(it8801_kso_mapping) == KEYBOARD_COLS_MAX); - -test_mockable void keyboard_raw_drive_column(int col) -{ - int kso_val; - - /* Tri-state all outputs */ - if (col == KEYBOARD_COLUMN_NONE) { - /* KSO[22:11, 6:0] output high */ - kso_val = IT8801_REG_MASK_KSOSDIC | IT8801_REG_MASK_AKSOSC; - - if (IS_ENABLED(CONFIG_KEYBOARD_COL2_INVERTED)) { - /* Output low(so not selected). */ - it8801_ioex_set_level(0, 2, IT8801_REG_GPIO23SOV, 0); - } - } - /* Assert all outputs */ - else if (col == KEYBOARD_COLUMN_ALL) { - /* KSO[22:11, 6:0] output low */ - kso_val = IT8801_REG_MASK_AKSOSC; - - if (IS_ENABLED(CONFIG_KEYBOARD_COL2_INVERTED)) { - /* Output high(so selected). */ - it8801_ioex_set_level(0, 2, IT8801_REG_GPIO23SOV, 1); - } - } else { - /* To check if column is valid or not. */ - if (col >= KEYBOARD_COLS_MAX) - return; - /* - * Selected KSO[20, 18:11, 6:3, 1:0] output low, - * all others KSO output high. - */ - kso_val = it8801_kso_mapping[col]; - - if (IS_ENABLED(CONFIG_KEYBOARD_COL2_INVERTED)) { - /* GPIO23 is inverted. */ - if (col == IT8801_REG_MASK_SELKSO2) { - /* Output high(so selected). */ - it8801_ioex_set_level(0, 2, - IT8801_REG_GPIO23SOV, 1); - } else { - /* Output low(so not selected). */ - it8801_ioex_set_level(0, 2, - IT8801_REG_GPIO23SOV, 0); - } - } - } - - it8801_write(IT8801_REG_KSOMCR, kso_val); -} - -test_mockable int keyboard_raw_read_rows(void) -{ - int data = 0; - int ksieer = 0; - - it8801_read(IT8801_REG_KSIDR, &data); - - /* This register needs to write clear after reading data */ - it8801_read(IT8801_REG_KSIEER, &ksieer); - it8801_write(IT8801_REG_KSIEER, ksieer); - - /* Bits are active-low, so invert returned levels */ - return (~data) & 0xff; -} - -void keyboard_raw_enable_interrupt(int enable) -{ - if (enable) { - /* Clear pending iterrupts */ - it8801_write(IT8801_REG_KSIEER, 0xff); - - /* Enable muxed Keyboard & GPIO interrupt */ - it8801_muxed_kbd_gpio_intr_enable(); - } - - it8801_write(IT8801_REG_KSIIER, enable ? 0xff : 0x00); -} -#endif /* CONFIG_KEYBOARD_NOT_RAW */ - -void io_expander_it8801_interrupt(enum gpio_signal signal) -{ - hook_call_deferred(&it8801_ioex_event_handler_data, 0); -} - -static int it8801_ioex_read(int ioex, int reg, int *data) -{ - struct ioexpander_config_t *ioex_p = &ioex_config[ioex]; - - return i2c_read8(ioex_p->i2c_host_port, ioex_p->i2c_addr_flags, - reg, data); -} - -static int it8801_ioex_write(int ioex, int reg, int data) -{ - struct ioexpander_config_t *ioex_p = &ioex_config[ioex]; - - return i2c_write8(ioex_p->i2c_host_port, ioex_p->i2c_addr_flags, - reg, data); -} - -static int it8801_ioex_update(int ioex, int reg, int data, - enum mask_update_action action) -{ - struct ioexpander_config_t *ioex_p = &ioex_config[ioex]; - - return i2c_update8(ioex_p->i2c_host_port, ioex_p->i2c_addr_flags, - reg, data, action); -} - -static const int it8801_valid_gpio_group[] = { - IT8801_VALID_GPIO_G0_MASK, - IT8801_VALID_GPIO_G1_MASK, - IT8801_VALID_GPIO_G2_MASK, -}; - -/* Mutexes */ -static struct mutex ioex_mutex; - -static uint8_t it8801_gpio_sov[ARRAY_SIZE(it8801_valid_gpio_group)]; - -/* - * Initialize the general purpose I/O port(GPIO) - */ -static int it8801_ioex_init(int ioex) -{ - int ret, port, val = 0; - - /* Verify Vendor ID registers. */ - ret = it8801_check_vendor_id(); - if (ret) { - CPRINTS("Failed to read IT8801 vendor id %x", ret); - return ret; - } - - /* - * We will read the value of SOVR and write it to the - * cache(it8801_gpio_sov[port]) to avoid causing cache - * to reset when EC is reset. - */ - for (port = 0; port < ARRAY_SIZE(it8801_valid_gpio_group); port++) { - it8801_ioex_read(ioex, IT8801_REG_GPIO_SOVR(port), &val); - it8801_gpio_sov[port] = val; - } - - /* Enable muxed Keyboard & GPIO interrupt */ - it8801_muxed_kbd_gpio_intr_enable(); - - return EC_SUCCESS; -} - -static int ioex_check_is_not_valid(int port, int mask) -{ - if (port >= ARRAY_SIZE(it8801_valid_gpio_group)) { - CPRINTS("Port%d is not support in IT8801", port); - return EC_ERROR_INVAL; - } - - if (mask & ~it8801_valid_gpio_group[port]) { - CPRINTS("GPIO%d-%d is not support in IT8801", port, - __fls(mask & ~it8801_valid_gpio_group[port])); - return EC_ERROR_INVAL; - } - - return EC_SUCCESS; -} - -static int it8801_ioex_get_level(int ioex, int port, int mask, int *val) -{ - int rv; - - if (ioex_check_is_not_valid(port, mask)) - return EC_ERROR_INVAL; - - rv = it8801_ioex_read(ioex, IT8801_REG_GPIO_IPSR(port), val); - - *val = !!(*val & mask); - - return rv; -} - -static int it8801_ioex_set_level(int ioex, int port, int mask, int value) -{ - int rv = EC_SUCCESS; - - if (ioex_check_is_not_valid(port, mask)) - return EC_ERROR_INVAL; - - mutex_lock(&ioex_mutex); - /* - * The bit of output value in SOV is different than - * the one we were about to set it to. - */ - if (!!(it8801_gpio_sov[port] & mask) ^ value) { - if (value) - it8801_gpio_sov[port] |= mask; - else - it8801_gpio_sov[port] &= ~mask; - - rv = it8801_ioex_write(ioex, IT8801_REG_GPIO_SOVR(port), - it8801_gpio_sov[port]); - } - mutex_unlock(&ioex_mutex); - - return rv; -} - -static int it8801_ioex_get_flags_by_mask(int ioex, int port, - int mask, int *flags) -{ - int rv, val; - - if (ioex_check_is_not_valid(port, mask)) - return EC_ERROR_INVAL; - - rv = it8801_ioex_read(ioex, IT8801_REG_GPIO_CR(port, mask), &val); - if (rv) - return rv; - - *flags = 0; - - /* Get GPIO direction */ - *flags |= (val & IT8801_GPIODIR) ? GPIO_OUTPUT : GPIO_INPUT; - - /* Get GPIO type, 0:push-pull 1:open-drain */ - if (val & IT8801_GPIOIOT) - *flags |= GPIO_OPEN_DRAIN; - - rv = it8801_ioex_read(ioex, IT8801_REG_GPIO_IPSR(port), &val); - if (rv) - return rv; - - /* Get GPIO output level */ - *flags |= (val & mask) ? GPIO_HIGH : GPIO_LOW; - - return EC_SUCCESS; -} - -static int it8801_ioex_set_flags_by_mask(int ioex, int port, - int mask, int flags) -{ - int rv, val; - - if (ioex_check_is_not_valid(port, mask)) - return EC_ERROR_INVAL; - - if (flags & ~IT8801_SUPPORT_GPIO_FLAGS) { - CPRINTS("Flag 0x%08x is not supported at port %d, mask %d", - flags, port, mask); - return EC_ERROR_INVAL; - } - - /* GPIO alternate function switching(GPIO[00, 12:15, 20:23]). */ - rv = it8801_ioex_write(ioex, IT8801_REG_GPIO_CR(port, mask), - IT8801_REG_MASK_GPIOAFS_FUNC1); - if (rv) - return rv; - - mutex_lock(&ioex_mutex); - rv = it8801_ioex_read(ioex, IT8801_REG_GPIO_CR(port, mask), &val); - if (rv) - goto unlock_mutex; - - /* Select open drain 0:push-pull 1:open-drain */ - if (flags & GPIO_OPEN_DRAIN) - val |= IT8801_GPIOIOT; - else - val &= ~IT8801_GPIOIOT; - - /* Select GPIO direction */ - if (flags & GPIO_OUTPUT) { - /* Configure the output level */ - if (flags & GPIO_HIGH) - it8801_gpio_sov[port] |= mask; - else - it8801_gpio_sov[port] &= ~mask; - - rv = it8801_ioex_write(ioex, IT8801_REG_GPIO_SOVR(port), - it8801_gpio_sov[port]); - if (rv) - goto unlock_mutex; - - val |= IT8801_GPIODIR; - } else { - val &= ~IT8801_GPIODIR; - } - - /* Set Interrupt Type */ - if (flags & GPIO_INT_RISING) - val |= IT8801_GPIOIOT_INT_RISING; - if (flags & GPIO_INT_FALLING) - val |= IT8801_GPIOIOT_INT_FALLING; - - rv = it8801_ioex_write(ioex, IT8801_REG_GPIO_CR(port, mask), val); - -unlock_mutex: - mutex_unlock(&ioex_mutex); - - return rv; -} - -/* Enable the individual GPIO interrupt pins based on the board requirement. */ -static int it8801_ioex_enable_interrupt(int ioex, int port, int mask, - int enable) -{ - int rv; - - if (ioex_check_is_not_valid(port, mask)) - return EC_ERROR_INVAL; - - /* Clear pending interrupt */ - rv = it8801_ioex_update(ioex, IT8801_REG_GPIO_ISR(port), - mask, MASK_SET); - if (rv) - return rv; - - return it8801_ioex_update(ioex, IT8801_REG_GPIO_IER(port), - mask, enable ? MASK_SET : MASK_CLR); -} - -static void it8801_ioex_irq(int ioex, int port) -{ - int rv, data, i; - const struct ioex_info *g; - - rv = it8801_ioex_read(ioex, IT8801_REG_GPIO_ISR(port), &data); - if (rv || !data) - return; - - /* Trigger the intended interrupt from the IOEX IRQ pins */ - for (i = 0, g = ioex_list; i < ioex_ih_count; i++, g++) { - if (ioex == g->ioex && port == g->port && data & g->mask) { - ioex_irq_handlers[i](i + IOEX_SIGNAL_START); - data &= ~g->mask; - - /* Clear pending interrupt */ - it8801_ioex_update(ioex, IT8801_REG_GPIO_ISR(port), - g->mask, MASK_SET); - - if (!data) - break; - } - } -} - -static void it8801_ioex_event_handler(void) -{ - int data, i; - - /* Gather KSI interrupt status register */ - if (it8801_read(IT8801_REG_GISR, &data)) - return; - - /* Wake the keyboard scan task if KSI interrupts are triggered */ - if (IS_ENABLED(CONFIG_KEYBOARD_NOT_RAW) && - data & IT8801_REG_MASK_GISR_GKSIIS) - task_wake(TASK_ID_KEYSCAN); - - /* - * Trigger the GPIO callback functions if the GPIO interrupts are - * triggered. - */ - if (data & (IT8801_REG_MASK_GISR_GGPIOGXIS)) { - for (i = 0; i < CONFIG_IO_EXPANDER_PORT_COUNT; i++) { - if (ioex_config[i].drv == &it8801_ioexpander_drv) { - /* Interrupt from GPIO port 0 is triggered */ - if (data & IT8801_REG_MASK_GISR_GGPIOG0IS) - it8801_ioex_irq(i, 0); - /* Interrupt from GPIO port 1 is triggered */ - if (data & IT8801_REG_MASK_GISR_GGPIOG1IS) - it8801_ioex_irq(i, 1); - /* Interrupt from GPIO port 2 is triggered */ - if (data & IT8801_REG_MASK_GISR_GGPIOG2IS) - it8801_ioex_irq(i, 2); - } - } - } -} - -const struct ioexpander_drv it8801_ioexpander_drv = { - .init = &it8801_ioex_init, - .get_level = &it8801_ioex_get_level, - .set_level = &it8801_ioex_set_level, - .get_flags_by_mask = &it8801_ioex_get_flags_by_mask, - .set_flags_by_mask = &it8801_ioex_set_flags_by_mask, - .enable_interrupt = &it8801_ioex_enable_interrupt, -}; - -static void dump_register(int reg) -{ - int rv; - int data; - - ccprintf("[%Xh] = ", reg); - - rv = it8801_read(reg, &data); - - if (!rv) - ccprintf("0x%02x\n", data); - else - ccprintf("ERR (%d)\n", rv); -} - -static int it8801_dump(int argc, char **argv) -{ - dump_register(IT8801_REG_KSIIER); - dump_register(IT8801_REG_KSIEER); - dump_register(IT8801_REG_KSIDR); - dump_register(IT8801_REG_KSOMCR); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(it8801_dump, it8801_dump, "NULL", - "Dumps IT8801 registers"); - -#ifdef CONFIG_IO_EXPANDER_IT8801_PWM - -struct it8801_pwm_gpio_map { - int port; - int mask; - int pushpull_en; -}; - -const static struct it8801_pwm_gpio_map it8801_pwm_gpio_map[] = { - [1] = {.port = 1, .mask = BIT(2), .pushpull_en = BIT(0)}, - [2] = {.port = 1, .mask = BIT(3), .pushpull_en = BIT(1)}, - [3] = {.port = 1, .mask = BIT(4), .pushpull_en = BIT(2)}, - [4] = {.port = 1, .mask = BIT(5), .pushpull_en = BIT(3)}, - [7] = {.port = 2, .mask = BIT(0), .pushpull_en = BIT(4)}, - [8] = {.port = 2, .mask = BIT(3), .pushpull_en = BIT(5)}, - [9] = {.port = 2, .mask = BIT(2), .pushpull_en = BIT(6)}, -}; - -void it8801_pwm_enable(enum pwm_channel ch, int enabled) -{ - int port, mask, val, index; - - index = it8801_pwm_channels[ch].index; - if (index < 0 || index >= ARRAY_SIZE(it8801_pwm_gpio_map)) - return; - port = it8801_pwm_gpio_map[index].port; - mask = it8801_pwm_gpio_map[index].mask; - if (port == 0 && mask == 0) - return; - - /* - * PWM1~4,7: alt func 1 - * PWM8,9: alt func 2 - */ - if (it8801_pwm_channels[ch].index <= 7) - it8801_write(IT8801_REG_GPIO_CR(port, mask), - 0x1 << IT8801_GPIOAFS_SHIFT); - else - it8801_write(IT8801_REG_GPIO_CR(port, mask), - 0x2 << IT8801_GPIOAFS_SHIFT); - - it8801_read(IT8801_REG_PWMMCR(it8801_pwm_channels[ch].index), &val); - val &= (~IT8801_PWMMCR_MCR_MASK); - if (enabled) - val |= IT8801_PWMMCR_MCR_BLINKING; - it8801_write(IT8801_REG_PWMMCR(it8801_pwm_channels[ch].index), val); - - /* - * 1: enable push pull function - */ - it8801_read(IT8801_REG_PWMODDSR, &val); - val &= ~it8801_pwm_gpio_map[index].pushpull_en; - if (enabled) - val |= it8801_pwm_gpio_map[index].pushpull_en; - it8801_write(IT8801_REG_PWMODDSR, val); - -} - -int it8801_pwm_get_enabled(enum pwm_channel ch) -{ - int val; - - if (it8801_read(IT8801_REG_PWMMCR(it8801_pwm_channels[ch].index), &val)) - return 0; - return (val & IT8801_PWMMCR_MCR_MASK) == IT8801_PWMMCR_MCR_BLINKING; -} - -void it8801_pwm_set_raw_duty(enum pwm_channel ch, uint16_t duty) -{ - duty = MIN(duty, 255); - duty = MAX(duty, 0); - it8801_write(IT8801_REG_PWMDCR(it8801_pwm_channels[ch].index), duty); -} - -uint16_t it8801_pwm_get_raw_duty(enum pwm_channel ch) -{ - int val; - - if (it8801_read(IT8801_REG_PWMDCR(it8801_pwm_channels[ch].index), &val)) - return 0; - return val; -} - -void it8801_pwm_set_duty(enum pwm_channel ch, int percent) -{ - return it8801_pwm_set_raw_duty(ch, percent * 255 / 100); -} - -int it8801_pwm_get_duty(enum pwm_channel ch) -{ - return it8801_pwm_get_raw_duty(ch) * 100 / 255; -} - -#ifdef CONFIG_KEYBOARD_BACKLIGHT -const enum pwm_channel it8801_kblight_pwm_ch = IT8801_PWM_CH_KBLIGHT; - -static int it8801_kblight_enable(int enable) -{ - it8801_pwm_enable(it8801_kblight_pwm_ch, enable); - return EC_SUCCESS; -} - -static int it8801_kblight_set_brightness(int percent) -{ - it8801_pwm_set_duty(it8801_kblight_pwm_ch, percent); - return EC_SUCCESS; -} - -static int it8801_kblight_get_brightness(void) -{ - return it8801_pwm_get_duty(it8801_kblight_pwm_ch); -} - -static int it8801_kblight_init(void) -{ - it8801_pwm_set_duty(it8801_kblight_pwm_ch, 0); - it8801_pwm_enable(it8801_kblight_pwm_ch, 1); - return EC_SUCCESS; -} - -const struct kblight_drv kblight_it8801 = { - .init = it8801_kblight_init, - .set = it8801_kblight_set_brightness, - .get = it8801_kblight_get_brightness, - .enable = it8801_kblight_enable, -}; -#endif -#endif /* CONFIG_IO_EXPANDER_IT8801_PWM */ diff --git a/driver/ioexpander/it8801.h b/driver/ioexpander/it8801.h deleted file mode 100644 index 05a17acf78..0000000000 --- a/driver/ioexpander/it8801.h +++ /dev/null @@ -1,126 +0,0 @@ -/* Copyright 2019 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. - * - * IT8801 is an I/O expander with the keyboard matrix controller. - * - */ - -#ifndef __CROS_EC_IO_EXPANDER_IT8801_H -#define __CROS_EC_IO_EXPANDER_IT8801_H - -/* I2C address flags (7-bit without R/W) */ -#define IT8801_I2C_ADDR1 0x38 -#define IT8801_I2C_ADDR2 0x39 - -/* Keyboard Matrix Scan control (KBS) */ -#define IT8801_REG_KSOMCR 0x40 -#define IT8801_REG_MASK_KSOSDIC BIT(7) -#define IT8801_REG_MASK_KSE BIT(6) -#define IT8801_REG_MASK_AKSOSC BIT(5) -#define IT8801_REG_KSIDR 0x41 -#define IT8801_REG_KSIEER 0x42 -#define IT8801_REG_KSIIER 0x43 -#define IT8801_REG_SMBCR 0xfa -#define IT8801_REG_MASK_ARE BIT(4) -#define IT8801_REG_GIECR 0xfb -#define IT8801_REG_MASK_GKSIIE BIT(3) -#define IT8801_REG_GPIO10 0x12 -#define IT8801_REG_GPIO00_KSO19 0x0a -#define IT8801_REG_GPIO01_KSO18 0x0b -#define IT8801_REG_GPIO22_KSO21 0x1c -#define IT8801_REG_GPIO23_KSO20 0x1d -#define IT8801_REG_MASK_GPIOAFS_PULLUP BIT(7) -#define IT8801_REG_MASK_GPIOAFS_FUNC2 BIT(6) -#define IT8801_REG_MASK_GPIODIR BIT(5) -#define IT8801_REG_MASK_GPIOPUE BIT(0) -#define IT8801_REG_GPIO23SOV BIT(3) -#define IT8801_REG_MASK_SELKSO2 0x02 -#define IT8801_REG_GISR 0xF9 -#define IT8801_REG_MASK_GISR_GKSIIS BIT(6) -#define IT8801_REG_MASK_GISR_GGPIOG2IS BIT(2) -#define IT8801_REG_MASK_GISR_GGPIOG1IS BIT(1) -#define IT8801_REG_MASK_GISR_GGPIOG0IS BIT(0) -#define IT8801_REG_MASK_GISR_GGPIOGXIS (IT8801_REG_MASK_GISR_GGPIOG2IS | \ - IT8801_REG_MASK_GISR_GGPIOG1IS | IT8801_REG_MASK_GISR_GGPIOG0IS) -#define IT8801_REG_LBVIDR 0xFE -#define IT8801_REG_HBVIDR 0xFF -#define IT8801_KSO_COUNT 18 - -/* General Purpose I/O Port (GPIO) */ -#define IT8801_SUPPORT_GPIO_FLAGS (GPIO_OPEN_DRAIN | GPIO_INPUT | \ - GPIO_OUTPUT | GPIO_LOW | GPIO_HIGH | GPIO_INT_ANY) - -#define IT8801_REG_MASK_GPIOAFS_FUNC1 (0x00 << 7) - -/* IT8801 only supports GPIO 0/1/2 */ -#define IT8801_VALID_GPIO_G0_MASK 0xD9 -#define IT8801_VALID_GPIO_G1_MASK 0x3F -#define IT8801_VALID_GPIO_G2_MASK 0x0F - -extern __override_proto const uint8_t it8801_kso_mapping[]; -extern const struct ioexpander_drv it8801_ioexpander_drv; - -/* GPIO Register map */ -/* Input pin status register */ -#define IT8801_REG_GPIO_IPSR(port) (0x00 + (port)) -/* Set output value register */ -#define IT8801_REG_GPIO_SOVR(port) (0x05 + (port)) -/* Control register */ -#define IT8801_REG_GPIO_CR(port, mask) \ - (0x0A + (port) * 8 + GPIO_MASK_TO_NUM(mask)) -/* Interrupt status register */ -#define IT8801_REG_GPIO_ISR(port) (0x32 + (port)) -/* Interrupt enable register */ -#define IT8801_REG_GPIO_IER(port) (0x37 + (port)) - -/* Control register values */ -#define IT8801_GPIOAFS_SHIFT 6 /* bit 6~7 */ - -#define IT8801_GPIODIR BIT(5) /* direction, output=1 */ -/* input pin */ -#define IT8801_GPIOIOT_INT_RISING BIT(3) -#define IT8801_GPIOIOT_INT_FALLING BIT(4) - -#define IT8801_GPIODIR BIT(5) -#define IT8801_GPIOIOT BIT(4) -#define IT8801_GPIOPOL BIT(2) /* polarity */ -#define IT8801_GPIOPDE BIT(1) /* pull-down enable */ -#define IT8801_GPIOPUE BIT(0) /* pull-up enable */ - -/* ISR for IT8801's SMB_INT# */ -void io_expander_it8801_interrupt(enum gpio_signal signal); - -#ifdef CONFIG_IO_EXPANDER_IT8801_PWM - -/* Mapping PWM_CH_LED_* to it8801 channel */ -struct it8801_pwm_t { - int index; -}; - -extern const struct it8801_pwm_t it8801_pwm_channels[]; -extern const struct kblight_drv kblight_it8801; - -/* standard pwm interface as defined in pwm.h */ -void it8801_pwm_enable(enum pwm_channel ch, int enabled); -int it8801_pwm_get_enabled(enum pwm_channel ch); -void it8801_pwm_set_raw_duty(enum pwm_channel ch, uint16_t duty); -uint16_t it8801_pwm_get_raw_duty(enum pwm_channel ch); -void it8801_pwm_set_duty(enum pwm_channel ch, int percent); -int it8801_pwm_get_duty(enum pwm_channel ch); - -#define IT8801_REG_PWMODDSR 0x5F -#define IT8801_REG_PWMMCR(n) (0x60 + ((n) - 1) * 8) -#define IT8801_REG_PWMDCR(n) (0x64 + ((n) - 1) * 8) -#define IT8801_REG_PWMPRSL(n) (0x66 + ((n) - 1) * 8) -#define IT8801_REG_PWMPRSM(n) (0x67 + ((n) - 1) * 8) - -#define IT8801_PWMMCR_MCR_MASK 0x3 -#define IT8801_PWMMCR_MCR_OFF 0 -#define IT8801_PWMMCR_MCR_BLINKING 1 -#define IT8801_PWMMCR_MCR_BREATHING 2 -#define IT8801_PWMMCR_MCR_ON 3 - -#endif /* CONFIG_IO_EXPANDER_IT8801_PWM */ - -#endif /* __CROS_EC_KBEXPANDER_IT8801_H */ diff --git a/driver/ioexpander/pca9534.c b/driver/ioexpander/pca9534.c deleted file mode 100644 index d56eb864cb..0000000000 --- a/driver/ioexpander/pca9534.c +++ /dev/null @@ -1,52 +0,0 @@ -/* Copyright 2014 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. - * - * NXP PCA9534 I/O expander - */ - -#include "i2c.h" -#include "pca9534.h" - -static int pca9534_pin_read(const int port, const uint16_t addr_flags, - int reg, int pin, int *val) -{ - int ret; - ret = i2c_read8(port, addr_flags, reg, val); - *val = (*val & BIT(pin)) ? 1 : 0; - return ret; -} - -static int pca9534_pin_write(const int port, const uint16_t addr_flags, - int reg, int pin, int val) -{ - int ret, v; - ret = i2c_read8(port, addr_flags, reg, &v); - if (ret != EC_SUCCESS) - return ret; - v &= ~BIT(pin); - if (val) - v |= 1 << pin; - return i2c_write8(port, addr_flags, reg, v); -} - -int pca9534_get_level(const int port, const uint16_t addr_flags, - int pin, int *level) -{ - return pca9534_pin_read(port, addr_flags, - PCA9534_REG_INPUT, pin, level); -} - -int pca9534_set_level(const int port, const uint16_t addr_flags, - int pin, int level) -{ - return pca9534_pin_write(port, addr_flags, - PCA9534_REG_OUTPUT, pin, level); -} - -int pca9534_config_pin(const int port, const uint16_t addr_flags, - int pin, int is_input) -{ - return pca9534_pin_write(port, addr_flags, - PCA9534_REG_CONFIG, pin, is_input); -} diff --git a/driver/ioexpander/pca9534.h b/driver/ioexpander/pca9534.h deleted file mode 100644 index 0fec577576..0000000000 --- a/driver/ioexpander/pca9534.h +++ /dev/null @@ -1,59 +0,0 @@ -/* Copyright 2014 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. - * - * NXP PCA9534 I/O expander - */ - -#ifndef __CROS_EC_IOEXPANDER_PCA9534_H -#define __CROS_EC_IOEXPANDER_PCA9534_H - -#define PCA9534_REG_INPUT 0x0 -#define PCA9534_REG_OUTPUT 0x1 -#define PCA9534_REG_CONFIG 0x3 - -#define PCA9534_OUTPUT 0 -#define PCA9534_INPUT 1 - -/* - * Get input level. Note that this reflects the actual level on the - * pin, even if the pin is configured as output. - * - * @param port The I2C port of PCA9534. - * @param addr The address of PCA9534. - * @param pin The index of the pin to read. - * @param level The pointer to where the read level is stored. - * - * @return EC_SUCCESS, or EC_ERROR_* on error. - */ -int pca9534_get_level(const int port, const uint16_t addr_flags, - int pin, int *level); - -/* - * Set output level. This function has no effect if the pin is - * configured as input. - * - * @param port The I2C port of PCA9534. - * @param addr The address of PCA9534. - * @param pin The index of the pin to set. - * @param level The level to set. - * - * @return EC_SUCCESS, or EC_ERROR_* on error. - */ -int pca9534_set_level(const int port, const uint16_t addr_flags, - int pin, int level); - -/* - * Config a pin as input or output. - * - * @param port The I2C port of PCA9534. - * @param addr The address of PCA9534. - * @param pin The index of the pin to set. - * @param is_input PCA9534_INPUT or PCA9534_OUTPUT. - * - * @return EC_SUCCESS, or EC_ERROR_* on error. - */ -int pca9534_config_pin(const int port, const uint16_t addr_flags, - int pin, int is_input); - -#endif /* __CROS_EC_IOEXPANDER_PCA9534_H */ diff --git a/driver/ioexpander/pca9555.h b/driver/ioexpander/pca9555.h deleted file mode 100644 index 273f898821..0000000000 --- a/driver/ioexpander/pca9555.h +++ /dev/null @@ -1,45 +0,0 @@ -/* Copyright 2017 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. - * - * NXP PCA9555 I/O Port expander driver header - */ - -#ifndef __CROS_EC_IOEXPANDER_PCA9555_H -#define __CROS_EC_IOEXPANDER_PCA9555_H - -#include "i2c.h" - -#define PCA9555_CMD_INPUT_PORT_0 0 -#define PCA9555_CMD_INPUT_PORT_1 1 -#define PCA9555_CMD_OUTPUT_PORT_0 2 -#define PCA9555_CMD_OUTPUT_PORT_1 3 -#define PCA9555_CMD_POLARITY_INVERSION_PORT_0 4 -#define PCA9555_CMD_POLARITY_INVERSION_PORT_1 5 -#define PCA9555_CMD_CONFIGURATION_PORT_0 6 -#define PCA9555_CMD_CONFIGURATION_PORT_1 7 - -#define PCA9555_IO_0 BIT(0) -#define PCA9555_IO_1 BIT(1) -#define PCA9555_IO_2 BIT(2) -#define PCA9555_IO_3 BIT(3) -#define PCA9555_IO_4 BIT(4) -#define PCA9555_IO_5 BIT(5) -#define PCA9555_IO_6 BIT(6) -#define PCA9555_IO_7 BIT(7) - -static inline int pca9555_read(const int port, - const uint16_t i2c_addr_flags, - int reg, int *data_ptr) -{ - return i2c_read8(port, i2c_addr_flags, reg, data_ptr); -} - -static inline int pca9555_write(const int port, - const uint16_t i2c_addr_flags, - int reg, int data) -{ - return i2c_write8(port, i2c_addr_flags, reg, data); -} - -#endif /* __CROS_EC_IOEXPANDER_PCA9555_H */ diff --git a/driver/ioexpander/pca9675.c b/driver/ioexpander/pca9675.c deleted file mode 100644 index 3fe3bfa0c4..0000000000 --- a/driver/ioexpander/pca9675.c +++ /dev/null @@ -1,127 +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. - * - * NXP PCA9675PW I/O Port expander driver source - */ - -#include "i2c.h" -#include "ioexpander.h" -#include "pca9675.h" - -struct pca9675_ioexpander { - /* I/O port direction (1 = input, 0 = output) */ - uint16_t io_direction; - uint16_t cache_out_pins; -}; - -static struct pca9675_ioexpander pca9675_iox[CONFIG_IO_EXPANDER_PORT_COUNT]; - -static int pca9675_read16(int ioex, uint16_t *data) -{ - return i2c_xfer(ioex_config[ioex].i2c_host_port, - ioex_config[ioex].i2c_addr_flags, - NULL, 0, (uint8_t *)data, 2); -} - -static int pca9675_write16(int ioex, uint16_t data) -{ - /* - * PCA9675 is Quasi-bidirectional I/O architecture hence - * append the direction (1 = input, 0 = output) to prevent - * overwriting I/O pins inadvertently. - */ - data |= pca9675_iox[ioex].io_direction; - - return i2c_xfer(ioex_config[ioex].i2c_host_port, - ioex_config[ioex].i2c_addr_flags, - (uint8_t *)&data, 2, NULL, 0); -} - -static int pca9675_reset(int ioex) -{ - uint8_t reset = PCA9675_RESET_SEQ_DATA; - - return i2c_xfer(ioex_config[ioex].i2c_host_port, - 0, &reset, 1, NULL, 0); -} - -static int pca9675_get_flags_by_mask(int ioex, int port, int mask, int *flags) -{ - *flags = mask & pca9675_iox[ioex].io_direction ? - GPIO_INPUT : GPIO_OUTPUT; - - return EC_SUCCESS; -} - -static int pca9675_get_level(int ioex, int port, int mask, int *val) -{ - int rv = EC_SUCCESS; - uint16_t data_read; - - /* Read from IO-expander only if the pin is input */ - if (pca9675_iox[ioex].io_direction & mask) { - rv = pca9675_read16(ioex, &data_read); - if (!rv) - *val = !!(data_read & mask); - } else { - *val = !!(pca9675_iox[ioex].cache_out_pins & mask); - } - - return rv; -} - -static int pca9675_set_level(int ioex, int port, int mask, int val) -{ - /* Update the output pins */ - if (val) - pca9675_iox[ioex].cache_out_pins |= mask; - else - pca9675_iox[ioex].cache_out_pins &= ~mask; - - return pca9675_write16(ioex, pca9675_iox[ioex].cache_out_pins); -} - -static int pca9675_set_flags_by_mask(int ioex, int port, int mask, int flags) -{ - int rv = EC_SUCCESS; - - /* Initialize the I/O directions */ - if (flags & GPIO_INPUT) { - pca9675_iox[ioex].io_direction |= mask; - } else { - pca9675_iox[ioex].io_direction &= ~mask; - - /* Initialize the pin */ - rv = pca9675_set_level(ioex, port, mask, flags & GPIO_HIGH); - } - - return rv; -} - -static int pca9675_enable_interrupt(int ioex, int port, int mask, int enable) -{ - /* - * Nothing to do as an interrupt is generated by any rising or - * falling edge of the port inputs. - */ - return EC_SUCCESS; -} - -int pca9675_init(int ioex) -{ - pca9675_iox[ioex].io_direction = PCA9675_DEFAULT_IO_DIRECTION; - pca9675_iox[ioex].cache_out_pins = 0; - - /* Set pca9675 to Power-on reset */ - return pca9675_reset(ioex); -} - -const struct ioexpander_drv pca9675_ioexpander_drv = { - .init = &pca9675_init, - .get_level = &pca9675_get_level, - .set_level = &pca9675_set_level, - .get_flags_by_mask = &pca9675_get_flags_by_mask, - .set_flags_by_mask = &pca9675_set_flags_by_mask, - .enable_interrupt = &pca9675_enable_interrupt, -}; diff --git a/driver/ioexpander/pca9675.h b/driver/ioexpander/pca9675.h deleted file mode 100644 index 59f36918a4..0000000000 --- a/driver/ioexpander/pca9675.h +++ /dev/null @@ -1,39 +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. - * - * NXP PCA9675PW I/O Port expander driver header - */ - -#ifndef __CROS_EC_IOEXPANDER_PCA9675_H -#define __CROS_EC_IOEXPANDER_PCA9675_H - -/* PCA9675 IO pins that can be referenced in gpio.inc */ -enum pca9675_io_pins { - PCA9675_IO_P00, - PCA9675_IO_P01, - PCA9675_IO_P02, - PCA9675_IO_P03, - PCA9675_IO_P04, - PCA9675_IO_P05, - PCA9675_IO_P06, - PCA9675_IO_P07, - PCA9675_IO_P10, - PCA9675_IO_P11, - PCA9675_IO_P12, - PCA9675_IO_P13, - PCA9675_IO_P14, - PCA9675_IO_P15, - PCA9675_IO_P16, - PCA9675_IO_P17, -}; - -/* Write 06 to address 00 to reset the PCA9675 to back to power up state */ -#define PCA9675_RESET_SEQ_DATA 0x06 - -/* Default I/O directons of PCA9675 is input */ -#define PCA9675_DEFAULT_IO_DIRECTION 0xffff - -extern const struct ioexpander_drv pca9675_ioexpander_drv; - -#endif /* __CROS_EC_IOEXPANDER_PCA9675_H */ diff --git a/driver/ioexpander/pcal6408.c b/driver/ioexpander/pcal6408.c deleted file mode 100644 index 287e0506d0..0000000000 --- a/driver/ioexpander/pcal6408.c +++ /dev/null @@ -1,354 +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. - * - * NXP PCA(L)6408 I/O expander - */ -#include "common.h" -#include "console.h" -#include "math_util.h" -#include "gpio.h" -#include "i2c.h" -#include "ioexpander.h" -#include "pcal6408.h" - -#define CPRINTF(format, args...) cprintf(CC_GPIO, format, ## args) -#define CPRINTS(format, args...) cprints(CC_GPIO, format, ## args) - -/* - * Store interrupt mask registers locally. In this way, - * we don't have to read it via i2c transaction every time. - * Default value of interrupt mask register is 0xff. - */ -uint8_t pcal6408_int_mask[] = { - [0 ... (CONFIG_IO_EXPANDER_PORT_COUNT - 1)] = 0xff }; - - -static int pcal6408_read(int ioex, int reg, int *data) -{ - int rv; - struct ioexpander_config_t *ioex_p = &ioex_config[ioex]; - - rv = i2c_read8(ioex_p->i2c_host_port, ioex_p->i2c_addr_flags, - reg, data); - - return rv; -} - -static int pcal6408_write(int ioex, int reg, int data) -{ - int rv; - struct ioexpander_config_t *ioex_p = &ioex_config[ioex]; - - rv = i2c_write8(ioex_p->i2c_host_port, ioex_p->i2c_addr_flags, - reg, data); - - return rv; -} - -static int pcal6408_ioex_check_is_valid(int port, int mask) -{ - if (port != 0) - return EC_ERROR_INVAL; - - if (mask & ~PCAL6408_VALID_GPIO_MASK) { - CPRINTF("GPIO%02d is not support in PCAL6408\n", - __fls(mask)); - return EC_ERROR_INVAL; - } - - return EC_SUCCESS; -} - -static int pcal6408_ioex_init(int ioex) -{ - /* It seems that we have nothing to do here. - * This chip has not a chip id to be identified. - */ - return EC_SUCCESS; -} - -static int pcal6408_ioex_get_level(int ioex, int port, int mask, int *val) -{ - int rv; - - rv = pcal6408_ioex_check_is_valid(port, mask); - if (rv != EC_SUCCESS) - return rv; - - rv = pcal6408_read(ioex, PCAL6408_REG_INPUT, val); - if (rv != EC_SUCCESS) - return rv; - - *val = !!(*val & mask); - - return EC_SUCCESS; -} - -static int pcal6408_ioex_set_level(int ioex, int port, int mask, int value) -{ - int rv, val; - - rv = pcal6408_ioex_check_is_valid(port, mask); - if (rv != EC_SUCCESS) - return rv; - - rv = pcal6408_read(ioex, PCAL6408_REG_OUTPUT, &val); - if (rv != EC_SUCCESS) - return rv; - - if (value) - val |= mask; - else - val &= ~mask; - - return pcal6408_write(ioex, PCAL6408_REG_OUTPUT, val); -} - -static int pcal6408_ioex_get_flags_by_mask(int ioex, int port, int mask, - int *flags) -{ - int rv, val; - - rv = pcal6408_ioex_check_is_valid(port, mask); - if (rv != EC_SUCCESS) - return rv; - - *flags = GPIO_FLAG_NONE; - - rv = pcal6408_read(ioex, PCAL6408_REG_CONFIG, &val); - if (rv != EC_SUCCESS) - return rv; - - if (val & mask) - *flags |= GPIO_INPUT; - else - *flags |= GPIO_OUTPUT; - - rv = pcal6408_read(ioex, PCAL6408_REG_INPUT, &val); - if (rv != EC_SUCCESS) - return rv; - - if (val & mask) - *flags |= GPIO_HIGH; - else - *flags |= GPIO_LOW; - - rv = pcal6408_read(ioex, PCAL6408_REG_OUT_CONFIG, &val); - if (rv != EC_SUCCESS) - return rv; - - if (val & PCAL6408_OUT_CONFIG_OPEN_DRAIN) - *flags |= GPIO_OPEN_DRAIN; - - rv = pcal6408_read(ioex, PCAL6408_REG_PULL_ENABLE, &val); - if (rv != EC_SUCCESS) - return rv; - - if (val & mask) { - rv = pcal6408_read(ioex, PCAL6408_REG_PULL_UP_DOWN, &val); - if (rv != EC_SUCCESS) - return rv; - - if (val & mask) - *flags |= GPIO_PULL_UP; - else - *flags |= GPIO_PULL_DOWN; - } - - rv = pcal6408_read(ioex, PCAL6408_REG_INT_MASK, &val); - if (rv != EC_SUCCESS) - return rv; - - if ((!!(val & mask) == 0) && ((*flags) & GPIO_INPUT)) - *flags |= GPIO_INT_BOTH; - - return rv; -} - -static int pcal6408_ioex_set_flags_by_mask(int ioex, int port, int mask, - int flags) -{ - int rv, val; - - rv = pcal6408_ioex_check_is_valid(port, mask); - if (rv != EC_SUCCESS) - return rv; - - if (((flags & GPIO_INT_BOTH) == GPIO_INT_RISING) || - ((flags & GPIO_INT_BOTH) == GPIO_INT_FALLING)) { - CPRINTF("PCAL6408 only support GPIO_INT_BOTH.\n"); - return EC_ERROR_INVAL; - } - - - if ((flags & (GPIO_INT_F_RISING | GPIO_INT_F_FALLING)) && - !(flags & GPIO_INPUT)) { - CPRINTF("Interrupt pin must be GPIO_INPUT.\n"); - return EC_ERROR_INVAL; - } - - /* All output gpios share GPIO_OPEN_DRAIN, should be consistent */ - if (flags & GPIO_OPEN_DRAIN) - val = PCAL6408_OUT_CONFIG_OPEN_DRAIN; - else - val = 0; - - rv = pcal6408_write(ioex, PCAL6408_REG_OUT_CONFIG, val); - if (rv != EC_SUCCESS) - return rv; - - rv = pcal6408_read(ioex, PCAL6408_REG_CONFIG, &val); - if (rv != EC_SUCCESS) - return rv; - - if (flags & GPIO_INPUT) - val |= mask; - if (flags & GPIO_OUTPUT) - val &= ~mask; - - rv = pcal6408_write(ioex, PCAL6408_REG_CONFIG, val); - if (rv != EC_SUCCESS) - return rv; - - if (flags & GPIO_OUTPUT) { - rv = pcal6408_read(ioex, PCAL6408_REG_OUTPUT, &val); - if (rv != EC_SUCCESS) - return rv; - - if (flags & GPIO_HIGH) - val |= mask; - else if (flags & GPIO_LOW) - val &= ~mask; - - rv = pcal6408_write(ioex, PCAL6408_REG_OUTPUT, val); - if (rv != EC_SUCCESS) - return rv; - } - - if (!(flags & (GPIO_PULL_UP | GPIO_PULL_DOWN))) { - rv = pcal6408_read(ioex, PCAL6408_REG_PULL_ENABLE, &val); - if (rv != EC_SUCCESS) - return rv; - - val &= ~mask; - - rv = pcal6408_write(ioex, PCAL6408_REG_PULL_ENABLE, val); - if (rv != EC_SUCCESS) - return rv; - } else { - rv = pcal6408_read(ioex, PCAL6408_REG_PULL_ENABLE, &val); - if (rv != EC_SUCCESS) - return rv; - - val |= mask; - - rv = pcal6408_write(ioex, PCAL6408_REG_PULL_ENABLE, val); - if (rv != EC_SUCCESS) - return rv; - - rv = pcal6408_read(ioex, PCAL6408_REG_PULL_UP_DOWN, &val); - if (rv != EC_SUCCESS) - return rv; - - if (flags & GPIO_PULL_UP) - val |= mask; - else if (flags & GPIO_PULL_DOWN) - val &= ~mask; - - rv = pcal6408_write(ioex, PCAL6408_REG_PULL_UP_DOWN, val); - if (rv != EC_SUCCESS) - return rv; - } - - return rv; -} - -static int pcal6408_ioex_enable_interrupt(int ioex, int port, int mask, - int enable) -{ - int rv, val; - - rv = pcal6408_ioex_check_is_valid(port, mask); - if (rv != EC_SUCCESS) - return rv; - - /* Interrupt should be latched */ - rv = pcal6408_read(ioex, PCAL6408_REG_INPUT_LATCH, &val); - if (rv != EC_SUCCESS) - return rv; - - if (enable) - val |= mask; - else - val &= ~mask; - - rv = pcal6408_write(ioex, PCAL6408_REG_INPUT_LATCH, val); - if (rv != EC_SUCCESS) - return rv; - - /* - * Enable or disable interrupt. - * In PCAL6408_REG_INT_MASK, 0 = enable interrupt, - * 1 = disable interrupt. - */ - if (enable) - pcal6408_int_mask[ioex] &= ~mask; - else - pcal6408_int_mask[ioex] |= mask; - - rv = pcal6408_write(ioex, PCAL6408_REG_INT_MASK, - pcal6408_int_mask[ioex]); - - return rv; -} - -int pcal6408_ioex_event_handler(int ioex) -{ - int int_status, int_mask; - struct ioexpander_config_t *ioex_p = &ioex_config[ioex]; - int i, rv = 0; - const struct ioex_info *g; - - int_mask = pcal6408_int_mask[ioex]; - - /* - * Read input port register will clear the interrupt, - * read status register will not. - */ - rv = i2c_read8(ioex_p->i2c_host_port, ioex_p->i2c_addr_flags, - PCAL6408_REG_INT_STATUS, &int_status); - if (rv != EC_SUCCESS) - return rv; - - /* - * In pcal6408_int_mask[x], 0 = enable interrupt, - * 1 = disable interrupt. - */ - int_status = int_status & ~int_mask; - - if (!int_status) - return EC_SUCCESS; - - for (i = 0, g = ioex_list; i < ioex_ih_count; i++, g++) { - - if (ioex == g->ioex && 0 == g->port && - (int_status & g->mask)) { - ioex_irq_handlers[i](i + IOEX_SIGNAL_START); - int_status &= ~g->mask; - if (!int_status) - break; - } - } - - return EC_SUCCESS; -} - -const struct ioexpander_drv pcal6408_ioexpander_drv = { - .init = &pcal6408_ioex_init, - .get_level = &pcal6408_ioex_get_level, - .set_level = &pcal6408_ioex_set_level, - .get_flags_by_mask = &pcal6408_ioex_get_flags_by_mask, - .set_flags_by_mask = &pcal6408_ioex_set_flags_by_mask, - .enable_interrupt = &pcal6408_ioex_enable_interrupt, -}; diff --git a/driver/ioexpander/pcal6408.h b/driver/ioexpander/pcal6408.h deleted file mode 100644 index fc9969aab1..0000000000 --- a/driver/ioexpander/pcal6408.h +++ /dev/null @@ -1,42 +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. - * - * NXP PCA(L)6408 I/O expander - */ - -#ifndef __CROS_EC_IOEXPANDER_PCAL6408_H -#define __CROS_EC_IOEXPANDER_PCAL6408_H - -#define PCAL6408_I2C_ADDR0 0x20 -#define PCAL6408_I2C_ADDR1 0x21 - -#define PCAL6408_REG_INPUT 0x00 -#define PCAL6408_REG_OUTPUT 0x01 -#define PCAL6408_REG_POLARITY_INVERSION 0x02 -#define PCAL6408_REG_CONFIG 0x03 -#define PCAL6408_REG_OUT_STRENGTH0 0x40 -#define PCAL6408_REG_OUT_STRENGTH1 0x41 -#define PCAL6408_REG_INPUT_LATCH 0x42 -#define PCAL6408_REG_PULL_ENABLE 0x43 -#define PCAL6408_REG_PULL_UP_DOWN 0x44 -#define PCAL6408_REG_INT_MASK 0x45 -#define PCAL6408_REG_INT_STATUS 0x46 -#define PCAL6408_REG_OUT_CONFIG 0x4f - -#define PCAL6408_VALID_GPIO_MASK 0xff - -#define PCAL6408_OUTPUT 0 -#define PCAL6408_INPUT 1 - -#define PCAL6408_OUT_CONFIG_OPEN_DRAIN 0x01 - -/* - * Check which IO's interrupt event is triggered. If any, call its - * registered interrupt handler. - */ -int pcal6408_ioex_event_handler(int ioex); - -extern const struct ioexpander_drv pcal6408_ioexpander_drv; - -#endif /* __CROS_EC_IOEXPANDER_PCAL6408_H */ diff --git a/driver/ioexpander/tca64xxa.c b/driver/ioexpander/tca64xxa.c deleted file mode 100644 index 9a70ceec11..0000000000 --- a/driver/ioexpander/tca64xxa.c +++ /dev/null @@ -1,226 +0,0 @@ -/* Copyright 2021 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 "common.h" -#include "i2c.h" -#include "ioexpander.h" -#include "system.h" -#include "tca64xxa.h" - -/* - * This chip series contain registers in the same order. - * Difference between models is only amount of registers and - * value of which you must multiply to access specific register. - * For 16 bit series, registers are 2 byte away, so to access TCA64XXA_REG_CONF - * you must multiply it by 2. For 24 bit, they are away by 4 bytes so you - * must multiply them by 4. Flags value contains information which version - * of chip is used. - */ -#define TCA64XXA_PORT_ID(port, reg, flags) \ - ((((flags) & TCA64XXA_FLAG_VER_MASK) \ - >> TCA64XXA_FLAG_VER_OFFSET) * (reg) + (port)) - -static int tca64xxa_write_byte(int ioex, int port, int reg, uint8_t val) -{ - const struct ioexpander_config_t *ioex_p = &ioex_config[ioex]; - const int reg_addr = TCA64XXA_PORT_ID(port, reg, ioex_p->flags); - - return i2c_write8(ioex_p->i2c_host_port, - ioex_p->i2c_addr_flags, - reg_addr, - val); -} - -static int tca64xxa_read_byte(int ioex, int port, int reg, int *val) -{ - const struct ioexpander_config_t *ioex_p = &ioex_config[ioex]; - const int reg_addr = TCA64XXA_PORT_ID(port, reg, ioex_p->flags); - - return i2c_read8(ioex_p->i2c_host_port, - ioex_p->i2c_addr_flags, - reg_addr, - val); -} - -/* Restore default values in registers */ -static int tca64xxa_reset(int ioex, int portsCount) -{ - int port; - int ret; - - /* - * On servo_v4p1, reset pin is pulled up and it results in values - * not being restored to default ones after software reboot. - * This loop sets default values (from specification) to all registers. - */ - for (port = 0; port < portsCount; port++) { - ret = tca64xxa_write_byte(ioex, - port, - TCA64XXA_REG_OUTPUT, - TCA64XXA_DEFAULT_OUTPUT); - if (ret) - return ret; - - ret = tca64xxa_write_byte(ioex, - port, - TCA64XXA_REG_POLARITY_INV, - TCA64XXA_DEFAULT_POLARITY_INV); - if (ret) - return ret; - - ret = tca64xxa_write_byte(ioex, - port, - TCA64XXA_REG_CONF, - TCA64XXA_DEFAULT_CONF); - if (ret) - return ret; - } - - return EC_SUCCESS; -} - -/* Initialize IO expander chip/driver */ -static int tca64xxa_init(int ioex) -{ - const struct ioexpander_config_t *ioex_p = &ioex_config[ioex]; - int portsCount; - - if (ioex_p->flags & TCA64XXA_FLAG_VER_TCA6416A) - portsCount = 2; - else if (ioex_p->flags & TCA64XXA_FLAG_VER_TCA6424A) - portsCount = 3; - else - return EC_ERROR_UNIMPLEMENTED; - - if (!system_jumped_late()) - return tca64xxa_reset(ioex, portsCount); - - return EC_SUCCESS; -} - -/* Get the current level of the IOEX pin */ -static int tca64xxa_get_level(int ioex, int port, int mask, int *val) -{ - int buf; - int ret; - - ret = tca64xxa_read_byte(ioex, port, TCA64XXA_REG_INPUT, &buf); - *val = !!(buf & mask); - - return ret; -} - -/* Set the level of the IOEX pin */ -static int tca64xxa_set_level(int ioex, int port, int mask, int val) -{ - int ret; - int v; - - ret = tca64xxa_read_byte(ioex, port, TCA64XXA_REG_OUTPUT, &v); - if (ret) - return ret; - - if (val) - v |= mask; - else - v &= ~mask; - - return tca64xxa_write_byte(ioex, port, TCA64XXA_REG_OUTPUT, v); -} - -/* Get flags for the IOEX pin */ -static int tca64xxa_get_flags_by_mask(int ioex, int port, int mask, int *flags) -{ - int ret; - int v; - - ret = tca64xxa_read_byte(ioex, port, TCA64XXA_REG_CONF, &v); - if (ret) - return ret; - - *flags = 0; - if (v & mask) { - *flags |= GPIO_INPUT; - } else { - *flags |= GPIO_OUTPUT; - - ret = tca64xxa_read_byte(ioex, port, TCA64XXA_REG_OUTPUT, &v); - if(ret) - return ret; - - if (v & mask) - *flags |= GPIO_HIGH; - else - *flags |= GPIO_LOW; - } - - return EC_SUCCESS; -} - -/* Set flags for the IOEX pin */ -static int tca64xxa_set_flags_by_mask(int ioex, int port, int mask, int flags) -{ - int ret; - int v; - - /* Output value */ - if (flags & GPIO_OUTPUT) { - ret = tca64xxa_read_byte(ioex, port, TCA64XXA_REG_OUTPUT, &v); - if (ret) - return ret; - - if (flags & GPIO_LOW) - v &= ~mask; - else if (flags & GPIO_HIGH) - v |= mask; - else - return EC_ERROR_INVAL; - - ret = tca64xxa_write_byte(ioex, port, TCA64XXA_REG_OUTPUT, v); - if (ret) - return ret; - } - - /* Configuration */ - ret = tca64xxa_read_byte(ioex, port, TCA64XXA_REG_CONF, &v); - if(ret) - return ret; - - if (flags & GPIO_INPUT) - v |= mask; - else if (flags & GPIO_OUTPUT) - v &= ~mask; - else - return EC_ERROR_INVAL; - - ret = tca64xxa_write_byte(ioex, port, TCA64XXA_REG_CONF, v); - if (ret) - return ret; - - return EC_SUCCESS; -} - -#ifdef CONFIG_IO_EXPANDER_SUPPORT_GET_PORT - -/* Read levels for whole IO expander port */ -static int tca64xxa_get_port(int ioex, int port, int *val) -{ - return tca64xxa_read_byte(ioex, port, TCA64XXA_REG_INPUT, val); -} - -#endif - -/* Driver structure */ -const struct ioexpander_drv tca64xxa_ioexpander_drv = { - .init = tca64xxa_init, - .get_level = tca64xxa_get_level, - .set_level = tca64xxa_set_level, - .get_flags_by_mask = tca64xxa_get_flags_by_mask, - .set_flags_by_mask = tca64xxa_set_flags_by_mask, - .enable_interrupt = NULL, -#ifdef CONFIG_IO_EXPANDER_SUPPORT_GET_PORT - .get_port = tca64xxa_get_port, -#endif -}; diff --git a/driver/ioexpander/tca64xxa.h b/driver/ioexpander/tca64xxa.h deleted file mode 100644 index 8c3448f804..0000000000 --- a/driver/ioexpander/tca64xxa.h +++ /dev/null @@ -1,25 +0,0 @@ -/* Copyright 2021 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. - */ - -#ifndef __CROS_EC_DRIVER_IOEXPANDER_TCA64XXA_H_ -#define __CROS_EC_DRIVER_IOEXPANDER_TCA64XXA_H_ - -#define TCA64XXA_FLAG_VER_TCA6416A 2 -#define TCA64XXA_FLAG_VER_TCA6424A 4 -#define TCA64XXA_FLAG_VER_MASK GENMASK(2, 1) -#define TCA64XXA_FLAG_VER_OFFSET 0 - -#define TCA64XXA_REG_INPUT 0 -#define TCA64XXA_REG_OUTPUT 1 -#define TCA64XXA_REG_POLARITY_INV 2 -#define TCA64XXA_REG_CONF 3 - -#define TCA64XXA_DEFAULT_OUTPUT 0xFF -#define TCA64XXA_DEFAULT_POLARITY_INV 0x00 -#define TCA64XXA_DEFAULT_CONF 0xFF - -extern const struct ioexpander_drv tca64xxa_ioexpander_drv; - -#endif /* __CROS_EC_DRIVER_IOEXPANDER_TCA64XXA_H_ */ diff --git a/driver/led/ds2413.c b/driver/led/ds2413.c deleted file mode 100644 index b856d85671..0000000000 --- a/driver/led/ds2413.c +++ /dev/null @@ -1,166 +0,0 @@ -/* Copyright 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. - */ - -/* Power LED control for Chrome EC */ - -#include "charge_state.h" -#include "console.h" -#include "hooks.h" -#include "onewire.h" -#include "timer.h" -#include "util.h" - -#define ONEWIRE_RETRIES 10 - -enum led_color { - LED_OFF = 0, - LED_RED, - LED_YELLOW, - LED_GREEN, - LED_COLOR_COUNT /* Number of colors, not a color itself */ -}; - -static const uint8_t led_masks[LED_COLOR_COUNT] = {0xff, 0xfe, 0xfc, 0xfd}; -static const char * const color_names[LED_COLOR_COUNT] = { - "off", "red", "yellow", "green"}; - -/** - * Set the onewire LED GPIO controller outputs - * - * @param mask Mask of outputs to enable - * - * @return EC_SUCCESS, or non-zero if error. - */ -static int led_set_mask(int mask) -{ - int rv; - - /* Reset the 1-wire bus */ - rv = onewire_reset(); - if (rv) - return rv; - - /* Skip ROM, since only one device */ - onewire_write(0xcc); - - /* Write and turn on the LEDs */ - onewire_write(0x5a); - onewire_write(mask); - onewire_write(~mask); /* Repeat inverted */ - - rv = onewire_read(); /* Confirmation byte */ - if (rv != 0xaa) - return EC_ERROR_UNKNOWN; - - /* The next byte is a read-back of the chip status. Since we're only - * using lines as outputs, we can ignore it. */ - return EC_SUCCESS; -} - -static int led_set(enum led_color color) -{ - int rv = EC_SUCCESS; - int i; - - /* - * 1-wire communication can fail for timing reasons in the current - * system. We have a limited timing window to send/receive bits, but - * we can't disable interrupts for the rest of the system to guarantee - * we hit that window. Instead, simply retry the low-level command a - * few times. - */ - for (i = 0; i < ONEWIRE_RETRIES; i++) { - rv = led_set_mask(led_masks[color]); - if (rv == EC_SUCCESS) - break; - - /* - * Sleep for a bit between tries. This gives the 1-wire GPIO - * chip time to recover from the failed attempt, and allows - * lower-priority tasks a chance to run. - */ - usleep(100); - } - - return rv; -} - -/*****************************************************************************/ -/* Hooks */ - -static void onewire_led_tick(void) -{ - static enum led_color current_color = LED_COLOR_COUNT; - static int tick_count; - - enum led_color new_color = LED_OFF; - uint32_t chflags = charge_get_flags(); - - tick_count++; - - if (!(chflags & CHARGE_FLAG_EXTERNAL_POWER)) { - /* AC isn't present, so the power LED on the AC plug is off */ - current_color = LED_OFF; - return; - } - - /* Translate charge state to LED color */ - switch (charge_get_state()) { - case PWR_STATE_IDLE: - if (chflags & CHARGE_FLAG_FORCE_IDLE) - new_color = (tick_count & 1) ? LED_GREEN : LED_OFF; - else - new_color = LED_GREEN; - break; - case PWR_STATE_CHARGE: - new_color = LED_YELLOW; - break; - case PWR_STATE_CHARGE_NEAR_FULL: - new_color = LED_GREEN; - break; - case PWR_STATE_ERROR: - new_color = LED_RED; - break; - default: - /* Other states don't change LED color */ - break; - } - - /* - * The power adapter on link can partially unplug and lose its LED - * state. There's no way to detect this, so just assume it forgets its - * state every 10 seconds. - */ - if (!(tick_count % 10)) - current_color = LED_COLOR_COUNT; - - /* If current color is still correct, leave now */ - if (new_color == current_color) - return; - - /* Update LED */ - if (!led_set(new_color)) - current_color = new_color; -} -DECLARE_HOOK(HOOK_SECOND, onewire_led_tick, HOOK_PRIO_DEFAULT); - -/*****************************************************************************/ -/* Console commands */ -#define CONFIG_CMD_POWERLED -static int command_powerled(int argc, char **argv) -{ - int i; - - /* Pick a color, any color... */ - for (i = 0; i < LED_COLOR_COUNT; i++) { - if (!strcasecmp(argv[1], color_names[i])) - return led_set(i); - } - return EC_ERROR_PARAM1; -} -DECLARE_CONSOLE_COMMAND(powerled, command_powerled, - "<off | red | yellow | green>", - "Set power LED color"); -#endif diff --git a/driver/led/lm3509.c b/driver/led/lm3509.c deleted file mode 100644 index 7c20c43ac2..0000000000 --- a/driver/led/lm3509.c +++ /dev/null @@ -1,85 +0,0 @@ -/* Copyright 2018 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. - * - * TI LM3509 LED driver. - */ - -#include "compile_time_macros.h" -#include "i2c.h" -#include "keyboard_backlight.h" -#include "lm3509.h" - -static inline int lm3509_write(uint8_t reg, uint8_t val) -{ - return i2c_write8(I2C_PORT_KBLIGHT, LM3509_I2C_ADDR_FLAGS, - reg, val); -} - -static inline int lm3509_read(uint8_t reg, int *val) -{ - return i2c_read8(I2C_PORT_KBLIGHT, LM3509_I2C_ADDR_FLAGS, - reg, val); -} - -/* Brightness level (0.0 to 100.0%) to brightness register conversion table */ -static const uint16_t lm3509_brightness[32] = { - 0, 1, 6, 10, 11, 13, 16, 20, - 24, 28, 31, 37, 43, 52, 62, 75, - 87, 100, 125, 150, 168, 187, 225, 262, - 312, 375, 437, 525, 612, 700, 875, 1000 -}; - -static int brightness_to_bmain(int percent) -{ - int i; - int b = percent * 10; - - for (i = 1; i < sizeof(lm3509_brightness); i++) { - int low = lm3509_brightness[i - 1]; - int high = lm3509_brightness[i]; - if (high < b) - continue; - /* rounding to the nearest */ - return (b - low < high - b) ? i - 1 : i; - } - /* Brightness is out of range. Return the highest value. */ - return i - 1; -} - -static int lm3509_power(int enable) -{ - /* Enable both MAIN and SUB in unison mode. - * Don't alter brightness here. It's not driver's business. */ - return lm3509_write(LM3509_REG_GP, enable ? 0x7 : 0); -} - -static int lm3509_set_brightness(int percent) -{ - /* We don't need to read/mask/write BMAIN because bit6 and 7 are non - * functional read only bits. - */ - return lm3509_write(LM3509_REG_BMAIN, brightness_to_bmain(percent)); -} - -static int lm3509_get_brightness(void) -{ - int rv, val; - rv = lm3509_read(LM3509_REG_BMAIN, &val); - if (rv) - return -1; - val &= LM3509_BMAIN_MASK; - return lm3509_brightness[val] / 10; -} - -static int lm3509_init(void) -{ - return EC_SUCCESS; -} - -const struct kblight_drv kblight_lm3509 = { - .init = lm3509_init, - .set = lm3509_set_brightness, - .get = lm3509_get_brightness, - .enable = lm3509_power, -}; diff --git a/driver/led/lm3509.h b/driver/led/lm3509.h deleted file mode 100644 index a7defe1fb7..0000000000 --- a/driver/led/lm3509.h +++ /dev/null @@ -1,37 +0,0 @@ -/* Copyright 2018 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. - * - * TI LM3509 LED driver. - */ - -#ifndef __CROS_EC_LM3509_H -#define __CROS_EC_LM3509_H - -#define LM3509_I2C_ADDR_FLAGS 0x36 - -/* - * General purpose register - * - * [2]= set both main and secondary current same - * both control by BMAIN. - * [1]= enable secondary current sink. - * [0]= enable main current sink. - */ -#define LM3509_REG_GP 0x10 - -/* - * Brightness register - * - * 0x00: 0% - * 0x1F: 100% - * Power-on-value: 0% (0xE0) - */ -#define LM3509_REG_BMAIN 0xA0 -#define LM3509_REG_BSUB 0xB0 - -#define LM3509_BMAIN_MASK 0x1F - -extern const struct kblight_drv kblight_lm3509; - -#endif /* __CROS_EC_LM3509_H */ diff --git a/driver/led/lm3630a.c b/driver/led/lm3630a.c deleted file mode 100644 index a2c4aaa74c..0000000000 --- a/driver/led/lm3630a.c +++ /dev/null @@ -1,86 +0,0 @@ -/* Copyright 2018 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. - * - * TI LM3630A LED driver. - */ - -#include "hooks.h" -#include "i2c.h" -#include "lm3630a.h" -#include "timer.h" - - -/* I2C address */ -#define LM3630A_I2C_ADDR_FLAGS 0x36 - -static inline int lm3630a_write(uint8_t reg, uint8_t val) -{ - return i2c_write8(I2C_PORT_KBLIGHT, LM3630A_I2C_ADDR_FLAGS, - reg, val); -} - -static inline int lm3630a_read(uint8_t reg, int *val) -{ - return i2c_read8(I2C_PORT_KBLIGHT, LM3630A_I2C_ADDR_FLAGS, - reg, val); -} - -static void deferred_lm3630a_poweron(void) -{ - /* - * Set full brightness so that PWM will control. This needs to happen - * after setting the control register, because enabling the banks - * resets the value to 0. - */ - lm3630a_write(LM3630A_REG_A_BRIGHTNESS, 0xff); -} -DECLARE_DEFERRED(deferred_lm3630a_poweron); - -int lm3630a_poweron(void) -{ - int ret = 0; - - /* - * LM3630A will NAK I2C transactions for 1ms (tWAIT in the datasheet) - * after HWEN asserted or after SW reset. - */ - msleep(1); - - /* Sample PWM every 8 periods. */ - ret |= lm3630a_write(LM3630A_REG_FILTER_STRENGTH, 0x3); - - /* Enable feedback and PWM for banks A. */ - ret |= lm3630a_write(LM3630A_REG_CONFIG, - LM3630A_CFG_BIT_FB_EN_A | - LM3630A_CFG_BIT_PWM_EN_A); - - /* 24V, 800mA overcurrent protection, 500kHz boost frequency. */ - ret |= lm3630a_write(LM3630A_REG_BOOST_CONTROL, - LM3630A_BOOST_OVP_24V | - LM3630A_BOOST_OCP_800MA | - LM3630A_FMODE_500KHZ); - - /* Limit current to 24.5mA */ - ret |= lm3630a_write(LM3630A_REG_A_CURRENT, 0x1a); - - /* Enable bank A, put in linear mode, and connect LED2 to bank A. */ - ret |= lm3630a_write(LM3630A_REG_CONTROL, - LM3630A_CTRL_BIT_LINEAR_A | - LM3630A_CTRL_BIT_LED_EN_A | - LM3630A_CTRL_BIT_LED2_ON_A); - - /* - * Only set the brightness after ~100 ms. Without this, LED may blink - * for a short duration, as the PWM sampler sometimes appears to be - * confused, and slowly dim from a large initial PWM input value. - */ - hook_call_deferred(&deferred_lm3630a_poweron_data, 100 * MSEC); - - return ret; -} - -int lm3630a_poweroff(void) -{ - return lm3630a_write(LM3630A_REG_CONTROL, LM3630A_CTRL_BIT_SLEEP_CMD); -} diff --git a/driver/led/lm3630a.h b/driver/led/lm3630a.h deleted file mode 100644 index d43304b66e..0000000000 --- a/driver/led/lm3630a.h +++ /dev/null @@ -1,68 +0,0 @@ -/* Copyright 2018 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. - * - * TI LM3630A LED driver. - */ - -#ifndef __CROS_EC_LM3630A_H -#define __CROS_EC_LM3630A_H - -#define LM3630A_REG_CONTROL 0x00 -#define LM3630A_REG_CONFIG 0x01 -#define LM3630A_REG_BOOST_CONTROL 0x02 -#define LM3630A_REG_A_BRIGHTNESS 0x03 -#define LM3630A_REG_B_BRIGHTNESS 0x04 -#define LM3630A_REG_A_CURRENT 0x05 -#define LM3630A_REG_B_CURRENT 0x06 -#define LM3630A_REG_ONOFF_RAMP 0x07 -#define LM3630A_REG_RUN_RAMP 0x08 -#define LM3630A_REG_INT_STATUS 0x09 -#define LM3630A_REG_INT_ENABLE 0x0a -#define LM3630A_REG_FAULT_STATUS 0x0b -#define LM3630A_REG_SW_RESET 0x0f -#define LM3630A_REG_PWM_OUT_LOW 0x12 -#define LM3630A_REG_PWM_OUT_HIGH 0x13 -#define LM3630A_REG_REVISION 0x1f -#define LM3630A_REG_FILTER_STRENGTH 0x50 - -/* Control register bits */ -#define LM3630A_CTRL_BIT_SLEEP_CMD BIT(7) -#define LM3630A_CTRL_BIT_SLEEP_STAT BIT(6) -#define LM3630A_CTRL_BIT_LINEAR_A BIT(4) -#define LM3630A_CTRL_BIT_LINEAR_B BIT(3) -#define LM3630A_CTRL_BIT_LED_EN_A BIT(2) -#define LM3630A_CTRL_BIT_LED_EN_B BIT(1) -#define LM3630A_CTRL_BIT_LED2_ON_A BIT(0) - -/* Config register bits */ -#define LM3630A_CFG_BIT_FB_EN_B BIT(4) -#define LM3630A_CFG_BIT_FB_EN_A BIT(3) -#define LM3630A_CFG_BIT_PWM_LOW BIT(2) -#define LM3630A_CFG_BIT_PWM_EN_B BIT(1) -#define LM3630A_CFG_BIT_PWM_EN_A BIT(0) - -/* Boost control register bits */ -#define LM3630A_BOOST_OVP_16V (0 << 5) -#define LM3630A_BOOST_OVP_24V BIT(5) -#define LM3630A_BOOST_OVP_32V (2 << 5) -#define LM3630A_BOOST_OVP_40V (3 << 5) -#define LM3630A_BOOST_OCP_600MA (0 << 3) -#define LM3630A_BOOST_OCP_800MA BIT(3) -#define LM3630A_BOOST_OCP_1000MA (2 << 3) -#define LM3630A_BOOST_OCP_1200MA (3 << 3) -#define LM3630A_BOOST_SLOW_START BIT(2) -#define LM3630A_SHIFT_500KHZ (0 << 1) /* FMODE=0 */ -#define LM3630A_SHIFT_560KHZ BIT(1) /* FMODE=0 */ -#define LM3630A_SHIFT_1000KHZ (0 << 1) /* FMODE=1 */ -#define LM3630A_SHIFT_1120KHZ BIT(1) /* FMODE=1 */ -#define LM3630A_FMODE_500KHZ (0 << 0) -#define LM3630A_FMODE_1000KHZ BIT(0) - -/* Power on and initialize LM3630A. */ -int lm3630a_poweron(void); - -/* Power off LM3630A. */ -int lm3630a_poweroff(void); - -#endif /* __CROS_EC_LM3630A_H */ diff --git a/driver/led/lp5562.c b/driver/led/lp5562.c deleted file mode 100644 index e0758a8b91..0000000000 --- a/driver/led/lp5562.c +++ /dev/null @@ -1,160 +0,0 @@ -/* Copyright 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. - * - * TI LP5562 driver. - */ - -#include "console.h" -#include "i2c.h" -#include "lp5562.h" -#include "timer.h" -#include "util.h" - -/* I2C address */ -#define LP5562_I2C_ADDR_FLAGS 0x30 - -inline int lp5562_write(uint8_t reg, uint8_t val) -{ - return i2c_write8(I2C_PORT_MASTER, LP5562_I2C_ADDR_FLAGS, reg, val); -} - -inline int lp5562_read(uint8_t reg, int *val) -{ - return i2c_read8(I2C_PORT_MASTER, LP5562_I2C_ADDR_FLAGS, reg, val); -} - -int lp5562_set_color(uint32_t rgb) -{ - int ret = 0; - - ret |= lp5562_write(LP5562_REG_B_PWM, rgb & 0xff); - ret |= lp5562_write(LP5562_REG_G_PWM, (rgb >> 8) & 0xff); - ret |= lp5562_write(LP5562_REG_R_PWM, (rgb >> 16) & 0xff); - - return ret; -} - -int lp5562_set_engine(uint8_t r, uint8_t g, uint8_t b) -{ - return lp5562_write(LP5562_REG_LED_MAP, (r << 4) | (g << 2) | b); -} - -int lp5562_engine_load(int engine, const uint8_t *program, int size) -{ - int prog_addr = LP5562_REG_ENG_PROG(engine); - int i, ret, val; - int shift = 6 - engine * 2; - - ret = lp5562_read(LP5562_REG_OP_MODE, &val); - if (ret) - return ret; - val &= ~(0x3 << shift); - val |= 0x1 << shift; - ret = lp5562_write(LP5562_REG_OP_MODE, val); - if (ret) - return ret; - - for (i = 0; i < size; ++i) { - ret = lp5562_write(prog_addr + i, program[i]); - if (ret) - return ret; - } - - val &= ~(0x3 << shift); - val |= 0x2 << shift; - ret = lp5562_write(LP5562_REG_OP_MODE, val); - - return ret; -} - -int lp5562_engine_control(int eng1, int eng2, int eng3) -{ - int ret, val; - - ret = lp5562_read(LP5562_REG_ENABLE, &val); - if (ret) - return ret; - val &= 0xc0; - val |= (eng1 << 4) | (eng2 << 2) | eng3; - return lp5562_write(LP5562_REG_ENABLE, val); -} - -int lp5562_get_engine_state(int engine) -{ - int val; - - if (lp5562_read(LP5562_REG_ENABLE, &val)) - return 0xee; - return (val >> (6 - engine * 2)) & 0x3; -} - -int lp5562_poweron(void) -{ - int ret = 0; - - ret |= lp5562_write(LP5562_REG_ENABLE, 0x40); - udelay(500); /* start-up delay */ - - ret |= lp5562_write(LP5562_REG_CONFIG, 0x1); - ret |= lp5562_write(LP5562_REG_LED_MAP, 0x0); - - return ret; -} - -int lp5562_poweroff(void) -{ - return lp5562_write(LP5562_REG_ENABLE, 0x0); -} - -int lp5562_get_pc(int engine) -{ - int ret; - if (lp5562_read(LP5562_REG_ENG1_PC + engine - 1, &ret)) - return 0xee; - return ret; -} - -int lp5562_set_pc(int engine, int val) -{ - return lp5562_write(LP5562_REG_ENG1_PC + engine - 1, val); -} - -/*****************************************************************************/ -/* Console commands */ -#ifdef CONFIG_CMD_POWERLED -static int command_lp5562(int argc, char **argv) -{ - if (argc == 4) { - char *e; - uint8_t red, green, blue; - - red = strtoi(argv[1], &e, 0); - if (e && *e) - return EC_ERROR_PARAM1; - green = strtoi(argv[2], &e, 0); - if (e && *e) - return EC_ERROR_PARAM2; - blue = strtoi(argv[3], &e, 0); - if (e && *e) - return EC_ERROR_PARAM3; - - return lp5562_set_color((red << 16) | (green << 8) | blue); - } else if (argc == 2) { - int v; - - if (!parse_bool(argv[1], &v)) - return EC_ERROR_PARAM1; - - if (v) - return lp5562_poweron(); - else - return lp5562_poweroff(); - } - - return EC_ERROR_INVAL; -} -DECLARE_CONSOLE_COMMAND(lp5562, command_lp5562, - "on | off | <red> <green> <blue>", - "Set the color of the LED"); -#endif diff --git a/driver/led/lp5562.h b/driver/led/lp5562.h deleted file mode 100644 index 75e820aab7..0000000000 --- a/driver/led/lp5562.h +++ /dev/null @@ -1,76 +0,0 @@ -/* Copyright 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. - * - * TI LP5562 LED driver. - */ - -#ifndef __CROS_EC_LP5562_H -#define __CROS_EC_LP5562_H - -#define LP5562_REG_ENABLE 0x00 -#define LP5562_REG_OP_MODE 0x01 -#define LP5562_REG_B_PWM 0x02 -#define LP5562_REG_G_PWM 0x03 -#define LP5562_REG_R_PWM 0x04 -#define LP5562_REG_B_CURRENT 0x05 -#define LP5562_REG_G_CURRENT 0x06 -#define LP5562_REG_R_CURRENT 0x07 -#define LP5562_REG_CONFIG 0x08 -#define LP5562_REG_ENG1_PC 0x09 -#define LP5562_REG_ENG2_PC 0x0a -#define LP5562_REG_ENG3_PC 0x0b -#define LP5562_REG_STATUS 0x0c -#define LP5562_REG_RESET 0x0d -#define LP5562_REG_W_PWM 0x0e -#define LP5562_REG_W_CURRENT 0x0f -#define LP5562_REG_LED_MAP 0x70 - -#define LP5562_REG_ENG_PROG(n) (0x10 + ((n)-1) * 0x20) - -/* Brightness range: 0x00 - 0xff */ -#define LP5562_COLOR_NONE 0x000000 -#define LP5562_COLOR_RED(b) (0x010000 * (b)) -#define LP5562_COLOR_GREEN(b) (0x000100 * (b)) -#define LP5562_COLOR_BLUE(b) (0x000001 * (b)) - -#define LP5562_ENG_SEL_NONE 0x0 -#define LP5562_ENG_SEL_1 0x1 -#define LP5562_ENG_SEL_2 0x2 -#define LP5562_ENG_SEL_3 0x3 - -#define LP5562_ENG_HOLD 0x0 -#define LP5562_ENG_STEP 0x1 -#define LP5562_ENG_RUN 0x2 - -/* Power on and initialize LP5562. */ -int lp5562_poweron(void); - -/* Power off LP5562. */ -int lp5562_poweroff(void); - -/* - * Set LED color. - * The parameter 'rgb' is in the format 0x00RRGGBB. - */ -int lp5562_set_color(uint32_t rgb); - -/* Set lighting engine used by each color */ -int lp5562_set_engine(uint8_t r, uint8_t g, uint8_t b); - -/* Load lighting engine program */ -int lp5562_engine_load(int engine, const uint8_t *program, int size); - -/* Control lighting engine execution state */ -int lp5562_engine_control(int eng1, int eng2, int eng3); - -/* Get engine execution state. Return 0xee on error. */ -int lp5562_get_engine_state(int engine); - -/* Get current program counter. Return 0xee on error. */ -int lp5562_get_pc(int engine); - -/* Set program counter */ -int lp5562_set_pc(int engine, int val); - -#endif /* __CROS_EC_LP5562_H */ diff --git a/driver/led/max695x.c b/driver/led/max695x.c deleted file mode 100644 index 6f0e1b8e84..0000000000 --- a/driver/led/max695x.c +++ /dev/null @@ -1,123 +0,0 @@ -/* Copyright 2019 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. - * - * MAX6958/MAX6959 7-Segment LED Display Driver - */ - -#include "common.h" -#include "console.h" -#include "display_7seg.h" -#include "hooks.h" -#include "i2c.h" -#include "max695x.h" -#include "util.h" - -#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args) - -static inline int max695x_i2c_write8(uint8_t offset, uint8_t data) -{ - return i2c_write8(I2C_PORT_PORT80, PORT80_I2C_ADDR, - offset, (int)data); -} - -static inline int max695x_i2c_write(uint8_t offset, uint8_t *data, int len) -{ - /* - * The address pointer stored in the MAX695x increments after - * each data byte is written unless the address equals 01111111 - */ - return i2c_write_block(I2C_PORT_PORT80, PORT80_I2C_ADDR, - offset, data, len); -} - -int display_7seg_write(enum seven_seg_module_display module, uint16_t data) -{ - uint8_t buf[4]; - - /* - * Convert the data into binary coded hexadecimal value i.e. - * in hexadecimal code-decode mode, the decoder prints 1 byte - * on two segments. It checks the lower nibble of the data in - * the digit register (D3–D0), disregarding bits D7–D4. Hence, - * preparing the hexadecimal buffer to be sent. - * - * Segment 3-2 : Module name - * 0xEC : EC - * 0x80 : PORT80 - * Segment 1-0 : Data - * For console Command segment 3-0 : Data - */ - switch (module) { - case SEVEN_SEG_CONSOLE_DISPLAY: - /* Segment - 3 */ - buf[0] = (data >> 12) & 0x0F; - /* Segment - 2 */ - buf[1] = (data >> 8) & 0x0F; - break; - case SEVEN_SEG_EC_DISPLAY: - /* Segment - 3 */ - buf[0] = 0x0E; - /* Segment - 2 */ - buf[1] = 0x0C; - break; - case SEVEN_SEG_PORT80_DISPLAY: - /* Segment - 3 */ - buf[0] = 0x08; - /* Segment - 2 */ - buf[1] = 0x00; - break; - default: - CPRINTS("Unknown Module"); - return EC_ERROR_UNKNOWN; - } - /* Segment - 1 */ - buf[2] = (data >> 4) & 0x0F; - /* Segment - 0 */ - buf[3] = data & 0x0F; - - return max695x_i2c_write(MAX695X_DIGIT0_ADDR, buf, ARRAY_SIZE(buf)); -} - -/** - * Initialise MAX656x 7-segment display. - */ -static void max695x_init(void) -{ - uint8_t buf[4] = { - [0] = MAX695X_DECODE_MODE_HEX_DECODE, - [1] = MAX695X_INTENSITY_MEDIUM, - [2] = MAX695X_SCAN_LIMIT_4, - [3] = MAX695X_CONFIG_OPR_NORMAL - }; - max695x_i2c_write(MAX695X_REG_DECODE_MODE, buf, ARRAY_SIZE(buf)); -} -DECLARE_HOOK(HOOK_INIT, max695x_init, HOOK_PRIO_DEFAULT); - -static void max695x_shutdown(void) -{ - max695x_i2c_write8(MAX695X_REG_CONFIG, - MAX695X_CONFIG_OPR_SHUTDOWN); -} -DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, max695x_shutdown, HOOK_PRIO_DEFAULT); - -#ifdef CONFIG_CMD_SEVEN_SEG_DISPLAY -static int console_command_max695x_write(int argc, char **argv) -{ - char *e; - int val; - - if (argc < 2) - return EC_ERROR_PARAM_COUNT; - - /* Get value to be written to the seven segment display*/ - val = strtoi(argv[1], &e, 0); - if (*e || val < 0 || val > UINT16_MAX) - return EC_ERROR_PARAM1; - - return display_7seg_write(SEVEN_SEG_CONSOLE_DISPLAY, val); -} -DECLARE_CONSOLE_COMMAND(seg, console_command_max695x_write, - "<val>", - "Write to 7 segment display in hex"); -#endif diff --git a/driver/led/max695x.h b/driver/led/max695x.h deleted file mode 100644 index 5ed5d91e2f..0000000000 --- a/driver/led/max695x.h +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright 2019 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. - * - * MAX6958/MAX6959 7-Segment LED Display Driver header - */ - -#ifndef __CROS_EC_MAX656X_H -#define __CROS_EC_MAX656X_H - -/* I2C interface */ -#define MAX695X_I2C_ADDR1_FLAGS 0x38 -#define MAX695X_I2C_ADDR2_FLAGS 0x39 - -/* Decode mode register */ -#define MAX695X_REG_DECODE_MODE 0x01 -/* Hexadecimal decode for digits 3–0 */ -#define MAX695X_DECODE_MODE_HEX_DECODE 0x0f - -/* Intensity register */ -#define MAX695X_REG_INTENSITY 0x02 -/* Setting meduim intensity */ -#define MAX695X_INTENSITY_MEDIUM 0x20 - -/* Scan limit register value */ -#define MAX695X_REG_SCAN_LIMIT 0x03 - -/* Scanning digits 0-3 */ -#define MAX695X_SCAN_LIMIT_4 0x03 - -/* Configuration register */ -#define MAX695X_REG_CONFIG 0x04 -/* Shutdown seven segment display */ -#define MAX695X_CONFIG_OPR_SHUTDOWN 0x00 -/* Start seven segment display */ -#define MAX695X_CONFIG_OPR_NORMAL 0x01 - -/* Digit addresses */ -#define MAX695X_DIGIT0_ADDR 0x20 -#define MAX695X_DIGIT1_ADDR 0x21 -#define MAX695X_DIGIT2_ADDR 0x22 -#define MAX695X_DIGIT3_ADDR 0x23 - -#endif /* __CROS_EC_MAX656X_H */ diff --git a/driver/led/oz554.c b/driver/led/oz554.c deleted file mode 100644 index 504ac55e90..0000000000 --- a/driver/led/oz554.c +++ /dev/null @@ -1,147 +0,0 @@ -/* Copyright 2018 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. - * - * O2 Micro OZ554 LED driver. - */ - -#include "console.h" -#include "gpio.h" -#include "hooks.h" -#include "i2c.h" -#include "oz554.h" -#include "task.h" -#include "timer.h" - -#define CPRINTS(format, args...) cprints(CC_I2C, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_I2C, format, ## args) - -#define I2C_ADDR_OZ554_FLAGS 0x31 - -struct oz554_value { - uint8_t offset; - uint8_t data; -}; - -/* - * OZ554ALN asserts the interrupt when it's ready for writing settings, which - * are cleared when it's turned off. We enable the interrupt on HOOK_INIT and - * keep it enabled in S0/S3/S5. - * - * It's assumed the device doesn't have a lid and OZ554ALN is powered only in - * S0. For clamshell devices, different interrupt & power control scheme may be - * needed. - */ - -/* This ordering is suggested by vendor. */ -static struct oz554_value oz554_conf[] = { - /* - * Reigster 0x01: Operation frequency control - * Frequency selection: 300(KHz) - * Short circuit protection: 8(V) - */ - {.offset = 1, .data = 0x43}, - /* - * Reigster 0x02: LED current amplitude control - * ISET Resistor: 10.2(Kohm) - * Maximum LED current: 1636/10.2 = 160.4(mA) - * Setting LED current: 65(mA) - */ - {.offset = 2, .data = 0x65}, - /* - * Reigster 0x03: LED backlight Status - * Status function: Read only - */ - {.offset = 3, .data = 0x00}, - /* - * Reigster 0x04: LED current control with SMBus - * SMBus PWM function: None Use - */ - {.offset = 4, .data = 0x00}, - /* - * Reigster 0x05: OVP, OCP control - * Over Current Protection: 0.5(V) - * Panel LED Voltage(Max): 47.8(V) - * OVP setting: 54(V) - */ - {.offset = 5, .data = 0x97}, - /* - * Reigster 0x00: Dimming mode and string ON/OFF control - * String Selection: 4(Number) - * Interface Selection: 1 - * Brightness mode: 3 - */ - {.offset = 0, .data = 0xF2}, -}; -static const int oz554_conf_size = ARRAY_SIZE(oz554_conf); - -static void set_oz554_reg(void) -{ - int i; - - for (i = 0; i < oz554_conf_size; ++i) { - int rv = i2c_write8(I2C_PORT_BACKLIGHT, - I2C_ADDR_OZ554_FLAGS, - oz554_conf[i].offset, oz554_conf[i].data); - if (rv) { - CPRINTS("Write OZ554 register %d failed rv=%d" , i, rv); - return; - } - } - CPRINTS("Wrote OZ554 settings"); -} - -static void backlight_enable_deferred(void) -{ - if (gpio_get_level(GPIO_PANEL_BACKLIGHT_EN)) - set_oz554_reg(); -} -DECLARE_DEFERRED(backlight_enable_deferred); - -void backlight_enable_interrupt(enum gpio_signal signal) -{ - /* - * 1. Spec says backlight should be turned on after 500ms - * after eDP signals are ready. - * - * 2. There's no way to get exact eDP ready time, therefore, - * give one second delay. - * - * power up __/---------------- - * eDP ______/------------ - * backlight _____________/----- - * |- t1 -| : >=500 ms - * |- t2 -| : 1 second is enough - */ - hook_call_deferred(&backlight_enable_deferred_data, - OZ554_POWER_BACKLIGHT_DELAY); -} - -int oz554_set_config(int offset, int data) -{ - int i; - for (i = 0; i < oz554_conf_size; i++) { - if (oz554_conf[i].offset == offset) - break; - } - if (i >= oz554_conf_size) { - /* Matching offset not found */ - CPRINTS("oz554: offset %d not found", i); - return EC_ERROR_INVAL; - } - oz554_conf[i].data = data; - return EC_SUCCESS; -} - -static void init_oz554(void) -{ - oz554_board_init(); - - gpio_enable_interrupt(GPIO_PANEL_BACKLIGHT_EN); -} -DECLARE_HOOK(HOOK_INIT, init_oz554, HOOK_PRIO_DEFAULT); - - -__overridable void oz554_board_init(void) -{ -} diff --git a/driver/led/oz554.h b/driver/led/oz554.h deleted file mode 100644 index d1d9d9656e..0000000000 --- a/driver/led/oz554.h +++ /dev/null @@ -1,35 +0,0 @@ -/* Copyright 2018 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. - * - * O2 Micro OZ554 LED driver. - */ - -#ifndef __CROS_EC_OZ554_H -#define __CROS_EC_OZ554_H - -#include "gpio.h" -#include "common.h" - -/* - * Overridable board initialization. Should be overridden by a board - * specific function if the default is not appropriate - */ -__override_proto void oz554_board_init(void); - -/** - * Update oz554 configuration array (oz554_conf). - * - * @param offset: Offset of the register to be set. - * @param data: Value to be set. - * @return EC_SUCCESS or EC_ERROR_* for errors. - */ -int oz554_set_config(int offset, int data); - -#ifndef OZ554_POWER_BACKLIGHT_DELAY -#define OZ554_POWER_BACKLIGHT_DELAY SECOND -#endif - -void backlight_enable_interrupt(enum gpio_signal signal); - -#endif diff --git a/driver/ln9310.c b/driver/ln9310.c deleted file mode 100644 index 3464cf46a2..0000000000 --- a/driver/ln9310.c +++ /dev/null @@ -1,573 +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. - * - * LION Semiconductor LN-9310 switched capacitor converter. - */ - -#include "common.h" -#include "console.h" -#include "driver/ln9310.h" -#include "hooks.h" -#include "i2c.h" -#include "util.h" -#include "timer.h" - -#define CPUTS(outstr) cputs(CC_I2C, outstr) -#define CPRINTF(format, args...) cprintf(CC_I2C, format, ## args) -#define CPRINTS(format, args...) cprints(CC_I2C, format, ## args) - -static int power_good; -static int startup_workaround_required; - -int ln9310_power_good(void) -{ - return power_good; -} - -static inline int raw_read8(int offset, int *value) -{ - return i2c_read8(ln9310_config.i2c_port, - ln9310_config.i2c_addr_flags, - offset, - value); -} - -static inline int field_update8(int offset, int mask, int value) -{ - /* Clear mask and then set value in i2c reg value */ - return i2c_field_update8(ln9310_config.i2c_port, - ln9310_config.i2c_addr_flags, - offset, - mask, - value); -} - -static void ln9310_irq_deferred(void) -{ - int status, val, pg_2to1, pg_3to1; - - status = raw_read8(LN9310_REG_INT1, &val); - if (status) { - CPRINTS("LN9310 reading INT1 failed"); - return; - } - - CPRINTS("LN9310 received interrupt: 0x%x", val); - /* Don't care other interrupts except mode change */ - if (!(val & LN9310_INT1_MODE)) - return; - - /* Check if the device is active in 2:1 or 3:1 switching mode */ - status = raw_read8(LN9310_REG_SYS_STS, &val); - if (status) { - CPRINTS("LN9310 reading SYS_STS failed"); - return; - } - CPRINTS("LN9310 system status: 0x%x", val); - - /* Either 2:1 or 3:1 mode active is treated as PGOOD */ - pg_2to1 = !!(val & LN9310_SYS_SWITCHING21_ACTIVE); - pg_3to1 = !!(val & LN9310_SYS_SWITCHING31_ACTIVE); - power_good = pg_2to1 || pg_3to1; -} -DECLARE_DEFERRED(ln9310_irq_deferred); - -void ln9310_interrupt(enum gpio_signal signal) -{ - hook_call_deferred(&ln9310_irq_deferred_data, 0); -} - -static int is_battery_gt_10v(bool *out) -{ - int status, val; - - CPRINTS("LN9310 checking input voltage, threshold=10V"); - /* - * Turn on INFET_OUT_SWITCH_OK comparator; - * configure INFET_OUT_SWITCH_OK to 10V. - */ - status = field_update8(LN9310_REG_TRACK_CTRL, - LN9310_TRACK_INFET_OUT_SWITCH_OK_EN_MASK | - LN9310_TRACK_INFET_OUT_SWITCH_OK_CFG_MASK, - LN9310_TRACK_INFET_OUT_SWITCH_OK_EN_ON | - LN9310_TRACK_INFET_OUT_SWITCH_OK_CFG_10V); - if (status != EC_SUCCESS) - return status; - - /* Read INFET_OUT_SWITCH_OK comparator */ - status = raw_read8(LN9310_REG_BC_STS_B, &val); - if (status != EC_SUCCESS) { - CPRINTS("LN9310 reading BC_STS_B failed"); - return status; - } - CPRINTS("LN9310 BC_STS_B: 0x%x", val); - - /* - * If INFET_OUT_SWITCH_OK=0, VIN < 10V - * If INFET_OUT_SWITCH_OK=1, VIN > 10V - */ - *out = !!(val & LN9310_BC_STS_B_INFET_OUT_SWITCH_OK); - CPRINTS("LN9310 battery %s 10V", (*out) ? ">" : "<"); - - /* Turn off INFET_OUT_SWITCH_OK comparator */ - status = field_update8(LN9310_REG_TRACK_CTRL, - LN9310_TRACK_INFET_OUT_SWITCH_OK_EN_MASK, - LN9310_TRACK_INFET_OUT_SWITCH_OK_EN_OFF); - - return status; -} - -static int ln9310_reset_detected(void) -{ - /* - * Check LN9310_REG_LION_CTRL to see if it has been reset to 0x0. - * ln9310_init() and all other functions will set this register - * to a non-zero value so it should only become 0 again if LN9310 - * is reset. - */ - int val, status, reset_detected; - - status = raw_read8(LN9310_REG_LION_CTRL, &val); - if (status) { - CPRINTS("LN9310 reading LN9310_REG_LION_CTRL failed"); - /* If read fails, safest to assume reset has occurred */ - return 1; - } - reset_detected = (val == 0x0); - if (reset_detected) { - CPRINTS("LN9310 was reset (possibly in error)"); - } - return reset_detected; -} - -static int ln9310_update_startup_seq(void) -{ - int rc; - - CPRINTS("LN9310 update startup sequence"); - - /* - * Startup sequence instruction swap to hold Cfly - * bottom plate low during startup - */ - rc = field_update8(LN9310_REG_LION_CTRL, LN9310_LION_CTRL_MASK, - LN9310_LION_CTRL_UNLOCK_AND_EN_TM); - - rc |= field_update8(LN9310_REG_SWAP_CTRL_0, 0xff, 0x52); - - rc |= field_update8(LN9310_REG_SWAP_CTRL_1, 0xff, 0x54); - - rc |= field_update8(LN9310_REG_SWAP_CTRL_2, 0xff, 0xCC); - - rc |= field_update8(LN9310_REG_SWAP_CTRL_3, 0xff, 0x02); - - /* Startup sequence settings */ - rc |= field_update8( - LN9310_REG_CFG_4, - LN9310_CFG_4_SC_OUT_PRECHARGE_EN_TIME_CFG_MASK | - LN9310_CFG_4_SW1_VGS_SHORT_EN_MSK_MASK | - LN9310_CFG_4_BSTH_BSTL_HIGH_ROUT_CFG_MASK, - LN9310_CFG_4_SC_OUT_PRECHARGE_EN_TIME_CFG_ON | - LN9310_CFG_4_SW1_VGS_SHORT_EN_MSK_OFF | - LN9310_CFG_4_BSTH_BSTL_HIGH_ROUT_CFG_LOWEST); - - /* SW4 before BSTH_BSTL */ - rc |= field_update8(LN9310_REG_SPARE_0, - LN9310_SPARE_0_SW4_BEFORE_BSTH_BSTL_EN_CFG_MASK, - LN9310_SPARE_0_SW4_BEFORE_BSTH_BSTL_EN_CFG_ON); - - rc |= field_update8(LN9310_REG_LION_CTRL, LN9310_LION_CTRL_MASK, - LN9310_LION_CTRL_LOCK); - - return rc == EC_SUCCESS ? EC_SUCCESS : EC_ERROR_UNKNOWN; -} - -static int ln9310_init_3to1(void) -{ - int rc; - - CPRINTS("LN9310 init (3:1 operation)"); - - /* Enable track protection and SC_OUT configs for 3:1 switching */ - rc = field_update8(LN9310_REG_MODE_CHANGE_CFG, - LN9310_MODE_TM_TRACK_MASK | - LN9310_MODE_TM_SC_OUT_PRECHG_MASK | - LN9310_MODE_TM_VIN_OV_CFG_MASK, - LN9310_MODE_TM_TRACK_SWITCH31 | - LN9310_MODE_TM_SC_OUT_PRECHG_SWITCH31 | - LN9310_MODE_TM_VIN_OV_CFG_3S); - - /* Enable 3:1 operation mode */ - rc |= field_update8(LN9310_REG_PWR_CTRL, LN9310_PWR_OP_MODE_MASK, - LN9310_PWR_OP_MODE_SWITCH31); - - /* 3S lower bound delta configurations */ - rc |= field_update8(LN9310_REG_LB_CTRL, LN9310_LB_DELTA_MASK, - LN9310_LB_DELTA_3S); - - /* - * TODO(waihong): The LN9310_REG_SYS_CTR was set to a wrong value - * accidentally. Override it to 0. This may not need. - */ - rc |= field_update8(LN9310_REG_SYS_CTRL, 0xff, 0); - - return rc == EC_SUCCESS ? EC_SUCCESS : EC_ERROR_UNKNOWN; -} - -static int ln9310_init_2to1(void) -{ - int rc; - bool battery_gt_10v; - - CPRINTS("LN9310 init (2:1 operation)"); - - rc = is_battery_gt_10v(&battery_gt_10v); - if (rc != EC_SUCCESS || battery_gt_10v) { - CPRINTS("LN9310 init stop. Input voltage is too high."); - return EC_ERROR_UNKNOWN; - } - - /* Enable track protection and SC_OUT configs for 2:1 switching */ - rc = field_update8(LN9310_REG_MODE_CHANGE_CFG, - LN9310_MODE_TM_TRACK_MASK | - LN9310_MODE_TM_SC_OUT_PRECHG_MASK, - LN9310_MODE_TM_TRACK_SWITCH21 | - LN9310_MODE_TM_SC_OUT_PRECHG_SWITCH21); - - /* Enable 2:1 operation mode */ - rc |= field_update8(LN9310_REG_PWR_CTRL, LN9310_PWR_OP_MODE_MASK, - LN9310_PWR_OP_MODE_SWITCH21); - - /* 2S lower bound delta configurations */ - rc |= field_update8(LN9310_REG_LB_CTRL, LN9310_LB_DELTA_MASK, - LN9310_LB_DELTA_2S); - - /* - * TODO(waihong): The LN9310_REG_SYS_CTR was set to a wrong value - * accidentally. Override it to 0. This may not need. - */ - rc |= field_update8(LN9310_REG_SYS_CTRL, 0xff, 0); - - return rc == EC_SUCCESS ? EC_SUCCESS : EC_ERROR_UNKNOWN; -} - -static int ln9310_update_infet(void) -{ - int rc; - - CPRINTS("LN9310 update infet configuration"); - - rc = field_update8(LN9310_REG_LION_CTRL, LN9310_LION_CTRL_MASK, - LN9310_LION_CTRL_UNLOCK_AND_EN_TM); - - /* Update Infet register settings */ - rc |= field_update8(LN9310_REG_CFG_5, LN9310_CFG_5_INGATE_PD_EN_MASK, - LN9310_CFG_5_INGATE_PD_EN_OFF); - - rc |= field_update8(LN9310_REG_CFG_5, - LN9310_CFG_5_INFET_CP_PD_BIAS_CFG_MASK, - LN9310_CFG_5_INFET_CP_PD_BIAS_CFG_LOWEST); - - /* enable automatic infet control */ - rc |= field_update8(LN9310_REG_PWR_CTRL, LN9310_PWR_INFET_AUTO_MODE_MASK, - LN9310_PWR_INFET_AUTO_MODE_ON); - - /* disable LS_HELPER during IDLE by setting MSK bit high */ - rc |= field_update8(LN9310_REG_CFG_0, - LN9310_CFG_0_LS_HELPER_IDLE_MSK_MASK, - LN9310_CFG_0_LS_HELPER_IDLE_MSK_ON); - - rc |= field_update8(LN9310_REG_LION_CTRL, LN9310_LION_CTRL_MASK, - LN9310_LION_CTRL_LOCK); - - return rc == EC_SUCCESS ? EC_SUCCESS : EC_ERROR_UNKNOWN; -} - -static int ln9310_precharge_cfly(uint64_t *precharge_timeout) -{ - int status = 0; - CPRINTS("LN9310 precharge cfly"); - - /* Unlock registers and enable test mode */ - status |= field_update8(LN9310_REG_LION_CTRL, - LN9310_LION_CTRL_MASK, - LN9310_LION_CTRL_UNLOCK_AND_EN_TM); - - /* disable test mode overrides */ - status |= field_update8(LN9310_REG_FORCE_SC21_CTRL_2, - LN9310_FORCE_SC21_CTRL_2_FORCE_SW_CTRL_REQ_MASK, - LN9310_FORCE_SC21_CTRL_2_FORCE_SW_CTRL_REQ_OFF); - - /* Configure test mode target values for precharge ckts. */ - status |= field_update8(LN9310_REG_FORCE_SC21_CTRL_1, - LN9310_FORCE_SC21_CTRL_1_TM_SC_OUT_CFLY_PRECHARGE_MASK, - LN9310_FORCE_SC21_CTRL_1_TM_SC_OUT_CFLY_PRECHARGE_ON); - - /* Force SCOUT precharge/predischarge overrides */ - status |= field_update8(LN9310_REG_TEST_MODE_CTRL, - LN9310_TEST_MODE_CTRL_FORCE_SC_OUT_PRECHARGE_MASK | - LN9310_TEST_MODE_CTRL_FORCE_SC_OUT_PREDISCHARGE_MASK, - LN9310_TEST_MODE_CTRL_FORCE_SC_OUT_PRECHARGE_ON | - LN9310_TEST_MODE_CTRL_FORCE_SC_OUT_PREDISCHARGE_ON); - - /* Force enable CFLY precharge overrides */ - status |= field_update8(LN9310_REG_FORCE_SC21_CTRL_2, - LN9310_FORCE_SC21_CTRL_2_FORCE_SW_CTRL_REQ_MASK, - LN9310_FORCE_SC21_CTRL_2_FORCE_SW_CTRL_REQ_ON); - - /* delay long enough to ensure CFLY has time to fully precharge */ - usleep(LN9310_CFLY_PRECHARGE_DELAY); - - /* locking and leaving test mode will stop CFLY precharge */ - *precharge_timeout = get_time().val + LN9310_CFLY_PRECHARGE_TIMEOUT; - status |= field_update8(LN9310_REG_LION_CTRL, - LN9310_LION_CTRL_MASK, - LN9310_LION_CTRL_LOCK); - - return status; -} - -static int ln9310_precharge_cfly_reset(void) -{ - int status = 0; - CPRINTS("LN9310 precharge cfly reset"); - - /* set known initial state for config bits related to cfly precharge */ - status |= field_update8(LN9310_REG_LION_CTRL, - LN9310_LION_CTRL_MASK, - LN9310_LION_CTRL_UNLOCK); - - /* Force off SCOUT precharge/predischarge overrides */ - status |= field_update8(LN9310_REG_TEST_MODE_CTRL, - LN9310_TEST_MODE_CTRL_FORCE_SC_OUT_PRECHARGE_MASK | - LN9310_TEST_MODE_CTRL_FORCE_SC_OUT_PREDISCHARGE_MASK, - LN9310_TEST_MODE_CTRL_FORCE_SC_OUT_PRECHARGE_OFF | - LN9310_TEST_MODE_CTRL_FORCE_SC_OUT_PREDISCHARGE_OFF); - - /* disable test mode overrides */ - status |= field_update8(LN9310_REG_FORCE_SC21_CTRL_2, - LN9310_FORCE_SC21_CTRL_2_FORCE_SW_CTRL_REQ_MASK, - LN9310_FORCE_SC21_CTRL_2_FORCE_SW_CTRL_REQ_OFF); - - /* disable CFLY and SC_OUT precharge control */ - status |= field_update8(LN9310_REG_FORCE_SC21_CTRL_1, - LN9310_FORCE_SC21_CTRL_1_TM_SC_OUT_CFLY_PRECHARGE_MASK, - LN9310_FORCE_SC21_CTRL_1_TM_SC_OUT_CFLY_PRECHARGE_OFF); - - status |= field_update8(LN9310_REG_LION_CTRL, - LN9310_LION_CTRL_MASK, - LN9310_LION_CTRL_LOCK); - - return status; -} - -int ln9310_init(void) -{ - int status, val, chip_revision; - enum battery_cell_type batt; - - /* Make sure initial state of LN9310 is STANDBY (i.e. output is off) */ - field_update8(LN9310_REG_STARTUP_CTRL, - LN9310_STARTUP_STANDBY_EN, - 1); - - /* - * LN9310 software startup is only required for earlier silicon revs. - * LN9310 hardware revisions after LN9310_BC_STS_C_CHIP_REV_FIXED - * should not use the software startup sequence. - */ - status = raw_read8(LN9310_REG_BC_STS_C, &val); - if (status != EC_SUCCESS) { - CPRINTS("LN9310 reading BC_STS_C failed: %d", status); - return status; - } - chip_revision = val & LN9310_BC_STS_C_CHIP_REV_MASK; - startup_workaround_required = chip_revision < LN9310_BC_STS_C_CHIP_REV_FIXED; - - /* Update INFET configuration */ - status = ln9310_update_infet(); - - if (status != EC_SUCCESS) - return status; - - /* - * Set OPERATION_MODE update method - * - OP_MODE_MANUAL_UPDATE = 0 - * - OP_MODE_SELF_SYNC_EN = 1 - */ - field_update8(LN9310_REG_PWR_CTRL, - LN9310_PWR_OP_MODE_MANUAL_UPDATE_MASK, - LN9310_PWR_OP_MODE_MANUAL_UPDATE_OFF); - - field_update8(LN9310_REG_TIMER_CTRL, - LN9310_TIMER_OP_SELF_SYNC_EN_MASK, - LN9310_TIMER_OP_SELF_SYNC_EN_ON); - - /* - * Use VIN for VDR, not EXT_5V. The following usleep will give - * circuit time to settle. - */ - field_update8(LN9310_REG_STARTUP_CTRL, - LN9310_STARTUP_SELECT_EXT_5V_FOR_VDR, - 0); - - field_update8(LN9310_REG_LB_CTRL, - LN9310_LB_MIN_FREQ_EN, - LN9310_LB_MIN_FREQ_EN); - - /* Set minimum switching frequency to 25 kHz */ - field_update8(LN9310_REG_SPARE_0, - LN9310_SPARE_0_LB_MIN_FREQ_SEL_MASK, - LN9310_SPARE_0_LB_MIN_FREQ_SEL_ON); - - usleep(LN9310_CDC_DELAY); - CPRINTS("LN9310 OP_MODE Update method: Self-sync"); - - if (startup_workaround_required) { - /* Update Startup sequence */ - status = ln9310_update_startup_seq(); - if (status != EC_SUCCESS) - return status; - } - - batt = board_get_battery_cell_type(); - if (batt == BATTERY_CELL_TYPE_3S) { - status = ln9310_init_3to1(); - } else if (batt == BATTERY_CELL_TYPE_2S) { - status = ln9310_init_2to1(); - } else { - CPRINTS("LN9310 not supported battery type: %d", batt); - return EC_ERROR_INVAL; - } - - if (status != EC_SUCCESS) - return status; - - /* Unmask the MODE change interrupt */ - field_update8(LN9310_REG_INT1_MSK, - LN9310_INT1_MODE, - 0); - return EC_SUCCESS; -} - -void ln9310_software_enable(int enable) -{ - int status, val, retry_count; - uint64_t precharge_timeout; - bool ln9310_init_completed = false; - - /* - * LN9310 startup requires (nEN=0 AND STANDBY_EN=0) where nEN is a pin - * and STANDBY_EN is a register bit. Previous EC firmware set - * STANDBY_EN=1 in ln9310_init and toggled nEN to startup/shutdown. This - * function implements an alternate software (i.e. controlled by EC - * through I2C commands) startup sequence so one option is to set nEN=1 - * and just used ln9310_software_enable to startup/shutdown. - * ln9310_software_enable can also be used in conjunction w/ the nEN pin - * (in case nEN pin is desired as visible signal ) as follows: - * - * Initial battery insertion: - * nEN=1 - * ln9310_init() - initial condition is STANDBY_EN=1 - * - * Power up LN9310: - * nEN=0 - STANDBY_EN should be 1 so this doesn't trigger startup - * ln9310_software_enable(1) - triggers alternate software-based startup - * - * Power down LN9310: - * nEN=1 - shutdown LN9310 (shutdown seq. does not require modification) - * ln9310_software_enable(0) - reset LN9310 register to state necessary - * for subsequent startups - */ - if (ln9310_reset_detected()) - ln9310_init(); - - /* Dummy clear all interrupts */ - status = raw_read8(LN9310_REG_INT1, &val); - if (status) { - CPRINTS("LN9310 reading INT1 failed"); - return; - } - CPRINTS("LN9310 cleared interrupts: 0x%x", val); - - if (startup_workaround_required) { - if (enable) { - /* - * Software modification of LN9310 startup sequence w/ retry - * loop. - * - * (1) Clear interrupts - * (2) Precharge Cfly w/ overrides of internal LN9310 signals - * (3) disable overrides -> stop precharging Cfly - * (4.1) if < 100 ms elapsed since (2) -> trigger LN9310 internal - * startup seq. - * (4.2) else -> abort and optionally retry from step 2 - */ - retry_count = 0; - while (!ln9310_init_completed && retry_count < LN9310_INIT_RETRY_COUNT) { - /* Precharge CFLY before starting up */ - status = ln9310_precharge_cfly(&precharge_timeout); - if (status != EC_SUCCESS) { - CPRINTS("LN9310 failed to run Cfly precharge sequence"); - status = ln9310_precharge_cfly_reset(); - retry_count++; - continue; - } - - /* - * Only start the SC if the cfly precharge - * hasn't timed out (i.e. ended too long ago) - */ - if (get_time().val < precharge_timeout) { - /* Clear the STANDBY_EN bit to enable the SC */ - field_update8(LN9310_REG_STARTUP_CTRL, - LN9310_STARTUP_STANDBY_EN, - 0); - if (get_time().val > precharge_timeout ) { - /* - * if timed out during previous I2C command, abort - * startup attempt - */ - field_update8(LN9310_REG_STARTUP_CTRL, - LN9310_STARTUP_STANDBY_EN, - 1); - } else { - /* all other paths should reattempt startup */ - ln9310_init_completed = true; - } - } - /* Reset to known state for config bits related to cfly precharge */ - ln9310_precharge_cfly_reset(); - retry_count++; - } - - if (!ln9310_init_completed) { - CPRINTS("LN9310 failed to start after %d retry attempts", - retry_count); - } - } else { - /* - * Internal LN9310 shutdown sequence is ok as is, so just reset - * the state to prepare for subsequent startup sequences. - * - * (1) set STANDBY_EN=1 to be sure the part turns off even if nEN=0 - * (2) reset cfly precharge related registers to known initial state - */ - field_update8(LN9310_REG_STARTUP_CTRL, - LN9310_STARTUP_STANDBY_EN, - 1); - - ln9310_precharge_cfly_reset(); - } - } else { - /* - * for newer LN9310 revsisions, the startup workaround is not required - * so the STANDBY_EN bit can just be set directly - */ - field_update8(LN9310_REG_STARTUP_CTRL, - LN9310_STARTUP_STANDBY_EN, - !enable); - } - return; -}
\ No newline at end of file diff --git a/driver/mag_bmm150.c b/driver/mag_bmm150.c deleted file mode 100644 index ad1eba7ad0..0000000000 --- a/driver/mag_bmm150.c +++ /dev/null @@ -1,268 +0,0 @@ -/* 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. - */ - -/** - * BMM150 compass behind a BMI160 - */ - -#include "accelgyro.h" -#include "common.h" -#include "console.h" -#include "driver/mag_bmm150.h" -#include "hooks.h" -#include "i2c.h" -#include "task.h" -#include "timer.h" -#include "util.h" - -#ifdef CONFIG_MAG_BMI_BMM150 -#include "driver/accelgyro_bmi_common.h" -#define raw_mag_read8 bmi160_sec_raw_read8 -#define raw_mag_write8 bmi160_sec_raw_write8 -#else -#error "Not implemented" -#endif - - -#define CPUTS(outstr) cputs(CC_ACCEL, outstr) -#define CPRINTF(format, args...) cprintf(CC_ACCEL, format, ## args) -#define CPRINTS(format, args...) cprints(CC_ACCEL, format, ## args) - - -/**************************************************************************** -* Copyright (C) 2011 - 2014 Bosch Sensortec GmbH -* -****************************************************************************/ -/*************************************************************************** -* License: -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* -* Neither the name of the copyright holder nor the names of the -* contributors may be used to endorse or promote products derived from -* this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE -* -* The information provided is believed to be accurate and reliable. -* The copyright holder assumes no responsibility for the consequences of use -* of such information nor for any infringement of patents or -* other rights of third parties which may result from its use. -* No license is granted by implication or otherwise under any patent or -* patent rights of the copyright holder. -*/ - -#define BMI150_READ_16BIT_COM_REG(store_, addr_) do { \ - int val; \ - raw_mag_read8(s->port, s->i2c_spi_addr_flags, (addr_), &val); \ - store_ = val; \ - raw_mag_read8(s->port, s->i2c_spi_addr_flags, (addr_) + 1, &val); \ - store_ |= (val << 8); \ -} while (0) - - -int bmm150_init(struct motion_sensor_t *s) -{ - int ret; - int val; - struct bmm150_comp_registers *regs = BMM150_COMP_REG(s); - struct mag_cal_t *moc = BMM150_CAL(s); - - /* Set the compass from Suspend to Sleep */ - ret = raw_mag_write8(s->port, s->i2c_spi_addr_flags, - BMM150_PWR_CTRL, BMM150_PWR_ON); - msleep(4); - /* Now we can read the device id */ - ret = raw_mag_read8(s->port, s->i2c_spi_addr_flags, - BMM150_CHIP_ID, &val); - if (ret) - return EC_ERROR_UNKNOWN; - - if (val != BMM150_CHIP_ID_MAJOR) - return EC_ERROR_ACCESS_DENIED; - - /* Read the private registers for compensation */ - ret = raw_mag_read8(s->port, s->i2c_spi_addr_flags, - BMM150_REGA_DIG_X1, &val); - if (ret) - return EC_ERROR_UNKNOWN; - regs->dig1[X] = val; - raw_mag_read8(s->port, s->i2c_spi_addr_flags, - BMM150_REGA_DIG_Y1, &val); - regs->dig1[Y] = val; - raw_mag_read8(s->port, s->i2c_spi_addr_flags, - BMM150_REGA_DIG_X2, &val); - regs->dig2[X] = val; - raw_mag_read8(s->port, s->i2c_spi_addr_flags, - BMM150_REGA_DIG_Y2, &val); - regs->dig2[Y] = val; - - raw_mag_read8(s->port, s->i2c_spi_addr_flags, - BMM150_REGA_DIG_XY1, &val); - regs->dig_xy1 = val; - - raw_mag_read8(s->port, s->i2c_spi_addr_flags, - BMM150_REGA_DIG_XY2, &val); - regs->dig_xy2 = val; - - BMI150_READ_16BIT_COM_REG(regs->dig_z1, BMM150_REGA_DIG_Z1_LSB); - BMI150_READ_16BIT_COM_REG(regs->dig_z2, BMM150_REGA_DIG_Z2_LSB); - BMI150_READ_16BIT_COM_REG(regs->dig_z3, BMM150_REGA_DIG_Z3_LSB); - BMI150_READ_16BIT_COM_REG(regs->dig_z4, BMM150_REGA_DIG_Z4_LSB); - BMI150_READ_16BIT_COM_REG(regs->dig_xyz1, BMM150_REGA_DIG_XYZ1_LSB); - - - /* Set the repetition in "Regular Preset" */ - raw_mag_write8(s->port, s->i2c_spi_addr_flags, - BMM150_REPXY, BMM150_REP(SPECIAL, XY)); - raw_mag_write8(s->port, s->i2c_spi_addr_flags, - BMM150_REPZ, BMM150_REP(SPECIAL, Z)); - ret = raw_mag_read8(s->port, s->i2c_spi_addr_flags, - BMM150_REPXY, &val); - ret = raw_mag_read8(s->port, s->i2c_spi_addr_flags, - BMM150_REPZ, &val); - /* - * Set the compass forced mode, to sleep after each measure. - */ - ret = raw_mag_write8(s->port, s->i2c_spi_addr_flags, - BMM150_OP_CTRL, - BMM150_OP_MODE_FORCED << BMM150_OP_MODE_OFFSET); - - init_mag_cal(moc); - moc->radius = 0.0f; - return ret; -} - -void bmm150_temp_compensate_xy(const struct motion_sensor_t *s, - intv3_t raw, - intv3_t comp, - int r) -{ - int inter, axis; - struct bmm150_comp_registers *regs = BMM150_COMP_REG(s); - if (r == 0) - inter = 0; - else - inter = ((int)regs->dig_xyz1 << 14) / r - BIT(14); - - for (axis = X; axis <= Y; axis++) { - if (raw[axis] == BMM150_FLIP_OVERFLOW_ADCVAL) { - comp[axis] = BMM150_OVERFLOW_OUTPUT; - continue; - } - /* - * The formula is, using 4 LSB for precision: - * (mdata_x * ((((dig_xy2 * i^2 / 268435456) + - * i * dig_xy1) / 16384) + 256) * - * (dig2 + 160)) / 8192 + dig1 * 8.0f - * To prevent precision loss, we calculate at << 12: - * 1 / 268435456 = 1 >> 28 = 1 >> (7 + 9 + 12) - * 1 / 16384 = 1 >> (-7 + 9 + 12) - * 256 = 1 << (20 - 12) - */ - comp[axis] = (int)regs->dig_xy2 * ((inter * inter) >> 7); - comp[axis] += inter * ((int)regs->dig_xy1 << 7); - comp[axis] >>= 9; - comp[axis] += 1 << (8 + 12); - comp[axis] *= (int)regs->dig2[axis] + 160; - comp[axis] >>= 12; - comp[axis] *= raw[axis]; - comp[axis] >>= 13; - comp[axis] += (int)regs->dig1[axis] << 3; - } -} - -void bmm150_temp_compensate_z(const struct motion_sensor_t *s, - intv3_t raw, - intv3_t comp, - int r) -{ - int dividend, divisor; - struct bmm150_comp_registers *regs = BMM150_COMP_REG(s); - - if (raw[Z] == BMM150_HALL_OVERFLOW_ADCVAL) { - comp[Z] = BMM150_OVERFLOW_OUTPUT; - return; - } - /* - * The formula is - * ((z - dig_z4) * 131072 - dig_z3 * (r - dig_xyz1)) / - * ((dig_z2 + dig_z1 * r / 32768) * 4); - * - * We spread 4 so we multiply by 131072 / 4 == BIT(15) only. - */ - dividend = (raw[Z] - (int)regs->dig_z4) << 15; - dividend -= (regs->dig_z3 * (r - (int)regs->dig_xyz1)) >> 2; - /* add BIT(15) to round to next integer. */ - divisor = (int)regs->dig_z1 * (r << 1) + BIT(15); - divisor >>= 16; - divisor += (int)regs->dig_z2; - comp[Z] = dividend / divisor; - if (comp[Z] > BIT(15) || comp[Z] < -(BIT(15))) - comp[Z] = BMM150_OVERFLOW_OUTPUT; -} - -void bmm150_normalize(const struct motion_sensor_t *s, - intv3_t v, - uint8_t *data) -{ - uint16_t r; - intv3_t raw; - struct mag_cal_t *cal = BMM150_CAL(s); - - /* X and Y are two's complement 13 bits vectors */ - raw[X] = ((int16_t)(data[0] | (data[1] << 8))) >> 3; - raw[Y] = ((int16_t)(data[2] | (data[3] << 8))) >> 3; - /* Z are two's complement 15 bits vectors */ - raw[Z] = ((int16_t)(data[4] | (data[5] << 8))) >> 1; - - /* RHALL value to compensate with - unsigned 14 bits */ - r = (data[6] | (data[7] << 8)) >> 2; - - bmm150_temp_compensate_xy(s, raw, v, r); - bmm150_temp_compensate_z(s, raw, v, r); - mag_cal_update(cal, v); - - v[X] += cal->bias[X]; - v[Y] += cal->bias[Y]; - v[Z] += cal->bias[Z]; -} - -int bmm150_set_offset(const struct motion_sensor_t *s, - const intv3_t offset) -{ - struct mag_cal_t *cal = BMM150_CAL(s); - cal->bias[X] = offset[X]; - cal->bias[Y] = offset[Y]; - cal->bias[Z] = offset[Z]; - return EC_SUCCESS; -} - -int bmm150_get_offset(const struct motion_sensor_t *s, - intv3_t offset) -{ - struct mag_cal_t *cal = BMM150_CAL(s); - offset[X] = cal->bias[X]; - offset[Y] = cal->bias[Y]; - offset[Z] = cal->bias[Z]; - return EC_SUCCESS; -} diff --git a/driver/mcdp28x0.c b/driver/mcdp28x0.c deleted file mode 100644 index bf44a6eaf8..0000000000 --- a/driver/mcdp28x0.c +++ /dev/null @@ -1,314 +0,0 @@ -/* Copyright 2014 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. - * - * Megachips DisplayPort to HDMI protocol converter / level shifter driver. - */ - -#include "config.h" -#include "console.h" -#include "common.h" -#include "ec_commands.h" -#include "mcdp28x0.h" -#include "queue.h" -#include "queue_policies.h" -#include "timer.h" -#include "usart-stm32f0.h" -#include "util.h" - -#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) - -static uint8_t mcdp_inbuf[MCDP_INBUF_MAX]; - -#undef MCDP_DEBUG - -#ifdef MCDP_DEBUG -static inline void print_buffer(uint8_t *buf, int cnt) -{ - int i; - CPRINTF("buf:"); - for (i = 0; i < cnt; i++) { - if (i && !(i % 4)) - CPRINTF("\n "); - CPRINTF("[%02d]0x%02x ", i, buf[i]); - } - CPRINTF("\n"); -} -#else -static inline void print_buffer(uint8_t *buf, int cnt) {} -#endif - -static struct usart_config const usart_mcdp; - -struct queue const usart_mcdp_rx_queue = QUEUE_DIRECT(MCDP_INBUF_MAX, - uint8_t, - usart_mcdp.producer, - null_consumer); -struct queue const usart_mcdp_tx_queue = QUEUE_DIRECT(MCDP_OUTBUF_MAX, - uint8_t, - null_producer, - usart_mcdp.consumer); - -static struct usart_config const usart_mcdp = USART_CONFIG(CONFIG_MCDP28X0, - usart_rx_interrupt, - usart_tx_interrupt, - 115200, - 0, - usart_mcdp_rx_queue, - usart_mcdp_tx_queue); - -/** - * Compute checksum. - * - * @seed initial value of checksum. - * @msg message bytes to compute checksum on. - * @cnt count of message bytes. - * @return partial checksum. - */ -static uint8_t compute_checksum(uint8_t seed, const uint8_t *msg, int cnt) -{ - int i; - uint8_t chksum = seed; - - for (i = 0; i < cnt; i++) - chksum += msg[i]; - return ~chksum + 1; -} - -/** - * transmit message over serial - * - * Packet consists of: - * msg[0] == length of entire packet - * msg[1] == 1st message byte (typically command) - * msg[cnt+1] == last message byte - * msg[cnt+2] == checksum - * - * @msg message bytes - * @cnt count of message bytes - * @return zero if success, error code otherwise - */ -static int tx_serial(const uint8_t *msg, int cnt) -{ - uint8_t out = cnt + 2; - /* 1st byte (not in msg) is always cnt + 2, so seed chksum with that */ - uint8_t chksum = compute_checksum(cnt + 2, msg, cnt); - - if (queue_add_unit(&usart_mcdp_tx_queue, &out) != 1) - return MCDP_ERROR_TX_CNT; - - if (queue_add_units(&usart_mcdp_tx_queue, msg, cnt) != cnt) - return MCDP_ERROR_TX_BODY; - - print_buffer((uint8_t *)msg, cnt); - - if (queue_add_unit(&usart_mcdp_tx_queue, &chksum) != 1) - return MCDP_ERROR_TX_CHKSUM; - - return MCDP_SUCCESS; -} - -/** - * receive message over serial - * - * While definitive documentation is lacking its believed the following receive - * packet is always true. - * - * Packet consists of: - * msg[0] == length of entire packet - * msg[1] == 1st message byte (typically command) - * msg[cnt+2] == last message byte - * msg[cnt+3] == checksum - * - * @msg pointer to buffer to read message into - * @cnt count of message bytes - * @return zero if success, error code otherwise - */ -static int rx_serial(uint8_t *msg, int cnt) -{ - size_t read; - int retry = 2; - - read = queue_remove_units(&usart_mcdp_rx_queue, msg, cnt); - while ((read < cnt) && retry) { - usleep(100*MSEC); - read += queue_remove_units(&usart_mcdp_rx_queue, msg + read, - cnt - read); - retry--; - } - - print_buffer(msg, cnt); - - /* Some response sizes are dynamic so shrink cnt accordingly. */ - if (cnt > msg[0]) - cnt = msg[0]; - - if (msg[cnt-1] != compute_checksum(0, msg, cnt-1)) - return MCDP_ERROR_CHKSUM; - - if (read != cnt) { - CPRINTF("rx_serial: read bytes %d != %d cnt\n", read, cnt); - return MCDP_ERROR_RX_BYTES; - } - - return MCDP_SUCCESS; -} - -static int rx_serial_ack(void) -{ - int rv = rx_serial(mcdp_inbuf, 3); - if (rv) - return rv; - - if (mcdp_inbuf[1] != MCDP_CMD_ACK) - return MCDP_ERROR_RX_ACK; - - return rv; -} - -void mcdp_enable(void) -{ - usart_init(&usart_mcdp); -} - -void mcdp_disable(void) -{ - usart_shutdown(&usart_mcdp); -} - -int mcdp_get_info(struct mcdp_info *info) -{ - const uint8_t msg[2] = {MCDP_CMD_APPSTEST, 0x28}; - int rv = tx_serial(msg, sizeof(msg)); - - if (rv) - return rv; - - rv = rx_serial_ack(); - if (rv) - return rv; - - /* chksum is unreliable ... don't check */ - rx_serial(mcdp_inbuf, MCDP_RSP_LEN(MCDP_LEN_GETINFO)); - - memcpy(info, &mcdp_inbuf[2], MCDP_LEN_GETINFO); - - return rv; -} - -#ifdef CONFIG_CMD_MCDP -static int mcdp_get_dev_id(char *dev, uint8_t dev_id, int dev_cnt) -{ - uint8_t msg[2]; - int rv; - msg[0] = MCDP_CMD_GETDEVID; - msg[1] = dev_id; - - rv = tx_serial(msg, sizeof(msg)); - if (rv) - return rv; - - rv = rx_serial(mcdp_inbuf, sizeof(mcdp_inbuf)); - if (rv) - return rv; - - memcpy(dev, &mcdp_inbuf[2], mcdp_inbuf[0] - 3); - dev[mcdp_inbuf[0] - 3] = '\0'; - return EC_SUCCESS; -} - -static int mcdp_appstest(uint8_t cmd, int paramc, char **paramv) -{ - uint8_t msg[6]; - char *e; - int i; - int rv = MCDP_SUCCESS; - - /* setup any appstest params */ - msg[0] = MCDP_CMD_APPSTESTPARAM; - for (i = 0; i < paramc; i++) { - uint32_t param = strtoi(paramv[i], &e, 10); - if (*e) - return EC_ERROR_PARAM1; - msg[1] = i + 1; - msg[2] = (param >> 24) & 0xff; - msg[3] = (param >> 16) & 0xff; - msg[4] = (param >> 8) & 0xff; - msg[5] = (param >> 0) & 0xff; - rv = tx_serial(msg, sizeof(msg)); - if (rv) - return rv; - - rv = rx_serial_ack(); - if (rv) - return rv; - } - - msg[0] = MCDP_CMD_APPSTEST; - msg[1] = cmd; - rv = tx_serial(msg, 2); - if (rv) - return rv; - - rv = rx_serial_ack(); - if (rv) - return rv; - - /* magic */ - rx_serial(mcdp_inbuf, sizeof(mcdp_inbuf)); - rx_serial(mcdp_inbuf, sizeof(mcdp_inbuf)); - - return EC_SUCCESS; -} - -int command_mcdp(int argc, char **argv) -{ - int rv = EC_SUCCESS; - char *e; - - if (argc < 2) - return EC_ERROR_PARAM_COUNT; - - mcdp_enable(); - if (!strncasecmp(argv[1], "info", 4)) { - struct mcdp_info info; - rv = mcdp_get_info(&info); - if (!rv) - ccprintf("family:%04x chipid:%04x irom:%d.%d.%d " - "fw:%d.%d.%d\n", - MCDP_FAMILY(info.family), - MCDP_CHIPID(info.chipid), - info.irom.major, info.irom.minor, - info.irom.build, - info.fw.major, info.fw.minor, info.fw.build); - } else if (!strncasecmp(argv[1], "devid", 4)) { - uint8_t dev_id = strtoi(argv[2], &e, 10); - char dev[32]; - if (*e) - return EC_ERROR_PARAM2; - else - rv = mcdp_get_dev_id(dev, dev_id, 32); - if (!rv) - ccprintf("devid[%d] = %s\n", dev_id, dev); - } else if (!strncasecmp(argv[1], "appstest", 4)) { - uint8_t cmd = strtoi(argv[2], &e, 10); - if (*e) - return EC_ERROR_PARAM2; - else - rv = mcdp_appstest(cmd, argc - 3, &argv[3]); - if (!rv) - ccprintf("appstest[%d] completed\n", cmd); - } else { - return EC_ERROR_PARAM1; - } - - mcdp_disable(); - if (rv) - ccprintf("mcdp_error:%d\n", rv); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(mcdp, command_mcdp, - "info|devid <id>|appstest <cmd> [<params>]", - "USB PD"); -#endif /* CONFIG_CMD_MCDP */ diff --git a/driver/mcdp28x0.h b/driver/mcdp28x0.h deleted file mode 100644 index 4352a3899e..0000000000 --- a/driver/mcdp28x0.h +++ /dev/null @@ -1,53 +0,0 @@ -/* Copyright 2014 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. - * - * Megachips DisplayPort to HDMI protocol converter / level shifter driver. - */ - -#ifndef __CROS_EC_MCDP28X0_H -#define __CROS_EC_MCDP28X0_H - -#define MCDP_OUTBUF_MAX 16 -#define MCDP_INBUF_MAX 16 - -#define MCDP_CMD_GETINFO 0x40 -#define MCDP_CMD_GETDEVID 0x30 -#define MCDP_CMD_APPSTEST 0x12 -#define MCDP_CMD_APPSTESTPARAM 0x11 -#define MCDP_CMD_ACK 0x0c - -/* packet header (2 bytes: length + cmd) + data + footer (1byte: checksum) */ -#define MCDP_RSP_LEN(len) (len + 3) -#define MCDP_LEN_GETINFO 12 - -/* List of common error codes that can be returned */ -enum mcdp_error_list { - MCDP_SUCCESS = 0, - MCDP_ERROR_TX_CNT, - MCDP_ERROR_TX_BODY, - MCDP_ERROR_TX_CHKSUM, - MCDP_ERROR_CHKSUM, - MCDP_ERROR_RX_BYTES, - MCDP_ERROR_RX_ACK, -}; - -/** - * Enable mcdp driver. - */ -void mcdp_enable(void); - -/** - * Disable mcdp driver. - */ -void mcdp_disable(void); - -/** - * get get information command from mcdp. - * - * @info pointer to mcdp_info structure - * @return zero if success, error code otherwise. - */ -int mcdp_get_info(struct mcdp_info *info); - -#endif diff --git a/driver/mp2964.c b/driver/mp2964.c deleted file mode 100644 index 21a23a8f4c..0000000000 --- a/driver/mp2964.c +++ /dev/null @@ -1,152 +0,0 @@ -/* Copyright 2021 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. - */ - -/* Driver for tuning the MP2964 IMVP8 - IMVP9.1 parameters */ - -#include "console.h" -#include "i2c.h" -#include "mp2964.h" -#include "timer.h" -#include "util.h" - -#define MP2964_STARTUP_WAIT_US (50 * MSEC) -#define MP2964_STORE_WAIT_US (300 * MSEC) -#define MP2964_RESTORE_WAIT_US (2 * MSEC) - -enum reg_page { - REG_PAGE_0, - REG_PAGE_1, - REG_PAGE_COUNT -}; - -static int mp2964_write8(uint8_t reg, uint8_t value) -{ - const uint8_t tx[2] = { reg, value }; - - return i2c_xfer_unlocked(I2C_PORT_MP2964, I2C_ADDR_MP2964_FLAGS, - tx, sizeof(tx), NULL, 0, I2C_XFER_SINGLE); -} - -static void mp2964_read16(uint8_t reg, uint16_t *value) -{ - const uint8_t tx[1] = { reg }; - uint8_t rx[2]; - - i2c_xfer_unlocked(I2C_PORT_MP2964, I2C_ADDR_MP2964_FLAGS, - tx, sizeof(tx), rx, sizeof(rx), I2C_XFER_SINGLE); - *value = (rx[1] << 8) | rx[0]; -} - -static void mp2964_write16(uint8_t reg, uint16_t value) -{ - const uint8_t tx[3] = { reg, value & 0xff, value >> 8 }; - - i2c_xfer_unlocked(I2C_PORT_MP2964, I2C_ADDR_MP2964_FLAGS, - tx, sizeof(tx), NULL, 0, I2C_XFER_SINGLE); -} - -static int mp2964_select_page(enum reg_page page) -{ - int status; - - if (page >= REG_PAGE_COUNT) - return EC_ERROR_INVAL; - - status = mp2964_write8(MP2964_PAGE, page); - if (status != EC_SUCCESS) { - ccprintf("%s: could not select page 0x%02x, error %d\n", - __func__, page, status); - } - return status; -} - -static void mp2964_write_vec16(const struct mp2964_reg_val *init_list, - int count, int *delta) -{ - const struct mp2964_reg_val *reg_val; - uint16_t outval; - int i; - - reg_val = init_list; - for (i = 0; i < count; ++i, ++reg_val) { - mp2964_read16(reg_val->reg, &outval); - if (outval == reg_val->val) { - ccprintf("mp2964: reg 0x%02x already 0x%04x\n", - reg_val->reg, outval); - continue; - } - ccprintf("mp2964: tuning reg 0x%02x from 0x%04x to 0x%04x\n", - reg_val->reg, outval, reg_val->val); - mp2964_write16(reg_val->reg, reg_val->val); - *delta += 1; - } -} - -static int mp2964_store_user_all(void) -{ - const uint8_t wr = MP2964_STORE_USER_ALL; - const uint8_t rd = MP2964_RESTORE_USER_ALL; - int status; - - ccprintf("%s: updating persistent settings\n", __func__); - - status = i2c_xfer_unlocked(I2C_PORT_MP2964, I2C_ADDR_MP2964_FLAGS, - &wr, sizeof(wr), NULL, 0, I2C_XFER_SINGLE); - if (status != EC_SUCCESS) - return status; - - usleep(MP2964_STORE_WAIT_US); - - status = i2c_xfer_unlocked(I2C_PORT_MP2964, I2C_ADDR_MP2964_FLAGS, - &rd, sizeof(rd), NULL, 0, I2C_XFER_SINGLE); - if (status != EC_SUCCESS) - return status; - - usleep(MP2964_RESTORE_WAIT_US); - - return EC_SUCCESS; -} - -static void mp2964_patch_rail(enum reg_page page, - const struct mp2964_reg_val *page_vals, - int count, - int *delta) -{ - if (mp2964_select_page(page) != EC_SUCCESS) - return; - mp2964_write_vec16(page_vals, count, delta); -} - -int mp2964_tune(const struct mp2964_reg_val *rail_a, int count_a, - const struct mp2964_reg_val *rail_b, int count_b) -{ - int tries = 2; - int delta; - - udelay(MP2964_STARTUP_WAIT_US); - - i2c_lock(I2C_PORT_MP2964, 1); - - do { - int status; - - delta = 0; - mp2964_patch_rail(REG_PAGE_0, rail_a, count_a, &delta); - mp2964_patch_rail(REG_PAGE_1, rail_b, count_b, &delta); - if (delta == 0) - break; - - status = mp2964_store_user_all(); - if (status != EC_SUCCESS) - ccprintf("%s: STORE_USER_ALL failed\n", __func__); - } while (--tries > 0); - - i2c_lock(I2C_PORT_MP2964, 0); - - if (delta) - return EC_ERROR_UNKNOWN; - else - return EC_SUCCESS; -} diff --git a/driver/mp2964.h b/driver/mp2964.h deleted file mode 100644 index 8c0339c06e..0000000000 --- a/driver/mp2964.h +++ /dev/null @@ -1,22 +0,0 @@ -/* Copyright 2021 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. - */ - -#ifndef __CROS_EC_PMIC_MP2964_H -#define __CROS_EC_PMIC_MP2964_H - -#define MP2964_PAGE 0x00 -#define MP2964_STORE_USER_ALL 0x15 -#define MP2964_RESTORE_USER_ALL 0x16 -#define MP2964_MFR_ALT_SET 0x3f - -struct mp2964_reg_val { - uint8_t reg; - uint16_t val; -}; - -int mp2964_tune(const struct mp2964_reg_val *page0, int count0, - const struct mp2964_reg_val *page1, int count1); - -#endif /* __CROS_EC_PMIC_MP2964_H */ diff --git a/driver/mp4245.c b/driver/mp4245.c deleted file mode 100644 index 2b38e5c9e9..0000000000 --- a/driver/mp4245.c +++ /dev/null @@ -1,214 +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. - */ - -/* MPS MP4245 Buck-Boost converter driver. */ - -#include "common.h" -#include "console.h" -#include "i2c.h" -#include "mp4245.h" -#include "util.h" - - -static int mp4245_reg16_write(int offset, int data) -{ - return i2c_write16(I2C_PORT_MP4245, MP4245_I2C_ADDR_FLAGS, offset, - data); -} - -int mp4245_set_voltage_out(int desired_mv) -{ - int vout; - - /* - * For a desired voltage output Vdes, Vout = Vdes * 1024. This means - * there are 10 fractional and 6 integer bits. Vdes is stored in in mV - * so this scaling to mV must also be accounted for. - * - * VOUT_COMMAND = (Vdes (mV) * 1024 / 1000) / 1024 - */ - vout = (desired_mv * MP4245_VOUT_FROM_MV + (MP4245_VOUT_1V >> 1)) - / MP4245_VOUT_1V; - - return mp4245_reg16_write(MP4245_CMD_VOUT_COMMAND, vout); -} - -int mp4245_set_current_lim(int desired_ma) -{ - int limit; - - /* Current limit is stored as number of 50 mA steps */ - limit = (desired_ma + (MP4245_ILIM_STEP_MA / 2)) / MP4245_ILIM_STEP_MA; - - return mp4245_reg16_write(MP4245_CMD_MFR_CURRENT_LIM, limit); -} - -int mp4245_votlage_out_enable(int enable) -{ - int cmd_val = enable ? MP4245_CMD_OPERATION_ON : 0; - - return i2c_write8(I2C_PORT_MP4245, MP4245_I2C_ADDR_FLAGS, - MP4245_CMD_OPERATION, cmd_val); -} - -int mp3245_get_vbus(int *mv, int *ma) -{ - int vbus = 0; - int ibus = 0; - int rv; - - /* Get Vbus/Ibus raw measurements */ - rv = i2c_read16(I2C_PORT_MP4245, MP4245_I2C_ADDR_FLAGS, - MP4245_CMD_READ_VOUT, &vbus); - rv |= i2c_read16(I2C_PORT_MP4245, MP4245_I2C_ADDR_FLAGS, - MP4245_CMD_READ_IOUT, &ibus); - - if (rv == EC_SUCCESS) { - /* Convert Vbus/Ibus to mV/mA */ - vbus = MP4245_VOUT_TO_MV(vbus); - ibus = MP4245_IOUT_TO_MA(ibus); - } - - *mv = vbus; - *ma = ibus; - - return rv; -} - -struct mp4245_info { - uint8_t cmd; - uint8_t len; -}; - -static struct mp4245_info mp4245_cmds[] = { - {MP4245_CMD_OPERATION, 1}, - {MP4245_CMD_CLEAR_FAULTS, 1}, - {MP4245_CMD_WRITE_PROTECT, 1}, - {MP4245_CMD_STORE_USER_ALL, 1}, - {MP4245_CMD_RESTORE_USER_ALL, 1}, - {MP4245_CMD_VOUT_MODE, 1}, - {MP4245_CMD_VOUT_COMMAND, 2}, - {MP4245_CMD_VOUT_SCALE_LOOP, 2}, - {MP4245_CMD_STATUS_BYTE, 1}, - {MP4245_CMD_STATUS_WORD, 2}, - {MP4245_CMD_STATUS_VOUT, 1}, - {MP4245_CMD_STATUS_INPUT, 1}, - {MP4245_CMD_STATUS_TEMP, 1}, - {MP4245_CMD_STATUS_CML, 1}, - {MP4245_CMD_READ_VIN, 2}, - {MP4245_CMD_READ_VOUT, 2}, - {MP4245_CMD_READ_IOUT, 2}, - {MP4245_CMD_READ_TEMP, 2}, - {MP4245_CMD_MFR_MODE_CTRL, 1}, - {MP4245_CMD_MFR_CURRENT_LIM, 1}, - {MP4245_CMD_MFR_LINE_DROP, 1}, - {MP4245_CMD_MFR_OT_FAULT_LIM, 1}, - {MP4245_CMD_MFR_OT_WARN_LIM, 1}, - {MP4245_CMD_MFR_CRC_ERROR, 1}, - {MP4245_CMD_MFF_MTP_CFG_CODE, 1}, - {MP4245_CMD_MFR_MTP_REV_NUM, 1}, - {MP4245_CMD_MFR_STATUS_MASK, 1}, -}; - -static void mp4245_dump_reg(void) -{ - int i; - int val; - int rv; - - for (i = 0; i < ARRAY_SIZE(mp4245_cmds); i++) { - if (mp4245_cmds[i].len == 1) { - rv = i2c_read8(I2C_PORT_MP4245, MP4245_I2C_ADDR_FLAGS, - mp4245_cmds[i].cmd, &val); - } else { - rv = i2c_read16(I2C_PORT_MP4245, MP4245_I2C_ADDR_FLAGS, - mp4245_cmds[i].cmd, &val); - } - - if (!rv) - ccprintf("[%02x]:\t%04x\n", mp4245_cmds[i].cmd, val); - } -} - -void mp4245_get_status(void) -{ - int status; - int on; - int vbus; - int ibus; - int ilim; - int vout; - - /* Get Operation register */ - i2c_read8(I2C_PORT_MP4245, MP4245_I2C_ADDR_FLAGS, - MP4245_CMD_OPERATION, &on); - /* Vbus on/off is bit 7 */ - on >>= 7; - - /* Get status word */ - i2c_read16(I2C_PORT_MP4245, MP4245_I2C_ADDR_FLAGS, - MP4245_CMD_STATUS_WORD, &status); - - /* Get Vbus measurement */ - i2c_read16(I2C_PORT_MP4245, MP4245_I2C_ADDR_FLAGS, - MP4245_CMD_READ_VOUT, &vbus); - vbus = MP4245_VOUT_TO_MV(vbus); - - /* Get Ibus measurement */ - i2c_read16(I2C_PORT_MP4245, MP4245_I2C_ADDR_FLAGS, - MP4245_CMD_READ_IOUT, &ibus); - ibus = MP4245_IOUT_TO_MA(ibus); - - /* Get Vout command (sets Vbus level) */ - i2c_read16(I2C_PORT_MP4245, MP4245_I2C_ADDR_FLAGS, - MP4245_CMD_VOUT_COMMAND, &vout); - vout = MP4245_VOUT_TO_MV(vout); - - /* Get Input current limit */ - i2c_read8(I2C_PORT_MP4245, MP4245_I2C_ADDR_FLAGS, - MP4245_CMD_MFR_CURRENT_LIM, &ilim); - ilim *= MP4245_ILIM_STEP_MA; - - ccprintf("mp4245 Vbus %s:\n", on ? "On" : "Off"); - ccprintf("\tstatus = 0x%04x\n", status); - ccprintf("\tVout = %d mV, Vbus = %d mV\n", vout, vbus); - ccprintf("\tIlim = %d mA, Ibus = %d mA\n", ilim, ibus); -} - -static int command_mp4245(int argc, char **argv) -{ - char *e; - int val; - - if (argc < 2) - return EC_ERROR_PARAM_COUNT; - - if (!strcasecmp(argv[1], "info")) { - mp4245_get_status(); - } else if (!strcasecmp(argv[1], "dump")) { - mp4245_dump_reg(); - } else if (!strcasecmp(argv[1], "vbus")) { - if (argc < 3) - return EC_ERROR_PARAM_COUNT; - val = strtoi(argv[2], &e, 10); - /* If value out of bounds, turn off */ - if (val < 0 || val > 20) { - return EC_ERROR_PARAM2; - } - if (val == 0) { - mp4245_votlage_out_enable(0); - } else { - mp4245_set_voltage_out(val * 1000); - mp4245_votlage_out_enable(1); - } - } else { - return EC_ERROR_PARAM1; - } - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(mp4245, command_mp4245, - "<info|dump|vbus|ilim>", - "Turn on/off|set vbus."); - diff --git a/driver/mp4245.h b/driver/mp4245.h deleted file mode 100644 index b453ad2076..0000000000 --- a/driver/mp4245.h +++ /dev/null @@ -1,96 +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. - */ -/* MPS MP4245 Buck-Boost converter driver definitions */ - -/* I2C addresses */ -#define MP4245_I2C_ADDR_0_FLAGS 0x61 /* R1 -> GND */ -#define MP4245_I2C_ADDR_1_FLAGS 0x62 /* R1 -> 15.0k */ -#define MP4245_I2C_ADDR_2_FLAGS 0x63 /* R1 -> 25.5k */ -#define MP4245_I2C_ADDR_3_FLAGS 0x64 /* R1 -> 35.7k */ -#define MP4245_I2C_ADDR_4_FLAGS 0x65 /* R1 -> 45.3k */ -#define MP4245_I2C_ADDR_5_FLAGS 0x66 /* R1 -> 56.0k */ -#define MP4245_I2C_ADDR_6_FLAGS 0x67 /* R1 -> VCC */ - - -/* MP4245 CMD Offsets */ -#define MP4245_CMD_OPERATION 0x01 -#define MP4245_CMD_CLEAR_FAULTS 0x03 -#define MP4245_CMD_WRITE_PROTECT 0x10 -#define MP4245_CMD_STORE_USER_ALL 0x15 -#define MP4245_CMD_RESTORE_USER_ALL 0x16 -#define MP4245_CMD_VOUT_MODE 0x20 -#define MP4245_CMD_VOUT_COMMAND 0x21 -#define MP4245_CMD_VOUT_SCALE_LOOP 0x29 -#define MP4245_CMD_STATUS_BYTE 0x78 -#define MP4245_CMD_STATUS_WORD 0x79 -#define MP4245_CMD_STATUS_VOUT 0x7A -#define MP4245_CMD_STATUS_INPUT 0x7C -#define MP4245_CMD_STATUS_TEMP 0x7D -#define MP4245_CMD_STATUS_CML 0x7E -#define MP4245_CMD_READ_VIN 0x88 -#define MP4245_CMD_READ_VOUT 0x8B -#define MP4245_CMD_READ_IOUT 0x8C -#define MP4245_CMD_READ_TEMP 0x8D -#define MP4245_CMD_MFR_MODE_CTRL 0xD0 -#define MP4245_CMD_MFR_CURRENT_LIM 0xD1 -#define MP4245_CMD_MFR_LINE_DROP 0xD2 -#define MP4245_CMD_MFR_OT_FAULT_LIM 0xD3 -#define MP4245_CMD_MFR_OT_WARN_LIM 0xD4 -#define MP4245_CMD_MFR_CRC_ERROR 0xD5 -#define MP4245_CMD_MFF_MTP_CFG_CODE 0xD6 -#define MP4245_CMD_MFR_MTP_REV_NUM 0xD7 -#define MP4245_CMD_MFR_STATUS_MASK 0xD8 - -#define MP4245_CMD_OPERATION_ON BIT(7) - -#define MP4245_VOUT_1V BIT(10) -#define MP4245_VOUT_FROM_MV (MP4245_VOUT_1V * MP4245_VOUT_1V / 1000) -#define MP4245_VOUT_TO_MV(v) ((v * 1000) / MP4245_VOUT_1V) -#define MP4245_IOUT_TO_MA(i) (((i & 0x7ff) * 1000) / BIT(6)) -#define MP4245_ILIM_STEP_MA 50 -#define MP4245_VOUT_5V_DELAY_MS 10 - - -#define MP4245_MFR_STATUS_MASK_VOUT BIT(7) -#define MP4245_MFR_STATUS_MASK_IOUT BIT(6) -#define MP4245_MFR_STATUS_MASK_INPUT BIT(5) -#define MP4245_MFR_STATUS_MASK_TEMP BIT(4) -#define MP4245_MFR_STATUS_MASK_PG_STATUS BIT(3) -#define MP4245_MFR_STATUS_MASK_PG_ALT_EDGE BIT(2) -#define MP4245_MFR_STATUS_MASK_OTHER BIT(1) -#define MP4245_MFR_STATUS_MASK_UNKNOWN BIT(0) - -/** - * MP4245 set output voltage level - * - * @param desired_mv -> voltage level in mV - * @return i2c write result - */ -int mp4245_set_voltage_out(int desired_mv); - -/** - * MP4245 set output current limit - * - * @param desired_ma -> current limit in mA - * @return i2c write result - */ -int mp4245_set_current_lim(int desired_ma); - -/** - * MP4245 set output current limit - * - * @param enable -> 0 = off, else on - * @return i2c write result - */ -int mp4245_votlage_out_enable(int enable); - -/** - * MP4245 get Vbus voltage/current values - * - * @param *mv -> vbus voltage in mV - * @param *ma -> vbus current in mA - * @return i2c read results - */ -int mp3245_get_vbus(int *mv, int *ma); diff --git a/driver/nfc/ctn730.c b/driver/nfc/ctn730.c deleted file mode 100644 index 6f711c509e..0000000000 --- a/driver/nfc/ctn730.c +++ /dev/null @@ -1,711 +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 "chipset.h" -#include "ctn730.h" -#include "common.h" -#include "console.h" -#include "gpio.h" -#include "i2c.h" -#include "peripheral_charger.h" -#include "timer.h" -#include "util.h" -#include "watchdog.h" - -/* - * Configuration - */ - -/* Print additional data */ -#define CTN730_DEBUG - -/* - * When ctn730 is asleep, I2C is ignored but can wake it up. I2C will be resent - * after this delay. - */ -static const int _wake_up_delay_ms = 10; - -/* Device detection interval */ -static const int _detection_interval_ms = 500; - -/* Buffer size for i2c read & write */ -#define CTN730_MESSAGE_BUFFER_SIZE 0x20 - -/* This driver isn't compatible with big endian. */ -BUILD_ASSERT(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__); - -#define CPRINTS(fmt, args...) cprints(CC_PCHG, "CTN730: " fmt, ##args) - -static const char *_text_instruction(uint8_t instruction) -{ - /* TODO: For normal build, use %pb and BINARY_VALUE(res->inst, 6) */ - switch (instruction) { - case WLC_HOST_CTRL_RESET: - return "RESET"; - case WLC_HOST_CTRL_DL_OPEN_SESSION: - return "DL_OPEN"; - case WLC_HOST_CTRL_DL_COMMIT_SESSION: - return "DL_COMMIT"; - case WLC_HOST_CTRL_DL_WRITE_FLASH: - return "DL_WRITE"; - case WLC_HOST_CTRL_DUMP_STATUS: - return "DUMP_STATUS"; - case WLC_HOST_CTRL_GENERIC_ERROR: - return "GENERIC_ERROR"; - case WLC_HOST_CTRL_BIST: - return "BIST"; - case WLC_CHG_CTRL_ENABLE: - return "ENABLE"; - case WLC_CHG_CTRL_DISABLE: - return "DISABLE"; - case WLC_CHG_CTRL_DEVICE_STATE: - return "DEVICE_STATE"; - case WLC_CHG_CTRL_CHARGING_STATE: - return "CHARGING_STATE"; - case WLC_CHG_CTRL_CHARGING_INFO: - return "CHARGING_INFO"; - default: - return "UNDEF"; - } -} - -static const char *_text_message_type(uint8_t type) -{ - switch (type) { - case CTN730_MESSAGE_TYPE_COMMAND: - return "CMD"; - case CTN730_MESSAGE_TYPE_RESPONSE: - return "RSP"; - case CTN730_MESSAGE_TYPE_EVENT: - return "EVT"; - default: - return "BAD"; - } -} - -static const char *_text_status_code(uint8_t code) -{ - switch (code) { - case WLC_HOST_STATUS_OK: - return "OK"; - case WLC_HOST_STATUS_PARAMETER_ERROR: - return "PARAMETER_ERR"; - case WLC_HOST_STATUS_STATE_ERROR: - return "STATE_ERR"; - case WLC_HOST_STATUS_VALUE_ERROR: - return "VALUE_ERR"; - case WLC_HOST_STATUS_REJECTED: - return "REJECTED"; - case WLC_HOST_STATUS_RESOURCE_ERROR: - return "RESOURCE_ERR"; - case WLC_HOST_STATUS_TXLDO_ERROR: - return "TXLDO_ERR"; - case WLC_HOST_STATUS_ANTENNA_SELECTION_ERROR: - return "ANTENNA_SELECTION_ERR"; - case WLC_HOST_STATUS_BIST_FAILED: - return "BIST_FAILED"; - case WLC_HOST_STATUS_BIST_NO_WLC_CAP: - return "BIST_NO_WLC_CAP"; - case WLC_HOST_STATUS_BIST_TXLDO_CURRENT_OVERFLOW: - return "BIST_TXLDO_CURRENT_OVERFLOW"; - case WLC_HOST_STATUS_BIST_TXLDO_CURRENT_UNDERFLOW: - return "BIST_TXLDO_CURRENT_UNDERFLOW"; - case WLC_HOST_STATUS_FW_VERSION_ERROR: - return "FW_VERSION_ERR"; - case WLC_HOST_STATUS_FW_VERIFICATION_ERROR: - return "FW_VERIFICATION_ERR"; - case WLC_HOST_STATUS_NTAG_BLOCK_PARAMETER_ERROR: - return "NTAG_BLOCK_PARAMETER_ERR"; - case WLC_HOST_STATUS_NTAG_READ_ERROR: - return "NTAG_READ_ERR"; - default: - return "UNDEF"; - } -} - -static const char *_text_reset_reason(uint8_t code) -{ - switch (code) { - case WLC_HOST_CTRL_RESET_REASON_INTENDED: - return "intended"; - case WLC_HOST_CTRL_RESET_REASON_CORRUPTED: - return "corrupted"; - case WLC_HOST_CTRL_RESET_REASON_UNRECOVERABLE: - return "unrecoverable"; - default: - return "unknown"; - } -} - -static int _i2c_read(int i2c_port, uint8_t *in, int in_len) -{ - int rv; - - memset(in, 0, in_len); - - rv = i2c_xfer(i2c_port, CTN730_I2C_ADDR, NULL, 0, in, in_len); - if (rv) { - msleep(_wake_up_delay_ms); - rv = i2c_xfer(i2c_port, CTN730_I2C_ADDR, NULL, 0, in, in_len); - } - if (rv) - CPRINTS("Failed to read: %d", rv); - - return rv; -} - -static void _print_header(const struct ctn730_msg *msg) -{ - CPRINTS("%s_%s", - _text_instruction(msg->instruction), - _text_message_type(msg->message_type)); -} - -static int _send_command(struct pchg *ctx, const struct ctn730_msg *cmd) -{ - int i2c_port = ctx->cfg->i2c_port; - int rv; - - _print_header(cmd); - - rv = i2c_xfer(i2c_port, CTN730_I2C_ADDR, (void *)cmd, - sizeof(*cmd) + cmd->length, NULL, 0); - - if (rv) { - msleep(_wake_up_delay_ms); - rv = i2c_xfer(i2c_port, CTN730_I2C_ADDR, (void *)cmd, - sizeof(*cmd) + cmd->length, NULL, 0); - } - if (rv) - CPRINTS("Failed to write: %d", rv); - - return rv; -} - -static int ctn730_reset(struct pchg *ctx) -{ - gpio_set_level(GPIO_WLC_NRST_CONN, 0); - /* - * Datasheet says minimum is 10 us. This is better not to be a sleep - * especially if it's long (e.g. ~1 ms) since the PCHG state machine - * may try to access the I2C bus, which is held low by ctn730. - */ - udelay(15); - gpio_set_level(GPIO_WLC_NRST_CONN, 1); - return EC_SUCCESS_IN_PROGRESS; -} - -static int ctn730_init(struct pchg *ctx) -{ - uint8_t buf[CTN730_MESSAGE_BUFFER_SIZE]; - struct ctn730_msg *cmd = (void *)buf; - int rv; - - cmd->message_type = CTN730_MESSAGE_TYPE_COMMAND; - cmd->instruction = WLC_HOST_CTRL_RESET; - cmd->length = WLC_HOST_CTRL_RESET_CMD_SIZE; - cmd->payload[0] = ctx->mode == PCHG_MODE_NORMAL - ? WLC_HOST_CTRL_RESET_CMD_MODE_NORMAL - : WLC_HOST_CTRL_RESET_CMD_MODE_DOWNLOAD; - - /* TODO: Run 1 sec timeout timer. */ - rv = _send_command(ctx, cmd); - if (rv) - return rv; - - /* WLC-host should send EVT_HOST_CTRL_RESET_EVT shortly. */ - return EC_SUCCESS_IN_PROGRESS; -} - -static int ctn730_enable(struct pchg *ctx, bool enable) -{ - uint8_t buf[CTN730_MESSAGE_BUFFER_SIZE]; - struct ctn730_msg *cmd = (void *)buf; - uint16_t *interval = (void *)cmd->payload; - int rv; - - cmd->message_type = CTN730_MESSAGE_TYPE_COMMAND; - if (enable) { - cmd->instruction = WLC_CHG_CTRL_ENABLE; - cmd->length = WLC_CHG_CTRL_ENABLE_CMD_SIZE; - /* Assume core is little endian. Use htole16 for portability. */ - *interval = _detection_interval_ms; - } else { - cmd->instruction = WLC_CHG_CTRL_DISABLE; - cmd->length = WLC_CHG_CTRL_DISABLE_CMD_SIZE; - } - - rv = _send_command(ctx, cmd); - if (rv) - return rv; - - return EC_SUCCESS_IN_PROGRESS; -} - -static int _process_payload_response(struct pchg *ctx, struct ctn730_msg *res) -{ - uint8_t len = res->length; - uint8_t buf[CTN730_MESSAGE_BUFFER_SIZE]; - - if (sizeof(buf) < len) { - CPRINTS("Response size (%d) exceeds buffer", len); - return EC_ERROR_OVERFLOW; - } - - if (len > 0) { - int rv = _i2c_read(ctx->cfg->i2c_port, buf, len); - if (rv) - return rv; - if (IS_ENABLED(CTN730_DEBUG)) - CPRINTS("Payload: %ph", HEX_BUF(buf, len)); - } - - ctx->event = PCHG_EVENT_NONE; - - /* - * Messages with no payload (<len> == 0) is allowed in the spec. So, - * make sure <len> is checked before reading buf[0]. - */ - switch (res->instruction) { - case WLC_HOST_CTRL_RESET: - if (len != WLC_HOST_CTRL_RESET_RSP_SIZE) - return EC_ERROR_UNKNOWN; - if (buf[0] != WLC_HOST_STATUS_OK) - ctx->event = PCHG_EVENT_OTHER_ERROR; - break; - case WLC_HOST_CTRL_DL_OPEN_SESSION: - if (len != WLC_HOST_CTRL_DL_OPEN_SESSION_RSP_SIZE) - return EC_ERROR_UNKNOWN; - if (buf[0] != WLC_HOST_STATUS_OK) { - CPRINTS("FW open session failed for %s", - _text_status_code(buf[0])); - ctx->event = PCHG_EVENT_UPDATE_ERROR; - ctx->error |= PCHG_ERROR_MASK(PCHG_ERROR_FW_VERSION); - } else { - ctx->event = PCHG_EVENT_UPDATE_OPENED; - } - break; - case WLC_HOST_CTRL_DL_COMMIT_SESSION: - if (len != WLC_HOST_CTRL_DL_COMMIT_SESSION_RSP_SIZE) - return EC_ERROR_UNKNOWN; - if (buf[0] != WLC_HOST_STATUS_OK) { - CPRINTS("FW commit failed for %s", - _text_status_code(buf[0])); - ctx->event = PCHG_EVENT_UPDATE_ERROR; - ctx->error |= PCHG_ERROR_MASK(PCHG_ERROR_INVALID_FW); - } else { - ctx->event = PCHG_EVENT_UPDATE_CLOSED; - } - break; - case WLC_HOST_CTRL_DL_WRITE_FLASH: - if (len != WLC_HOST_CTRL_DL_WRITE_FLASH_RSP_SIZE) - return EC_ERROR_UNKNOWN; - if (buf[0] != WLC_HOST_STATUS_OK) { - CPRINTS("FW write failed for %s", - _text_status_code(buf[0])); - ctx->event = PCHG_EVENT_UPDATE_ERROR; - ctx->error |= PCHG_ERROR_MASK(PCHG_ERROR_WRITE_FLASH); - } else { - ctx->event = PCHG_EVENT_UPDATE_WRITTEN; - } - break; - case WLC_CHG_CTRL_ENABLE: - if (len != WLC_CHG_CTRL_ENABLE_RSP_SIZE) - return EC_ERROR_UNKNOWN; - if (buf[0] != WLC_HOST_STATUS_OK) - ctx->event = PCHG_EVENT_OTHER_ERROR; - else - ctx->event = PCHG_EVENT_ENABLED; - break; - case WLC_CHG_CTRL_DISABLE: - if (len != WLC_CHG_CTRL_DISABLE_RSP_SIZE) - return EC_ERROR_UNKNOWN; - if (buf[0] != WLC_HOST_STATUS_OK) - ctx->event = PCHG_EVENT_OTHER_ERROR; - else - ctx->event = PCHG_EVENT_DISABLED; - break; - case WLC_CHG_CTRL_CHARGING_INFO: - if (len != WLC_CHG_CTRL_CHARGING_INFO_RSP_SIZE) - return EC_ERROR_UNKNOWN; - if (buf[0] != WLC_HOST_STATUS_OK) { - ctx->event = PCHG_EVENT_OTHER_ERROR; - } else { - ctx->battery_percent = buf[1]; - ctx->event = PCHG_EVENT_CHARGE_UPDATE; - } - break; - default: - CPRINTS("Received unknown response (%d)", res->instruction); - break; - } - - return EC_SUCCESS; -} - -static int _process_payload_event(struct pchg *ctx, struct ctn730_msg *res) -{ - uint8_t len = res->length; - uint8_t buf[CTN730_MESSAGE_BUFFER_SIZE]; - - if (sizeof(buf) < len) { - CPRINTS("Response size (%d) exceeds buffer", len); - return EC_ERROR_OVERFLOW; - } - - if (len > 0) { - int rv = _i2c_read(ctx->cfg->i2c_port, buf, len); - if (rv) - return rv; - if (IS_ENABLED(CTN730_DEBUG)) - CPRINTS("Payload: %ph", HEX_BUF(buf, len)); - } - - ctx->event = PCHG_EVENT_NONE; - - /* - * Messages with no payload (<len> == 0) is allowed in the spec. So, - * make sure <len> is checked before reading buf[0]. - */ - switch (res->instruction) { - case WLC_HOST_CTRL_RESET: - if (len < WLC_HOST_CTRL_RESET_EVT_MIN_SIZE) - return EC_ERROR_INVAL; - if (buf[0] == WLC_HOST_CTRL_RESET_EVT_NORMAL_MODE) { - if (len != WLC_HOST_CTRL_RESET_EVT_NORMAL_MODE_SIZE) - return EC_ERROR_INVAL; - ctx->event = PCHG_EVENT_IN_NORMAL; - ctx->fw_version = (uint16_t)buf[1] << 8 | buf[2]; - CPRINTS("Normal Mode (FW=0x%02x.%02x)", buf[1], buf[2]); - /* - * ctn730 isn't immediately ready for i2c write after - * normal mode initialization (b:178096436). - */ - msleep(5); - } else if (buf[0] == WLC_HOST_CTRL_RESET_EVT_DOWNLOAD_MODE) { - if (len != WLC_HOST_CTRL_RESET_EVT_DOWNLOAD_MODE_SIZE) - return EC_ERROR_INVAL; - CPRINTS("Download Mode (%s)", - _text_reset_reason(buf[1])); - ctx->event = PCHG_EVENT_RESET; - } else { - return EC_ERROR_INVAL; - } - break; - case WLC_HOST_CTRL_GENERIC_ERROR: - break; - case WLC_CHG_CTRL_DISABLE: - if (len != WLC_CHG_CTRL_DISABLE_EVT_SIZE) - return EC_ERROR_INVAL; - ctx->event = PCHG_EVENT_DISABLED; - break; - case WLC_CHG_CTRL_DEVICE_STATE: - if (len < WLC_CHG_CTRL_DEVICE_STATE_EVT_SIZE) - return EC_ERROR_INVAL; - switch (buf[0]) { - case WLC_CHG_CTRL_DEVICE_STATE_DEVICE_DOCKED: - if (len != WLC_CHG_CTRL_DEVICE_STATE_EVT_SIZE) - return EC_ERROR_INVAL; - ctx->event = PCHG_EVENT_DEVICE_DETECTED; - break; - case WLC_CHG_CTRL_DEVICE_STATE_DEVICE_DETECTED: - if (len != WLC_CHG_CTRL_DEVICE_STATE_EVT_SIZE_DETECTED) - return EC_ERROR_INVAL; - ctx->event = PCHG_EVENT_DEVICE_CONNECTED; - break; - case WLC_CHG_CTRL_DEVICE_STATE_DEVICE_DEVICE_LOST: - case WLC_CHG_CTRL_DEVICE_STATE_DEVICE_UNDOCKED: - if (len != WLC_CHG_CTRL_DEVICE_STATE_EVT_SIZE) - return EC_ERROR_INVAL; - ctx->event = PCHG_EVENT_DEVICE_LOST; - break; - default: - return EC_ERROR_INVAL; - } - break; - case WLC_CHG_CTRL_CHARGING_STATE: - if (len != WLC_CHG_CTRL_CHARGING_STATE_EVT_SIZE) - return EC_ERROR_INVAL; - switch (buf[0]) { - case WLC_CHG_CTRL_CHARGING_STATE_CHARGE_STARTED: - ctx->event = PCHG_EVENT_CHARGE_STARTED; - break; - case WLC_CHG_CTRL_CHARGING_STATE_CHARGE_ENDED: - ctx->event = PCHG_EVENT_CHARGE_ENDED; - break; - case WLC_CHG_CTRL_CHARGING_STATE_CHARGE_STOPPED: - /* Includes over temp., DISABLE_CMD, device removal. */ - ctx->event = PCHG_EVENT_CHARGE_STOPPED; - break; - default: - return EC_ERROR_INVAL; - } - break; - case WLC_CHG_CTRL_CHARGING_INFO: - if (len != WLC_CHG_CTRL_CHARGING_INFO_EVT_SIZE || buf[0] > 100) - return EC_ERROR_INVAL; - ctx->event = PCHG_EVENT_CHARGE_UPDATE; - ctx->battery_percent = buf[0]; - break; - default: - CPRINTS("Received unknown event (%d)", res->instruction); - break; - } - - return EC_SUCCESS; -} - -static int ctn730_get_event(struct pchg *ctx) -{ - struct ctn730_msg res; - int i2c_port = ctx->cfg->i2c_port; - int rv; - - /* Read message header */ - rv = _i2c_read(i2c_port, (uint8_t *)&res, sizeof(res)); - if (rv) - return rv; - - _print_header(&res); - - if (res.message_type == CTN730_MESSAGE_TYPE_RESPONSE) { - /* TODO: Check 1 sec timeout. */ - return _process_payload_response(ctx, &res); - } else if (res.message_type == CTN730_MESSAGE_TYPE_EVENT) { - return _process_payload_event(ctx, &res); - } - - CPRINTS("Invalid message type (%d)", res.message_type); - return EC_ERROR_UNKNOWN; -} - -static int ctn730_get_soc(struct pchg *ctx) -{ - struct ctn730_msg cmd; - int rv; - - cmd.message_type = CTN730_MESSAGE_TYPE_COMMAND; - cmd.instruction = WLC_CHG_CTRL_CHARGING_INFO; - cmd.length = WLC_CHG_CTRL_CHARGING_INFO_CMD_SIZE; - - rv = _send_command(ctx, &cmd); - if (rv) - return rv; - - return EC_SUCCESS_IN_PROGRESS; -} - -static int ctn730_update_open(struct pchg *ctx) -{ - uint8_t buf[sizeof(struct ctn730_msg) - + WLC_HOST_CTRL_DL_OPEN_SESSION_CMD_SIZE]; - struct ctn730_msg *cmd = (void *)buf; - uint32_t version = ctx->update.version; - int rv; - - cmd->message_type = CTN730_MESSAGE_TYPE_COMMAND; - cmd->instruction = WLC_HOST_CTRL_DL_OPEN_SESSION; - cmd->length = WLC_HOST_CTRL_DL_OPEN_SESSION_CMD_SIZE; - cmd->payload[0] = (version >> 8) & 0xff; - cmd->payload[1] = version & 0xff; - - rv = _send_command(ctx, cmd); - if (rv) - return rv; - - return EC_SUCCESS_IN_PROGRESS; -} - -static int ctn730_update_write(struct pchg *ctx) -{ - uint8_t buf[sizeof(struct ctn730_msg) - + WLC_HOST_CTRL_DL_WRITE_FLASH_CMD_SIZE]; - struct ctn730_msg *cmd = (void *)buf; - uint32_t *a = (void *)cmd->payload; - uint8_t *d = (void *)&cmd->payload[CTN730_FLASH_ADDR_SIZE]; - int rv; - - /* Address is 3 bytes. FW size must be a multiple of 128 bytes. */ - if (ctx->update.addr & GENMASK(31, 24) - || ctx->update.size != WLC_HOST_CTRL_DL_WRITE_FLASH_BLOCK_SIZE) - return EC_ERROR_INVAL; - - cmd->message_type = CTN730_MESSAGE_TYPE_COMMAND; - cmd->instruction = WLC_HOST_CTRL_DL_WRITE_FLASH; - cmd->length = WLC_HOST_CTRL_DL_WRITE_FLASH_CMD_SIZE; - - /* 4th byte will be overwritten by memcpy below. */ - *a = ctx->update.addr; - - /* Store data in payload with 0-padding for short blocks. */ - memset(d, 0, WLC_HOST_CTRL_DL_WRITE_FLASH_BLOCK_SIZE); - memcpy(d, ctx->update.data, ctx->update.size); - - rv = _send_command(ctx, cmd); - if (rv) - return rv; - - return EC_SUCCESS_IN_PROGRESS; -} - -static int ctn730_update_close(struct pchg *ctx) -{ - uint8_t buf[sizeof(struct ctn730_msg) - + WLC_HOST_CTRL_DL_COMMIT_SESSION_CMD_SIZE]; - struct ctn730_msg *cmd = (void *)buf; - uint32_t *crc32 = (void *)cmd->payload; - int rv; - - cmd->message_type = CTN730_MESSAGE_TYPE_COMMAND; - cmd->instruction = WLC_HOST_CTRL_DL_COMMIT_SESSION; - cmd->length = WLC_HOST_CTRL_DL_COMMIT_SESSION_CMD_SIZE; - *crc32 = ctx->update.crc32; - - rv = _send_command(ctx, cmd); - if (rv) - return rv; - - return EC_SUCCESS_IN_PROGRESS; -} - -/** - * Send command in blocking loop - * - * @param ctx PCHG port context - * @param buf [IN] Command header and payload to send. - * [OUT] Response header and payload received. - * @param buf_len Size of <buf> - * @return enum ec_error_list - */ -static int _send_command_blocking(struct pchg *ctx, uint8_t *buf, int buf_len) -{ - int i2c_port = ctx->cfg->i2c_port; - int irq_pin = ctx->cfg->irq_pin; - struct ctn730_msg *cmd = (void *)buf; - struct ctn730_msg *res = (void *)buf; - timestamp_t deadline; - int rv; - - gpio_disable_interrupt(irq_pin); - - rv = _send_command(ctx, cmd); - if (rv) - goto exit; - - deadline.val = get_time().val + CTN730_COMMAND_TIME_OUT; - - /* Busy loop */ - while (gpio_get_level(irq_pin) == 0 && !rv) { - udelay(1 * MSEC); - rv = timestamp_expired(deadline, NULL); - watchdog_reload(); - } - - if (rv) { - ccprintf("Response timeout\n"); - rv = EC_ERROR_TIMEOUT; - goto exit; - } - - rv = _i2c_read(i2c_port, buf, sizeof(*res)); - if (rv) - goto exit; - - _print_header(res); - - if (sizeof(*res) + res->length > buf_len) { - ccprintf("RSP size exceeds buffer\n"); - rv = EC_ERROR_OVERFLOW; - goto exit; - } - - rv = _i2c_read(i2c_port, res->payload, res->length); - if (rv) - goto exit; - -exit: - gpio_clear_pending_interrupt(irq_pin); - gpio_enable_interrupt(irq_pin); - - return rv; -} - -const struct pchg_drv ctn730_drv = { - .reset = ctn730_reset, - .init = ctn730_init, - .enable = ctn730_enable, - .get_event = ctn730_get_event, - .get_soc = ctn730_get_soc, - .update_open = ctn730_update_open, - .update_write = ctn730_update_write, - .update_close = ctn730_update_close, -}; - -static int cc_ctn730(int argc, char **argv) -{ - int port; - char *end; - uint8_t buf[CTN730_MESSAGE_BUFFER_SIZE]; - struct ctn730_msg *cmd = (void *)buf; - struct ctn730_msg *res = (void *)buf; - int rv; - - if (argc < 4) - return EC_ERROR_PARAM_COUNT; - - port = strtoi(argv[1], &end, 0); - if (*end || port < 0 || pchg_count <= port) - return EC_ERROR_PARAM2; - - cmd->message_type = CTN730_MESSAGE_TYPE_COMMAND; - - if (!strcasecmp(argv[2], "dump")) { - int tag = strtoi(argv[3], &end, 0); - - if (*end || tag < 0 || 0x07 < tag) - return EC_ERROR_PARAM3; - - cmd->instruction = WLC_HOST_CTRL_DUMP_STATUS; - cmd->length = WLC_HOST_CTRL_DUMP_STATUS_CMD_SIZE; - cmd->payload[0] = tag; - } else if (!strcasecmp(argv[2], "bist")) { - int id = strtoi(argv[3], &end, 0); - - if (*end || id < 0) - return EC_ERROR_PARAM3; - - cmd->instruction = WLC_HOST_CTRL_BIST; - cmd->payload[0] = id; - - switch (id) { - case 0x01: - /* Switch on RF field. Tx driver conf not implemented */ - cmd->length = 1; - break; - case 0x04: - /* WLC device activation test */ - cmd->length = 1; - break; - default: - return EC_ERROR_PARAM3; - } - } else { - return EC_ERROR_PARAM2; - } - - rv = _send_command_blocking(&pchgs[port], buf, sizeof(buf)); - if (rv) - return rv; - - ccprintf("STATUS_%s\n", _text_status_code(res->payload[0])); - hexdump(res->payload, res->length); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(ctn730, cc_ctn730, - "<port> dump/bist <tag/id>" - "\n\t<port> dump <tag>" - "\n\t<port> bist <test_id>", - "Control ctn730"); diff --git a/driver/nfc/ctn730.h b/driver/nfc/ctn730.h deleted file mode 100644 index 0195b36a6d..0000000000 --- a/driver/nfc/ctn730.h +++ /dev/null @@ -1,121 +0,0 @@ -/* Copyright 2021 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. - */ - -#ifndef __CROS_EC_CTN730_H -#define __CROS_EC_CTN730_H - -#define CTN730_I2C_ADDR 0x28 - -/* Size of flash address space in bytes */ -#define CTN730_FLASH_ADDR_SIZE 3 - -/* All commands are guaranteed to finish within 1 second. */ -#define CTN730_COMMAND_TIME_OUT (1 * SECOND) - -/* Message Types */ -#define CTN730_MESSAGE_TYPE_COMMAND 0b00 -#define CTN730_MESSAGE_TYPE_RESPONSE 0b01 -#define CTN730_MESSAGE_TYPE_EVENT 0b10 - -/* Instruction Codes */ -#define WLC_HOST_CTRL_RESET 0b000000 -#define WLC_HOST_CTRL_DL_OPEN_SESSION 0b000011 -#define WLC_HOST_CTRL_DL_COMMIT_SESSION 0b000100 -#define WLC_HOST_CTRL_DL_WRITE_FLASH 0b000101 -#define WLC_HOST_CTRL_DUMP_STATUS 0b001100 -#define WLC_HOST_CTRL_GENERIC_ERROR 0b001111 -#define WLC_HOST_CTRL_BIST 0b000110 -#define WLC_CHG_CTRL_ENABLE 0b010000 -#define WLC_CHG_CTRL_DISABLE 0b010001 -#define WLC_CHG_CTRL_DEVICE_STATE 0b010010 -#define WLC_CHG_CTRL_CHARGING_STATE 0b010100 -#define WLC_CHG_CTRL_CHARGING_INFO 0b010101 - -/* WLC_HOST_CTRL_RESET constants */ -#define WLC_HOST_CTRL_RESET_CMD_SIZE 1 -#define WLC_HOST_CTRL_RESET_RSP_SIZE 1 -#define WLC_HOST_CTRL_RESET_EVT_NORMAL_MODE 0x00 -#define WLC_HOST_CTRL_RESET_EVT_NORMAL_MODE_SIZE 3 -#define WLC_HOST_CTRL_RESET_EVT_DOWNLOAD_MODE 0x01 -#define WLC_HOST_CTRL_RESET_EVT_DOWNLOAD_MODE_SIZE 2 -#define WLC_HOST_CTRL_RESET_REASON_INTENDED 0x00 -#define WLC_HOST_CTRL_RESET_REASON_CORRUPTED 0x01 -#define WLC_HOST_CTRL_RESET_REASON_UNRECOVERABLE 0x02 -#define WLC_HOST_CTRL_RESET_CMD_MODE_NORMAL 0x00 -#define WLC_HOST_CTRL_RESET_CMD_MODE_DOWNLOAD 0x01 -#define WLC_HOST_CTRL_RESET_EVT_MIN_SIZE \ - WLC_HOST_CTRL_RESET_EVT_DOWNLOAD_MODE_SIZE - -/* WLC_HOST_CTRL_DL_* constants */ -#define WLC_HOST_CTRL_DL_OPEN_SESSION_CMD_SIZE 2 -#define WLC_HOST_CTRL_DL_OPEN_SESSION_RSP_SIZE 1 -#define WLC_HOST_CTRL_DL_WRITE_FLASH_BLOCK_SIZE 128 -#define WLC_HOST_CTRL_DL_WRITE_FLASH_CMD_SIZE \ - (CTN730_FLASH_ADDR_SIZE + WLC_HOST_CTRL_DL_WRITE_FLASH_BLOCK_SIZE) -#define WLC_HOST_CTRL_DL_WRITE_FLASH_RSP_SIZE 1 -#define WLC_HOST_CTRL_DL_COMMIT_SESSION_CMD_SIZE 4 -#define WLC_HOST_CTRL_DL_COMMIT_SESSION_RSP_SIZE 1 - -/* WLC_CHG_CTRL_ENABLE constants */ -#define WLC_CHG_CTRL_ENABLE_CMD_SIZE 2 -#define WLC_CHG_CTRL_ENABLE_RSP_SIZE 1 - -/* WLC_CHG_CTRL_DISABLE constants */ -#define WLC_CHG_CTRL_DISABLE_CMD_SIZE 0 -#define WLC_CHG_CTRL_DISABLE_RSP_SIZE 1 -#define WLC_CHG_CTRL_DISABLE_EVT_SIZE 1 - -/* WLC_CHG_CTRL_DEVICE_STATE constants */ -#define WLC_CHG_CTRL_DEVICE_STATE_DEVICE_DETECTED 0x00 -#define WLC_CHG_CTRL_DEVICE_STATE_DEVICE_DEACTIVATED 0x01 -#define WLC_CHG_CTRL_DEVICE_STATE_DEVICE_DEVICE_LOST 0x02 -#define WLC_CHG_CTRL_DEVICE_STATE_DEVICE_DEVICE_BAD_VERSION 0x03 -#define WLC_CHG_CTRL_DEVICE_STATE_DEVICE_DOCKED 0x04 -#define WLC_CHG_CTRL_DEVICE_STATE_DEVICE_UNDOCKED 0x05 -#define WLC_CHG_CTRL_DEVICE_STATE_EVT_SIZE_DETECTED 8 -#define WLC_CHG_CTRL_DEVICE_STATE_EVT_SIZE 1 - -/* WLC_CHG_CTRL_CHARGING_STATE constants */ -#define WLC_CHG_CTRL_CHARGING_STATE_CHARGE_STARTED 0x00 -#define WLC_CHG_CTRL_CHARGING_STATE_CHARGE_ENDED 0x01 -#define WLC_CHG_CTRL_CHARGING_STATE_CHARGE_STOPPED 0x02 -#define WLC_CHG_CTRL_CHARGING_STATE_EVT_SIZE 1 - -/* WLC_HOST_CTRL_DUMP_STATUS constants */ -#define WLC_HOST_CTRL_DUMP_STATUS_CMD_SIZE 1 - -/* WLC_CHG_CTRL_CHARGING_INFO constants */ -#define WLC_CHG_CTRL_CHARGING_INFO_CMD_SIZE 0 -#define WLC_CHG_CTRL_CHARGING_INFO_RSP_SIZE 2 -#define WLC_CHG_CTRL_CHARGING_INFO_EVT_SIZE 5 - -/* Status Codes */ -enum wlc_host_status { - WLC_HOST_STATUS_OK = 0x00, - WLC_HOST_STATUS_PARAMETER_ERROR = 0x01, - WLC_HOST_STATUS_STATE_ERROR = 0x02, - WLC_HOST_STATUS_VALUE_ERROR = 0x03, - WLC_HOST_STATUS_REJECTED = 0x04, - WLC_HOST_STATUS_RESOURCE_ERROR = 0x10, - WLC_HOST_STATUS_TXLDO_ERROR = 0x11, - WLC_HOST_STATUS_ANTENNA_SELECTION_ERROR = 0x12, - WLC_HOST_STATUS_BIST_FAILED = 0x20, - WLC_HOST_STATUS_BIST_NO_WLC_CAP = 0x21, - WLC_HOST_STATUS_BIST_TXLDO_CURRENT_OVERFLOW = 0x22, - WLC_HOST_STATUS_BIST_TXLDO_CURRENT_UNDERFLOW = 0x23, - WLC_HOST_STATUS_FW_VERSION_ERROR = 0x30, - WLC_HOST_STATUS_FW_VERIFICATION_ERROR = 0x31, - WLC_HOST_STATUS_NTAG_BLOCK_PARAMETER_ERROR = 0x32, - WLC_HOST_STATUS_NTAG_READ_ERROR = 0x33, -}; - -struct ctn730_msg { - uint8_t instruction : 6; - uint8_t message_type : 2; - uint8_t length; - uint8_t payload[]; -} __packed; - -#endif /* __CROS_EC_CTN730_H */ diff --git a/driver/pmic_bd99992gw.h b/driver/pmic_bd99992gw.h deleted file mode 100644 index e00ea1d252..0000000000 --- a/driver/pmic_bd99992gw.h +++ /dev/null @@ -1,31 +0,0 @@ -/* Copyright 2018 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. - * - * ROHM BD99992GW PMIC register map. - */ - -#ifndef __CROS_EC_PMIC_BD99992GW_H -#define __CROS_EC_PMIC_BD99992GW_H - -#include "temp_sensor/bd99992gw.h" - -#define BD99992GW_REG_PWRSRCINT 0x04 -#define BD99992GW_REG_RESETIRQ1 0x08 -#define BD99992GW_REG_PBCONFIG 0x14 -#define BD99992GW_REG_PWRSTAT1 0x16 -#define BD99992GW_REG_PWRSTAT2 0x17 -#define BD99992GW_REG_VCCIOCNT 0x30 -#define BD99992GW_REG_V5ADS3CNT 0x31 -#define BD99992GW_REG_V18ACNT 0x34 -#define BD99992GW_REG_V100ACNT 0x37 -#define BD99992GW_REG_V085ACNT 0x38 -#define BD99992GW_REG_VRMODECTRL 0x3b -#define BD99992GW_REG_DISCHGCNT1 0x3c -#define BD99992GW_REG_DISCHGCNT2 0x3d -#define BD99992GW_REG_DISCHGCNT3 0x3e -#define BD99992GW_REG_DISCHGCNT4 0x3f -#define BD99992GW_REG_SDWNCTRL 0x49 -#define BD99992GW_SDWNCTRL_SWDN BIT(0) /* SWDN mask */ - -#endif /* __CROS_EC_PMIC_BD99992GW_H */ diff --git a/driver/pmic_tps650x30.h b/driver/pmic_tps650x30.h deleted file mode 100644 index f03bef5f05..0000000000 --- a/driver/pmic_tps650x30.h +++ /dev/null @@ -1,37 +0,0 @@ -/* Copyright 2017 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. - * - * TI TPS650x30 PMIC register map. - */ - -#ifndef __CROS_EC_PMIC_TPS650X30_H -#define __CROS_EC_PMIC_TPS650X30_H - -/* I2C interface */ -#define TPS650X30_I2C_ADDR1_FLAGS 0x30 -#define TPS650X30_I2C_ADDR2_FLAGS 0x32 -#define TPS650X30_I2C_ADDR3_FLAGS 0x34 - -/* TPS650X30 registers */ -#define TPS650X30_REG_VENDORID 0x00 -#define TPS650X30_REG_PBCONFIG 0x14 -#define TPS650X30_REG_PGMASK1 0x18 -#define TPS650X30_REG_VCCIOCNT 0x30 -#define TPS650X30_REG_V5ADS3CNT 0x31 -#define TPS650X30_REG_V33ADSWCNT 0x32 -#define TPS650X30_REG_V18ACNT 0x34 -#define TPS650X30_REG_V1P2UCNT 0x36 -#define TPS650X30_REG_V100ACNT 0x37 -#define TPS650X30_REG_VRMODECTRL 0x3B -#define TPS650X30_REG_DISCHCNT1 0x3C -#define TPS650X30_REG_DISCHCNT2 0x3D -#define TPS650X30_REG_DISCHCNT3 0x3E -#define TPS650X30_REG_DISCHCNT4 0x3F -#define TPS650X30_REG_PWFAULT_MASK1 0xE5 -#define TPS650X30_REG_PWFAULT_MASK2 0xE6 - -/* TPS650X30 register values */ -#define TPS650X30_VENDOR_ID 0x22 - -#endif /* __CROS_EC_PMIC_TPS650X30_H */ diff --git a/driver/ppc/aoz1380.c b/driver/ppc/aoz1380.c deleted file mode 100644 index 4e2188c60d..0000000000 --- a/driver/ppc/aoz1380.c +++ /dev/null @@ -1,162 +0,0 @@ -/* Copyright 2019 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. - */ - -/* - * AOZ1380 USB-C Power Path Controller - * - * This is a basic TCPM controlled PPC driver. It could easily be - * renamed and repurposed to be generic, if there are other TCPM - * controlled PPC chips that are similar to the AOZ1380 - */ - -#include "atomic.h" -#include "common.h" -#include "console.h" -#include "aoz1380.h" -#include "hooks.h" -#include "system.h" -#include "tcpm/tcpm.h" -#include "usb_pd.h" -#include "usb_pd_tcpc.h" -#include "usbc_ppc.h" - -#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) -#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) - -static uint32_t irq_pending; /* Bitmask of ports signaling an interrupt. */ - -#define AOZ1380_FLAGS_SOURCE_ENABLED BIT(0) -#define AOZ1380_FLAGS_SINK_ENABLED BIT(1) -#define AOZ1380_FLAGS_INT_ON_DISCONNECT BIT(2) -static uint32_t flags[CONFIG_USB_PD_PORT_MAX_COUNT]; - -#define AOZ1380_SET_FLAG(port, flag) atomic_or(&flags[port], (flag)) -#define AOZ1380_CLR_FLAG(port, flag) atomic_clear_bits(&flags[port], (flag)) - -static int aoz1380_init(int port) -{ - flags[port] = 0; - - if (tcpm_get_snk_ctrl(port)) - AOZ1380_SET_FLAG(port, AOZ1380_FLAGS_SINK_ENABLED); - - if (tcpm_get_src_ctrl(port)) - AOZ1380_SET_FLAG(port, AOZ1380_FLAGS_SOURCE_ENABLED); - - return EC_SUCCESS; -} - -static int aoz1380_vbus_sink_enable(int port, int enable) -{ - int rv; - - rv = tcpm_set_snk_ctrl(port, enable); - if (rv) - return rv; - - /* - * On enable, we want to indicate connection as a SINK. - * On disable, clear SINK and that we have interrupted. - */ - if (enable) - AOZ1380_SET_FLAG(port, AOZ1380_FLAGS_SINK_ENABLED); - else - AOZ1380_CLR_FLAG(port, (AOZ1380_FLAGS_SINK_ENABLED | - AOZ1380_FLAGS_INT_ON_DISCONNECT)); - - return EC_SUCCESS; -} - -static int aoz1380_vbus_source_enable(int port, int enable) -{ - int rv; - - rv = tcpm_set_src_ctrl(port, enable); - if (rv) - return rv; - - /* - * On enable, we want to indicate connection as a SOURCE. - * On disable, clear SOURCE and that we have interrupted. - */ - if (enable) - AOZ1380_SET_FLAG(port, AOZ1380_FLAGS_SOURCE_ENABLED); - else - AOZ1380_CLR_FLAG(port, (AOZ1380_FLAGS_SOURCE_ENABLED | - AOZ1380_FLAGS_INT_ON_DISCONNECT)); - - return EC_SUCCESS; -} - -static int aoz1380_is_sourcing_vbus(int port) -{ - return flags[port] & AOZ1380_FLAGS_SOURCE_ENABLED; -} - -static int aoz1380_set_vbus_source_current_limit(int port, - enum tcpc_rp_value rp) -{ - return board_aoz1380_set_vbus_source_current_limit(port, rp); -} - -/* - * AOZ1380 Interrupt Handler - * - * This device only has a single over current/temperature interrupt. - * TODO(b/141939343) Determine how to clear the interrupt - * TODO(b/142076004) Test this to verify we shut off vbus current - * TODO(b/147359722) Verify correct fault functionality - */ -static void aoz1380_handle_interrupt(int port) -{ - /* - * We can get a false positive on disconnect that we - * had an over current/temperature event when we are no - * longer connected as sink or source. Ignore it if - * that is the case. - */ - if (flags[port] != 0) { - /* - * This is a over current/temperature condition - */ - ppc_prints("Vbus overcurrent/temperature", port); - pd_handle_overcurrent(port); - } else { - /* - * Just in case there is a condition that we will - * continue an interrupt storm, track that we have - * already been here once and will take the other - * path if we do this again before setting the - * sink/source as enabled or disabled again. - */ - AOZ1380_SET_FLAG(port, AOZ1380_FLAGS_INT_ON_DISCONNECT); - } -} - -static void aoz1380_irq_deferred(void) -{ - int i; - uint32_t pending = atomic_clear(&irq_pending); - - for (i = 0; i < board_get_usb_pd_port_count(); i++) - if (BIT(i) & pending) - aoz1380_handle_interrupt(i); -} -DECLARE_DEFERRED(aoz1380_irq_deferred); - -void aoz1380_interrupt(int port) -{ - atomic_or(&irq_pending, BIT(port)); - hook_call_deferred(&aoz1380_irq_deferred_data, 0); -} - -const struct ppc_drv aoz1380_drv = { - .init = &aoz1380_init, - .is_sourcing_vbus = &aoz1380_is_sourcing_vbus, - .vbus_sink_enable = &aoz1380_vbus_sink_enable, - .vbus_source_enable = &aoz1380_vbus_source_enable, - .set_vbus_source_current_limit = - &aoz1380_set_vbus_source_current_limit, -}; diff --git a/driver/ppc/aoz1380.h b/driver/ppc/aoz1380.h deleted file mode 100644 index 94f2b804b7..0000000000 --- a/driver/ppc/aoz1380.h +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright 2019 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. - */ - -/* - * AOZ1380 USB-C Power Path Controller - * - * This is a basic TCPM controlled PPC driver. It could easily be - * renamed and repurposed to be generic, if there are other TCPM - * controlled PPC chips that are similar to the AOZ1380 - */ - -#ifndef __CROS_EC_AOZ1380_H -#define __CROS_EC_AOZ1380_H - -#include "usb_pd_tcpm.h" - -struct ppc_drv; -extern const struct ppc_drv aoz1380_drv; - -/** - * AOZ1380 Set VBus Source Current Limit. - * - * Using this driver requires a board_aoz1380_set_vbus_source_limit - * function due to the lack of programability of this device and - * requirement for hardware specific code to handle setting this limit. - * - * @param port The Type-C port - * @param rp The Type-C RP value - * @return EC_SUCCESS for success, otherwise error - */ -int board_aoz1380_set_vbus_source_current_limit(int port, - enum tcpc_rp_value rp); - - -/** - * Interrupt Handler for the AOZ1380. - * - * @param port: The Type-C port which triggered the interrupt. - */ -void aoz1380_interrupt(int port); - -#endif /* defined(__CROS_EC_AOZ1380_H) */ diff --git a/driver/ppc/nx20p348x.c b/driver/ppc/nx20p348x.c deleted file mode 100644 index a5136bbf23..0000000000 --- a/driver/ppc/nx20p348x.c +++ /dev/null @@ -1,566 +0,0 @@ -/* Copyright 2018 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. - */ - -/* NX20P348x USB-C Power Path Controller */ - -#include "common.h" -#include "console.h" -#include "nx20p348x.h" -#include "gpio.h" -#include "hooks.h" -#include "i2c.h" -#include "system.h" -#include "tcpm/tcpm.h" -#include "usb_charge.h" -#include "usb_pd_tcpm.h" -#include "usb_pd.h" -#include "usbc_ppc.h" -#include "util.h" - -#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) -#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) - -static uint32_t irq_pending; /* Bitmask of ports signaling an interrupt. */ - -#define NX20P348X_DB_EXIT_FAIL_THRESHOLD 10 -static int db_exit_fail_count[CONFIG_USB_PD_PORT_MAX_COUNT]; - -#define NX20P348X_FLAGS_SOURCE_ENABLED BIT(0) -static uint8_t flags[CONFIG_USB_PD_PORT_MAX_COUNT]; - -#if !defined(CONFIG_USBC_PPC_NX20P3481) && !defined(CONFIG_USBC_PPC_NX20P3483) -#error "Either the NX20P3481 or NX20P3483 must be selected" -#endif - -static int read_reg(uint8_t port, int reg, int *regval) -{ - return i2c_read8(ppc_chips[port].i2c_port, - ppc_chips[port].i2c_addr_flags, - reg, - regval); -} - -static int write_reg(uint8_t port, int reg, int regval) -{ - return i2c_write8(ppc_chips[port].i2c_port, - ppc_chips[port].i2c_addr_flags, - reg, - regval); -} - -static int nx20p348x_set_ovp_limit(int port) -{ - int rv; - int reg; - - /* Set VBUS over voltage threshold (OVLO) */ - rv = read_reg(port, NX20P348X_OVLO_THRESHOLD_REG, ®); - if (rv) - return rv; - /* OVLO threshold is 3 bit field */ - reg &= ~NX20P348X_OVLO_THRESHOLD_MASK; - /* Set SNK OVP to 23.0 V */ - reg |= NX20P348X_OVLO_23_0; - rv = write_reg(port, NX20P348X_OVLO_THRESHOLD_REG, reg); - if (rv) - return rv; - - return EC_SUCCESS; -} - -static int nx20p348x_is_sourcing_vbus(int port) -{ - return flags[port] & NX20P348X_FLAGS_SOURCE_ENABLED; -} - -static int nx20p348x_set_vbus_source_current_limit(int port, - enum tcpc_rp_value rp) -{ - int regval; - int status; - - status = read_reg(port, NX20P348X_5V_SRC_OCP_THRESHOLD_REG, ®val); - if (status) - return status; - - regval &= ~NX20P348X_ILIM_MASK; - - /* We need buffer room for all current values. */ - switch (rp) { - case TYPEC_RP_3A0: - regval |= NX20P348X_ILIM_3_200; - break; - - case TYPEC_RP_1A5: - regval |= NX20P348X_ILIM_1_600; - break; - - case TYPEC_RP_USB: - default: - regval |= NX20P348X_ILIM_0_600; - break; - }; - - - return write_reg(port, NX20P348X_5V_SRC_OCP_THRESHOLD_REG, regval); -} - -static int nx20p348x_discharge_vbus(int port, int enable) -{ - int regval; - int newval; - int status; - - status = read_reg(port, NX20P348X_DEVICE_CONTROL_REG, ®val); - if (status) - return status; - - if (enable) - newval = regval | NX20P348X_CTRL_VBUSDIS_EN; - else - newval = regval & ~NX20P348X_CTRL_VBUSDIS_EN; - - if (newval == regval) - return EC_SUCCESS; - - status = write_reg(port, NX20P348X_DEVICE_CONTROL_REG, newval); - if (status) { - CPRINTS("Failed to %s VBUS discharge", - enable ? "enable" : "disable"); - return status; - } - - return EC_SUCCESS; -} - -__maybe_unused static int nx20p3481_vbus_sink_enable(int port, int enable) -{ - int status; - int rv; - int control = enable ? NX20P3481_SWITCH_CONTROL_HVSNK : 0; - - if (enable) { - /* - * VBUS Discharge must be off in sink mode. - */ - rv = nx20p348x_discharge_vbus(port, 0); - if (rv) - return rv; - } - - rv = write_reg(port, NX20P348X_SWITCH_CONTROL_REG, control); - if (rv) - return rv; - - /* - * Read switch status register. The bit definitions for switch control - * and switch status resister are identical, so the control value can be - * compared against the status value. The control switch has a debounce - * (15 msec) before the status will reflect the control command. - */ - msleep(NX20P348X_SWITCH_STATUS_DEBOUNCE_MSEC); - rv = read_reg(port, NX20P348X_SWITCH_STATUS_REG, &status); - if (rv) - return rv; - - return (status & NX20P348X_SWITCH_STATUS_HVSNK) == control ? - EC_SUCCESS : EC_ERROR_UNKNOWN; -} - -__maybe_unused static int nx20p3481_vbus_source_enable(int port, int enable) -{ - int status; - int rv; - uint8_t previous_flags = flags[port]; - int control = enable ? NX20P3481_SWITCH_CONTROL_5VSRC : 0; - - rv = write_reg(port, NX20P348X_SWITCH_CONTROL_REG, control); - if (rv) - return rv; - - /* Cache the anticipated Vbus state */ - if (enable) - flags[port] |= NX20P348X_FLAGS_SOURCE_ENABLED; - else - flags[port] &= ~NX20P348X_FLAGS_SOURCE_ENABLED; - - /* - * Read switch status register. The bit definitions for switch control - * and switch status resister are identical, so the control value can be - * compared against the status value. The control switch has a debounce - * (15 msec) before the status will reflect the control command. - */ - msleep(NX20P348X_SWITCH_STATUS_DEBOUNCE_MSEC); - - if (IS_ENABLED(CONFIG_USBC_PPC_NX20P3481)) { - rv = read_reg(port, NX20P348X_SWITCH_STATUS_REG, &status); - if (rv) { - flags[port] = previous_flags; - return rv; - } - if ((status & NX20P348X_SWITCH_STATUS_MASK) != control) { - flags[port] = previous_flags; - return EC_ERROR_UNKNOWN; - } - } - - return EC_SUCCESS; -} - -__maybe_unused static int nx20p3483_vbus_sink_enable(int port, int enable) -{ - int rv; - - enable = !!enable; - - if (enable) { - /* - * VBUS Discharge must be off in sink mode. - */ - rv = nx20p348x_discharge_vbus(port, 0); - if (rv) - return rv; - } - - /* - * We cannot use an EC GPIO for EN_SNK since an EC reset - * will float the GPIO thus browning out the board (without - * a battery). - */ - rv = tcpm_set_snk_ctrl(port, enable); - if (rv) - return rv; - - for (int i = 0; i < NX20P348X_SWITCH_STATUS_DEBOUNCE_MSEC; ++i) { - int ds; - bool is_sink; - - rv = read_reg(port, NX20P348X_DEVICE_STATUS_REG, &ds); - if (rv != EC_SUCCESS) - return rv; - - is_sink = (ds & NX20P3483_DEVICE_MODE_MASK) == - NX20P3483_MODE_HV_SNK; - if (enable == is_sink) - return EC_SUCCESS; - - msleep(1); - } - - return EC_ERROR_TIMEOUT; -} - -__maybe_unused static int nx20p3483_vbus_source_enable(int port, int enable) -{ - int rv; - - enable = !!enable; - - /* - * For parity's sake, we should not use an EC GPIO for - * EN_SRC since we cannot use it for EN_SNK (for brown - * out reason listed above). - */ - rv = tcpm_set_src_ctrl(port, enable); - if (rv) - return rv; - - /* - * Wait up to NX20P348X_SWITCH_STATUS_DEBOUNCE_MSEC for the status - * to reflect the control command. - */ - - for (int i = 0; i < NX20P348X_SWITCH_STATUS_DEBOUNCE_MSEC; ++i) { - int s; - - rv = read_reg(port, NX20P348X_SWITCH_STATUS_REG, &s); - if (rv != EC_SUCCESS) - return rv; - - if (!!(s & (NX20P348X_SWITCH_STATUS_5VSRC | - NX20P348X_SWITCH_STATUS_HVSRC)) == enable) { - if (enable) - flags[port] |= NX20P348X_FLAGS_SOURCE_ENABLED; - else - flags[port] &= ~NX20P348X_FLAGS_SOURCE_ENABLED; - return EC_SUCCESS; - } - msleep(1); - } - - return EC_ERROR_TIMEOUT; -} - -static int nx20p348x_init(int port) -{ - int reg; - int mask; - int mode; - int rv; - enum tcpc_rp_value initial_current_limit; - - /* Mask interrupts for interrupt 2 register */ - mask = ~NX20P348X_INT2_EN_ERR; - rv = write_reg(port, NX20P348X_INTERRUPT2_MASK_REG, mask); - if (rv) - return rv; - - /* Mask interrupts for interrupt 1 register */ - mask = ~(NX20P348X_INT1_OC_5VSRC | NX20P348X_INT1_SC_5VSRC | - NX20P348X_INT1_RCP_5VSRC | NX20P348X_INT1_DBEXIT_ERR); - if (IS_ENABLED(CONFIG_USBC_PPC_NX20P3481)) { - /* Unmask Fast Role Swap detect interrupt */ - mask &= ~NX20P3481_INT1_FRS_DET; - } - rv = write_reg(port, NX20P348X_INTERRUPT1_MASK_REG, mask); - if (rv) - return rv; - - /* Clear any pending interrupts by reading interrupt registers */ - read_reg(port, NX20P348X_INTERRUPT1_REG, ®); - read_reg(port, NX20P348X_INTERRUPT2_REG, ®); - - /* Get device mode */ - rv = read_reg(port, NX20P348X_DEVICE_STATUS_REG, &mode); - if (rv) - return rv; - - if (IS_ENABLED(CONFIG_USBC_PPC_NX20P3481)) - mode &= NX20P3481_DEVICE_MODE_MASK; - else if (IS_ENABLED(CONFIG_USBC_PPC_NX20P3483)) - mode &= NX20P3483_DEVICE_MODE_MASK; - - /* Check if dead battery mode is active. */ - if (mode == NX20P348X_MODE_DEAD_BATTERY) { - /* - * If in dead battery mode, must enable HV SNK mode prior to - * exiting dead battery mode or VBUS path will get cut off and - * system will lose power. Before DB mode is exited, the device - * mode will not reflect the correct value and therefore the - * return value isn't useful here. - */ - nx20p348x_drv.vbus_sink_enable(port, 1); - - /* Exit dead battery mode. */ - rv = read_reg(port, NX20P348X_DEVICE_CONTROL_REG, ®); - if (rv) - return rv; - reg |= NX20P348X_CTRL_DB_EXIT; - rv = write_reg(port, NX20P348X_DEVICE_CONTROL_REG, reg); - if (rv) - return rv; - } - - /* - * Set VBUS over voltage threshold (OVLO). Note that while the PPC is in - * dead battery mode, OVLO is forced to 6.8V, so this setting must be - * done after dead battery mode is exited. - */ - nx20p348x_set_ovp_limit(port); - - /* Set the Vbus current limit after dead battery mode exit */ -#ifdef CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT - initial_current_limit = CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT; -#else - initial_current_limit = TYPEC_RP_1A5; -#endif - nx20p348x_set_vbus_source_current_limit(port, initial_current_limit); - - /* Restore power-on reset value */ - rv = write_reg(port, NX20P348X_DEVICE_CONTROL_REG, 0); - if (rv) - return rv; - - return EC_SUCCESS; -} - -static void nx20p348x_handle_interrupt(int port) -{ - int reg; - int control_reg; - - /* - * Read interrupt 1 status register. Note, interrupt register is - * automatically cleared by reading. - */ - read_reg(port, NX20P348X_INTERRUPT1_REG, ®); - - /* Check for DBEXIT error */ - if (reg & NX20P348X_INT1_DBEXIT_ERR) { - int mask_reg; - - /* - * This failure is not expected. If for some reason, this - * keeps happening, then log an error and mask the interrupt to - * prevent interrupt floods. - */ - if (++db_exit_fail_count[port] >= - NX20P348X_DB_EXIT_FAIL_THRESHOLD) { - ppc_prints("failed to exit DB mode", port); - if (read_reg(port, NX20P348X_INTERRUPT1_MASK_REG, - &mask_reg)) { - mask_reg |= NX20P348X_INT1_DBEXIT_ERR; - write_reg(port, NX20P348X_INTERRUPT1_MASK_REG, - mask_reg); - } - } - read_reg(port, NX20P348X_DEVICE_CONTROL_REG, &control_reg); - control_reg |= NX20P348X_CTRL_DB_EXIT; - write_reg(port, NX20P348X_DEVICE_CONTROL_REG, control_reg); - /* - * If DB exit mode failed, then the OVP limit setting done in - * the init routine will not be successful. Set the OVP limit - * again here. - */ - nx20p348x_set_ovp_limit(port); - } - - /* Check for 5V OC interrupt */ - if (reg & NX20P348X_INT1_OC_5VSRC) { - ppc_prints("detected Vbus overcurrent!", port); - pd_handle_overcurrent(port); - } - - /* Check for Vbus reverse current protection */ - if (reg & NX20P348X_INT1_RCP_5VSRC) - ppc_prints("detected Vbus reverse current!", port); - - /* Check for Vbus short protection */ - if (reg & NX20P348X_INT1_SC_5VSRC) - ppc_prints("Vbus short detected!", port); - - /* Check for FRS detection */ - if (IS_ENABLED(CONFIG_USBC_PPC_NX20P3481) && - (reg & NX20P3481_INT1_FRS_DET)) { - /* - * TODO(b/113069469): Need to check for CC status and verifiy - * that a sink is attached to continue with FRS. If a sink is - * not attached, then this FRS detect is a false detect which is - * triggered when removing an external charger. If FRS was - * detected by the PPC, then it has automatically enabled the - * 5V SRC mode and this must be undone for a proper detach. - */ - /* Check CC status */ - - /* - * False detect, disable SRC mode which was enabled by - * NX20P3481. - */ - ppc_prints("FRS false detect, disabling SRC mode!", port); - nx20p3481_vbus_source_enable(port, 0); - } - - /* - * Read interrupt 2 status register. Note, interrupt register is - * automatically cleared by reading. - */ - /* - * TODO (b/75272421): Not sure if any of these interrupts - * will be used. Might want to use EN_ERR which tracks when both - * SNK_EN and SRC_EN are set. However, since for the Analogix TCPC - * these values aren't controlled by the EC directly, not sure what - * action if any can be taken. - */ - read_reg(port, NX20P348X_INTERRUPT2_REG, ®); -} - -static void nx20p348x_irq_deferred(void) -{ - int i; - uint32_t pending = atomic_clear(&irq_pending); - - for (i = 0; i < board_get_usb_pd_port_count(); i++) - if (BIT(i) & pending) - nx20p348x_handle_interrupt(i); -} -DECLARE_DEFERRED(nx20p348x_irq_deferred); - -void nx20p348x_interrupt(int port) -{ - atomic_or(&irq_pending, BIT(port)); - hook_call_deferred(&nx20p348x_irq_deferred_data, 0); -} - -#ifdef CONFIG_CMD_PPC_DUMP -static int nx20p348x_dump(int port) -{ - int reg_addr; - int reg; - int rv; - - ccprintf("Port %d NX20P348X registers\n", port); - for (reg_addr = NX20P348X_DEVICE_ID_REG; reg_addr <= - NX20P348X_DEVICE_CONTROL_REG; reg_addr++) { - rv = read_reg(port, reg_addr, ®); - if (rv) { - ccprintf("nx20p: Failed to read register 0x%x\n", - reg_addr); - return rv; - } - ccprintf("[0x%02x]: 0x%02x\n", reg_addr, reg); - - /* Flush every call otherwise buffer may get full */ - cflush(); - } - - return EC_SUCCESS; -} -#endif /* defined(CONFIG_CMD_PPC_DUMP) */ - -/* - * TODO (b/112697473): The NX20P348x PPCs do not support vbus detection or vconn - * generation. However, if a different PPC does support these features and needs - * these config options, then these functions do need to exist. The - * configuration for what each PPC supports should be converted to bits within - * a flags variable that is part of the ppc_config_t struct. - */ -#ifdef CONFIG_USB_PD_VBUS_DETECT_PPC -static int nx20p348x_is_vbus_present(int port) -{ - return EC_ERROR_UNIMPLEMENTED; -} -#endif /* defined(CONFIG_USB_PD_VBUS_DETECT_PPC) */ - -#ifdef CONFIG_USBC_PPC_POLARITY -static int nx20p348x_set_polarity(int port, int polarity) -{ - return EC_ERROR_UNIMPLEMENTED; -} -#endif - -#ifdef CONFIG_USBC_PPC_VCONN -static int nx20p348x_set_vconn(int port, int enable) -{ - return EC_ERROR_UNIMPLEMENTED; -} -#endif - -const struct ppc_drv nx20p348x_drv = { - .init = &nx20p348x_init, - .is_sourcing_vbus = &nx20p348x_is_sourcing_vbus, -#ifdef CONFIG_USBC_PPC_NX20P3481 - .vbus_sink_enable = &nx20p3481_vbus_sink_enable, - .vbus_source_enable = &nx20p3481_vbus_source_enable, -#endif /* CONFIG_USBC_PPC_NX20P3481 */ -#ifdef CONFIG_USBC_PPC_NX20P3483 - .vbus_sink_enable = &nx20p3483_vbus_sink_enable, - .vbus_source_enable = &nx20p3483_vbus_source_enable, -#endif /* CONFIG_USBC_PPC_NX20P3483 */ -#ifdef CONFIG_CMD_PPC_DUMP - .reg_dump = &nx20p348x_dump, -#endif /* defined(CONFIG_CMD_PPC_DUMP) */ - .set_vbus_source_current_limit = - &nx20p348x_set_vbus_source_current_limit, - .discharge_vbus = &nx20p348x_discharge_vbus, -#ifdef CONFIG_USB_PD_VBUS_DETECT_PPC - .is_vbus_present = &nx20p348x_is_vbus_present, -#endif /* defined(CONFIG_USB_PD_VBUS_DETECT_PPC) */ -#ifdef CONFIG_USBC_PPC_POLARITY - .set_polarity = &nx20p348x_set_polarity, -#endif /* defined(CONFIG_USBC_PPC_POLARITY) */ -#ifdef CONFIG_USBC_PPC_VCONN - .set_vconn = &nx20p348x_set_vconn, -#endif /* defined(CONFIG_USBC_PPC_VCONN) */ -}; diff --git a/driver/ppc/nx20p348x.h b/driver/ppc/nx20p348x.h deleted file mode 100644 index 54c6dc40b5..0000000000 --- a/driver/ppc/nx20p348x.h +++ /dev/null @@ -1,132 +0,0 @@ -/* Copyright 2018 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. - */ - -/* NX20P348x Type-C Power Path Controller */ - -#ifndef __CROS_EC_NX20P348X_H -#define __CROS_EC_NX20P348X_H - -#define NX20P3483_ADDR0_FLAGS 0x70 -#define NX20P3483_ADDR1_FLAGS 0x71 -#define NX20P3483_ADDR2_FLAGS 0x72 -#define NX20P3483_ADDR3_FLAGS 0x73 - -#define NX20P3481_ADDR0_FLAGS 0x74 -#define NX20P3481_ADDR1_FLAGS 0x75 -#define NX20P3481_ADDR2_FLAGS 0x76 -#define NX20P3481_ADDR3_FLAGS 0x77 - -/* - * This PPC hard-codes the over voltage protect of Vbus at 6.8V in dead-battery - * mode. If we ever are every going to drop the PD rail, we need to first ensure - * that Vbus is negotiated to below 6.8V otherwise we can lock out Vbus. - */ -#define NX20P348X_SAFE_RESET_VBUS_MV 5000 - -/* NX20P348x register addresses */ -#define NX20P348X_DEVICE_ID_REG 0x00 -#define NX20P348X_DEVICE_STATUS_REG 0x01 -#define NX20P348X_SWITCH_CONTROL_REG 0x02 -#define NX20P348X_SWITCH_STATUS_REG 0x03 -#define NX20P348X_INTERRUPT1_REG 0x04 -#define NX20P348X_INTERRUPT2_REG 0x05 -#define NX20P348X_INTERRUPT1_MASK_REG 0x06 -#define NX20P348X_INTERRUPT2_MASK_REG 0x07 -#define NX20P348X_OVLO_THRESHOLD_REG 0x08 -#define NX20P348X_HV_SRC_OCP_THRESHOLD_REG 0x09 -#define NX20P348X_5V_SRC_OCP_THRESHOLD_REG 0x0A -#define NX20P348X_DEVICE_CONTROL_REG 0x0B - -/* Device Control Register (0x0B) */ -#define NX20P3483_CTRL_FRS_AT BIT(3) -#define NX20P348X_CTRL_DB_EXIT BIT(2) -#define NX20P348X_CTRL_VBUSDIS_EN BIT(1) -#define NX20P348X_CTRL_LDO_SD BIT(0) - -/* Device Status Modes (0x01) */ -#define NX20P3481_DEVICE_MODE_MASK 0x3 -#define NX20P3483_DEVICE_MODE_MASK 0x7 -#define NX20P348X_MODE_DEAD_BATTERY 0 -/* After dead battery, mode values are different between 3481 and 3483 */ -#define NX20P3481_MODE_NORMAL 1 -#define NX20P3481_MODE_FRS 2 -#define NX20P3481_MODE_STANDBY 3 - -#define NX20P3483_MODE_HV_SNK 1 -#define NX20P3483_MODE_5V_SRC 2 -#define NX20P3483_MODE_HV_SRC 3 -#define NX20P3483_MODE_STANDBY 4 - -/* Switch Control Register (0x02) */ -#define NX20P3481_SWITCH_CONTROL_5VSRC BIT(2) -#define NX20P3481_SWITCH_CONTROL_HVSRC BIT(1) -#define NX20P3481_SWITCH_CONTROL_HVSNK BIT(0) - -/* Switch Status Register (0x03) */ -#define NX20P348X_SWITCH_STATUS_5VSRC BIT(2) -#define NX20P348X_SWITCH_STATUS_HVSRC BIT(1) -#define NX20P348X_SWITCH_STATUS_HVSNK BIT(0) -#define NX20P348X_SWITCH_STATUS_DEBOUNCE_MSEC 25 -#define NX20P348X_SWITCH_STATUS_MASK 0x7 - -/* Internal 5V VBUS Switch Current Limit Settings (min) */ -#define NX20P348X_ILIM_MASK 0xF -#define NX20P348X_ILIM_0_400 0 -#define NX20P348X_ILIM_0_600 1 -#define NX20P348X_ILIM_0_800 2 -#define NX20P348X_ILIM_1_000 3 -#define NX20P348X_ILIM_1_200 4 -#define NX20P348X_ILIM_1_400 5 -#define NX20P348X_ILIM_1_600 6 -#define NX20P348X_ILIM_1_800 7 -#define NX20P348X_ILIM_2_000 8 -#define NX20P348X_ILIM_2_200 9 -#define NX20P348X_ILIM_2_400 10 -#define NX20P348X_ILIM_2_600 11 -#define NX20P348X_ILIM_2_800 12 -#define NX20P348X_ILIM_3_000 13 -#define NX20P348X_ILIM_3_200 14 -#define NX20P348X_ILIM_3_400 15 - -/* HV VBUS over voltage threshold settings V_mV*/ -#define NX20P348X_OVLO_THRESHOLD_MASK 0x7 -#define NX20P348X_OVLO_06_0 0 -#define NX20P348X_OVLO_06_8 1 -#define NX20P348X_OVLO_10_0 2 -#define NX20P348X_OVLO_11_5 3 -#define NX20P348X_OVLO_14_0 4 -#define NX20P348X_OVLO_17_0 5 -#define NX20P348X_OVLO_23_0 6 - -/* Interrupt 1 Register Bits (0x04) */ -#define NX20P348X_INT1_DBEXIT_ERR BIT(7) -#define NX20P3481_INT1_FRS_DET BIT(6) -#define NX20P348X_INT1_OV_5VSRC BIT(4) -#define NX20P348X_INT1_RCP_5VSRC BIT(3) -#define NX20P348X_INT1_SC_5VSRC BIT(2) -#define NX20P348X_INT1_OC_5VSRC BIT(1) -#define NX20P348X_INT1_OTP BIT(0) - -/* Interrupt 2 Register Bits (0x05) */ -#define NX20P348X_INT2_EN_ERR BIT(7) -#define NX20P348X_INT2_RCP_HVSNK BIT(6) -#define NX20P348X_INT2_SC_HVSNK BIT(5) -#define NX20P348X_INT2_OV_HVSNK BIT(4) -#define NX20P348X_INT2_RCP_HVSRC BIT(3) -#define NX20P348X_INT2_SC_HVSRC BIT(2) -#define NX20P348X_INT2_OC_HVSRC BIT(1) -#define NX20P348X_INT2_OV_HVSRC BIT(0) - -struct ppc_drv; -extern const struct ppc_drv nx20p348x_drv; - -/** - * Interrupt Handler for the NX20P348x. - * - * @param port: The Type-C port which triggered the interrupt. - */ -void nx20p348x_interrupt(int port); - -#endif /* defined(__CROS_EC_NX20P348X_H) */ diff --git a/driver/ppc/rt1718s.c b/driver/ppc/rt1718s.c deleted file mode 100644 index 96cb789cd0..0000000000 --- a/driver/ppc/rt1718s.c +++ /dev/null @@ -1,237 +0,0 @@ -/* Copyright 2021 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. - */ - -/* Richtek RT1718S USB-C Power Path Controller */ -#include "atomic.h" -#include "common.h" -#include "config.h" -#include "console.h" -#include "driver/ppc/rt1718s.h" -#include "driver/tcpm/tcpci.h" -#include "usbc_ppc.h" -#include "util.h" - - -#define RT1718S_FLAGS_SOURCE_ENABLED BIT(0) -static atomic_t flags[CONFIG_USB_PD_PORT_MAX_COUNT]; - -#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args) - -static int read_reg(uint8_t port, int reg, int *val) -{ - if (reg > 0xFF) { - return i2c_read_offset16( - ppc_chips[port].i2c_port, - ppc_chips[port].i2c_addr_flags, - reg, val, 1); - } else { - return i2c_read8( - ppc_chips[port].i2c_port, - ppc_chips[port].i2c_addr_flags, - reg, val); - } -} - -static int write_reg(uint8_t port, int reg, int val) -{ - if (reg > 0xFF) { - return i2c_write_offset16( - ppc_chips[port].i2c_port, - ppc_chips[port].i2c_addr_flags, - reg, val, 1); - } else { - return i2c_write8( - ppc_chips[port].i2c_port, - ppc_chips[port].i2c_addr_flags, - reg, val); - } -} - -static int update_bits(int port, int reg, int mask, int val) -{ - int reg_val; - - if (mask == 0xFF) - return write_reg(port, reg, val); - - RETURN_ERROR(read_reg(port, reg, ®_val)); - - reg_val &= (~mask); - reg_val |= (mask & val); - return write_reg(port, reg, reg_val); -} - -static int rt1718s_is_sourcing_vbus(int port) -{ - return (flags[port] & RT1718S_FLAGS_SOURCE_ENABLED); -} - -static int rt1718s_vbus_source_enable(int port, int enable) -{ - atomic_t prev_flag; - - if (enable) - prev_flag = atomic_or(&flags[port], - RT1718S_FLAGS_SOURCE_ENABLED); - else - prev_flag = atomic_clear_bits(&flags[port], - RT1718S_FLAGS_SOURCE_ENABLED); - - /* Return if status doesn't change */ - if (!!(prev_flag & RT1718S_FLAGS_SOURCE_ENABLED) == !!enable) - return EC_SUCCESS; - - RETURN_ERROR(tcpm_set_src_ctrl(port, enable)); - -#if defined(CONFIG_USB_CHARGER) && defined(CONFIG_USB_PD_VBUS_DETECT_PPC) - /* - * Since the VBUS state could be changing here, need to wake the - * USB_CHG_N task so that BC 1.2 detection will be triggered. - */ - usb_charger_vbus_change(port, enable); -#endif - - return EC_SUCCESS; -} - -static int rt1718s_vbus_sink_enable(int port, int enable) -{ - return tcpm_set_snk_ctrl(port, enable); -} - -static int rt1718s_discharge_vbus(int port, int enable) -{ - return update_bits(port, - TCPC_REG_POWER_CTRL, - TCPC_REG_POWER_CTRL_FORCE_DISCHARGE, - enable ? 0xFF : 0x00); -} - -#ifdef CONFIG_CMD_PPC_DUMP -static int rt1718s_dump(int port) -{ - for (int i = 0; i <= 0xEF; i++) { - int val = 0; - int rt = read_reg(port, i, &val); - - if (i % 16 == 0) - CPRINTF("%02X: ", i); - if (rt) - CPRINTF("-- "); - else - CPRINTF("%02X ", val); - if (i % 16 == 15) - CPRINTF("\n"); - } - for (int i = 0xF200; i <= 0xF2CF; i++) { - int val = 0; - int rt = read_reg(port, i, &val); - - if (i % 16 == 0) - CPRINTF("%04X: ", i); - if (rt) - CPRINTF("-- "); - else - CPRINTF("%02X ", val); - if (i % 16 == 15) - CPRINTF("\n"); - } - - return EC_SUCCESS; -} -#endif /* defined(CONFIG_CMD_PPC_DUMP) */ - -#ifdef CONFIG_USB_PD_VBUS_DETECT_PPC -static int rt1718s_is_vbus_present(int port) -{ - __maybe_unused static atomic_t vbus_prev[CONFIG_USB_PD_PORT_MAX_COUNT]; - int status, vbus; - - if (read_reg(port, TCPC_REG_POWER_STATUS, &status)) - return 0; - - vbus = !!(status & TCPC_REG_POWER_STATUS_VBUS_PRES); - -#ifdef CONFIG_USB_CHARGER - if (!!(vbus_prev[port] != vbus)) - usb_charger_vbus_change(port, vbus); - - if (vbus) - atomic_or(&vbus_prev[port], 1); - else - atomic_clear(&vbus_prev[port]); -#endif - - return vbus; -} -#endif - -static int rt1718s_init(int port) -{ - atomic_clear(&flags[port]); - - if (IS_ENABLED(CONFIG_USB_PD_FRS_PPC)) - /* Set Rx frs unmasked */ - RETURN_ERROR(update_bits(port, RT1718S_RT_MASK1, - RT1718S_RT_MASK1_M_RX_FRS, - 0xFF)); - - return EC_SUCCESS; -} - -#ifdef CONFIG_USBC_PPC_POLARITY -static int rt1718s_set_polarity(int port, int polarity) -{ - return tcpci_tcpm_set_polarity(port, polarity); -} -#endif - -#ifdef CONFIG_USB_PD_FRS_PPC -static int rt1718s_set_frs_enable(int port, int enable) -{ - /* - * Use write instead of update to save 2 i2c read. - * Assume other bits are at their reset value. - */ - int frs_ctrl2 = 0x10, vbus_ctrl_en = 0x3F; - - if (enable) { - frs_ctrl2 |= RT1718S_FRS_CTRL2_RX_FRS_EN; - frs_ctrl2 |= RT1718S_FRS_CTRL2_VBUS_FRS_EN; - - vbus_ctrl_en |= RT1718S_VBUS_CTRL_EN_GPIO2_VBUS_PATH_EN; - vbus_ctrl_en |= RT1718S_VBUS_CTRL_EN_GPIO1_VBUS_PATH_EN; - } - - RETURN_ERROR(write_reg(port, RT1718S_FRS_CTRL2, frs_ctrl2)); - RETURN_ERROR(write_reg(port, RT1718S_VBUS_CTRL_EN, vbus_ctrl_en)); - return EC_SUCCESS; -} -#endif - -const struct ppc_drv rt1718s_ppc_drv = { - .init = &rt1718s_init, - .is_sourcing_vbus = &rt1718s_is_sourcing_vbus, - .vbus_sink_enable = &rt1718s_vbus_sink_enable, - .vbus_source_enable = &rt1718s_vbus_source_enable, -#ifdef CONFIG_CMD_PPC_DUMP - .reg_dump = &rt1718s_dump, -#endif /* defined(CONFIG_CMD_PPC_DUMP) */ - -#ifdef CONFIG_USB_PD_VBUS_DETECT_PPC - .is_vbus_present = &rt1718s_is_vbus_present, -#endif /* defined(CONFIG_USB_PD_VBUS_DETECT_PPC) */ - .discharge_vbus = &rt1718s_discharge_vbus, -#ifdef CONFIG_USBC_PPC_POLARITY - .set_polarity = &rt1718s_set_polarity, -#endif -#ifdef CONFIG_USBC_PPC_VCONN - .set_vconn = &tcpci_tcpm_set_vconn, -#endif -#ifdef CONFIG_USB_PD_FRS_PPC - .set_frs_enable = rt1718s_set_frs_enable, -#endif -}; diff --git a/driver/ppc/rt1718s.h b/driver/ppc/rt1718s.h deleted file mode 100644 index f692bf3dd4..0000000000 --- a/driver/ppc/rt1718s.h +++ /dev/null @@ -1,17 +0,0 @@ -/* Copyright 2021 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. - */ - -/* Richtek RT1718S Type-C Power Path Controller */ - -#ifndef __CROS_EC_PPC_RT1718S_H -#define __CROS_EC_PPC_RT1718S_H - -#include "driver/tcpm/rt1718s.h" -#include "usbc_ppc.h" - -extern const struct ppc_drv rt1718s_ppc_drv; - -#endif /* defined(__CROS_EC_PPC_RT1718S_H) */ - diff --git a/driver/ppc/sn5s330.c b/driver/ppc/sn5s330.c deleted file mode 100644 index 4abf85cf50..0000000000 --- a/driver/ppc/sn5s330.c +++ /dev/null @@ -1,752 +0,0 @@ -/* Copyright 2017 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. - */ - -/* TI SN5S330 USB-C Power Path Controller */ - -/* - * PP1 : Sourcing power path. - * PP2 : Sinking power path. - */ - -#include "common.h" -#include "console.h" -#include "sn5s330.h" -#include "hooks.h" -#include "i2c.h" -#include "system.h" -#include "timer.h" -#include "usb_charge.h" -#include "usb_pd_tcpm.h" -#include "usb_pd.h" -#include "usbc_ppc.h" -#include "util.h" - -#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) -#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) - -static uint32_t irq_pending; /* Bitmask of ports signaling an interrupt. */ -static int source_enabled[CONFIG_USB_PD_PORT_MAX_COUNT]; - -static int read_reg(uint8_t port, int reg, int *regval) -{ - return i2c_read8(ppc_chips[port].i2c_port, - ppc_chips[port].i2c_addr_flags, - reg, - regval); -} - -static int write_reg(uint8_t port, int reg, int regval) -{ - return i2c_write8(ppc_chips[port].i2c_port, - ppc_chips[port].i2c_addr_flags, - reg, - regval); -} - -static int set_flags(const int port, const int addr, const int flags_to_set) -{ - int val, rv; - - rv = read_reg(port, addr, &val); - if (rv) - return rv; - - val |= flags_to_set; - - return write_reg(port, addr, val); -} - - -static int clr_flags(const int port, const int addr, const int flags_to_clear) -{ - int val, rv; - - rv = read_reg(port, addr, &val); - if (rv) - return rv; - - val &= ~flags_to_clear; - - return write_reg(port, addr, val); -} - -#ifdef CONFIG_CMD_PPC_DUMP -static int sn5s330_dump(int port) -{ - int i; - int data; - const int i2c_port = ppc_chips[port].i2c_port; - const uint16_t i2c_addr_flags = ppc_chips[port].i2c_addr_flags; - - /* Flush after every set otherwise console buffer may get full. */ - - for (i = SN5S330_FUNC_SET1; i <= SN5S330_FUNC_SET12; i++) { - i2c_read8(i2c_port, i2c_addr_flags, i, &data); - ccprintf("FUNC_SET%d [%02Xh] = 0x%02x\n", - i - SN5S330_FUNC_SET1 + 1, - i, - data); - } - - cflush(); - - for (i = SN5S330_INT_STATUS_REG1; i <= SN5S330_INT_STATUS_REG4; i++) { - i2c_read8(i2c_port, i2c_addr_flags, i, &data); - ccprintf("INT_STATUS_REG%d [%02Xh] = 0x%02x\n", - i - SN5S330_INT_STATUS_REG1 + 1, - i, - data); - } - - cflush(); - - for (i = SN5S330_INT_TRIP_RISE_REG1; i <= SN5S330_INT_TRIP_RISE_REG3; - i++) { - i2c_read8(i2c_port, i2c_addr_flags, i, &data); - ccprintf("INT_TRIP_RISE_REG%d [%02Xh] = 0x%02x\n", - i - SN5S330_INT_TRIP_RISE_REG1 + 1, - i, - data); - } - - cflush(); - - for (i = SN5S330_INT_TRIP_FALL_REG1; i <= SN5S330_INT_TRIP_FALL_REG3; - i++) { - i2c_read8(i2c_port, i2c_addr_flags, i, &data); - ccprintf("INT_TRIP_FALL_REG%d [%02Xh] = 0x%02x\n", - i - SN5S330_INT_TRIP_FALL_REG1 + 1, - i, - data); - } - - cflush(); - - for (i = SN5S330_INT_MASK_RISE_REG1; i <= SN5S330_INT_MASK_RISE_REG3; - i++) { - i2c_read8(i2c_port, i2c_addr_flags, i, &data); - ccprintf("INT_MASK_RISE_REG%d [%02Xh] = 0x%02x\n", - i - SN5S330_INT_MASK_RISE_REG1 + 1, - i, - data); - } - - cflush(); - - for (i = SN5S330_INT_MASK_FALL_REG1; i <= SN5S330_INT_MASK_FALL_REG3; - i++) { - i2c_read8(i2c_port, i2c_addr_flags, i, &data); - ccprintf("INT_MASK_FALL_REG%d [%02Xh] = 0x%02x\n", - i - SN5S330_INT_MASK_FALL_REG1 + 1, - i, - data); - } - - cflush(); - - return EC_SUCCESS; -} -#endif /* defined(CONFIG_CMD_PPC_DUMP) */ - -static int sn5s330_pp_fet_enable(uint8_t port, enum sn5s330_pp_idx pp, - int enable) -{ - int status; - int pp_bit; - - if (pp == SN5S330_PP1) - pp_bit = SN5S330_PP1_EN; - else if (pp == SN5S330_PP2) - pp_bit = SN5S330_PP2_EN; - else - return EC_ERROR_INVAL; - - status = enable ? set_flags(port, SN5S330_FUNC_SET3, pp_bit) - : clr_flags(port, SN5S330_FUNC_SET3, pp_bit); - - if (status) { - ppc_prints("Failed to set FUNC_SET3!", port); - return status; - } - - if (pp == SN5S330_PP1) - source_enabled[port] = enable; - - return EC_SUCCESS; -} - -static int sn5s330_init(int port) -{ - int regval; - int status; - int retries; - int reg; - const int i2c_port = ppc_chips[port].i2c_port; - const uint16_t i2c_addr_flags = ppc_chips[port].i2c_addr_flags; - -#ifdef CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT - /* Set the sourcing current limit value. */ - switch (CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT) { - case TYPEC_RP_3A0: - /* Set current limit to ~3A. */ - regval = SN5S330_ILIM_3_06; - break; - - case TYPEC_RP_1A5: - default: - /* Set current limit to ~1.5A. */ - regval = SN5S330_ILIM_1_62; - break; - } -#else /* !defined(CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT) */ - /* Default SRC current limit to ~1.5A. */ - regval = SN5S330_ILIM_1_62; -#endif /* defined(CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT) */ - - /* - * It seems that sometimes setting the FUNC_SET1 register fails - * initially. Therefore, we'll retry a couple of times. - */ - retries = 0; - do { - status = i2c_write8(i2c_port, i2c_addr_flags, - SN5S330_FUNC_SET1, regval); - if (status) { - ppc_prints("Failed to set FUNC_SET1! Retrying..", - port); - retries++; - msleep(1); - } else { - break; - } - } while (retries < 10); - - /* Set Vbus OVP threshold to ~22.325V. */ - regval = 0x37; - status = i2c_write8(i2c_port, i2c_addr_flags, - SN5S330_FUNC_SET5, regval); - if (status) { - ppc_prints("Failed to set FUNC_SET5!", port); - return status; - } - - /* Set Vbus UVP threshold to ~2.75V. */ - status = i2c_read8(i2c_port, i2c_addr_flags, - SN5S330_FUNC_SET6, ®val); - if (status) { - ppc_prints("Failed to read FUNC_SET6!", port); - return status; - } - regval &= ~0x3F; - regval |= 1; - status = i2c_write8(i2c_port, i2c_addr_flags, - SN5S330_FUNC_SET6, regval); - if (status) { - ppc_prints("Failed to write FUNC_SET6!", port); - return status; - } - - /* Enable SBU Fets and set PP2 current limit to ~3A. */ - regval = SN5S330_SBU_EN | 0x8; - status = i2c_write8(i2c_port, i2c_addr_flags, - SN5S330_FUNC_SET2, regval); - if (status) { - ppc_prints("Failed to set FUNC_SET2!", port); - return status; - } - - /* - * Indicate we are using PP2 configuration 2 and enable OVP comparator - * for CC lines. - * - * Also, turn off under-voltage protection for incoming Vbus as it would - * prevent us from enabling SNK path before we hibernate the ec. We - * need to enable the SNK path so USB power will assert ACOK and wake - * the EC up went inserting USB power. We always turn off under-voltage - * protection because the battery charger will boost the voltage up - * to the needed battery voltage either way (and it will have its own - * low voltage protection). - */ - regval = SN5S330_OVP_EN_CC | SN5S330_PP2_CONFIG | SN5S330_CONFIG_UVP; - status = i2c_write8(i2c_port, i2c_addr_flags, - SN5S330_FUNC_SET9, regval); - if (status) { - ppc_prints("Failed to set FUNC_SET9!", port); - return status; - } - - /* - * Set analog current limit delay to 200 us for PP1, - * set 1000 us for PP2 for compatibility. - */ - regval = (PPX_ILIM_DEGLITCH_0_US_200 << 3) | - PPX_ILIM_DEGLITCH_0_US_1000; - status = i2c_write8(i2c_port, i2c_addr_flags, SN5S330_FUNC_SET11, - regval); - if (status) { - ppc_prints("Failed to set FUNC_SET11", port); - return status; - } - -#ifdef CONFIG_USBC_PPC_VCONN - /* - * Set the deglitch timeout on the Vconn current limit to 640us. This - * improves compatibility with some USB C -> HDMI devices versus the - * reset default (20 us). - */ - regval = 0; - status = i2c_read8(i2c_port, i2c_addr_flags, - SN5S330_FUNC_SET8, ®val); - if (status) { - ppc_prints("Failed to read FUNC_SET8!", port); - return status; - } - regval &= ~SN5S330_VCONN_DEGLITCH_MASK; - regval |= SN5S330_VCONN_DEGLITCH_640_US; - status = i2c_write8(i2c_port, i2c_addr_flags, - SN5S330_FUNC_SET8, regval); - if (status) { - ppc_prints("Failed to set FUNC_SET8!", port); - return status; - } -#endif /* CONFIG_USBC_PPC_VCONN */ - - /* - * Turn off dead battery resistors, turn on CC FETs, and set the higher - * of the two VCONN current limits (min 0.6A). Many VCONN accessories - * trip the default current limit of min 0.35A. - */ - status = set_flags(port, SN5S330_FUNC_SET4, - SN5S330_CC_EN | SN5S330_VCONN_ILIM_SEL); - if (status) { - ppc_prints("Failed to set FUNC_SET4!", port); - return status; - } - - /* Set ideal diode mode for both PP1 and PP2. */ - status = set_flags(port, SN5S330_FUNC_SET3, - SN5S330_SET_RCP_MODE_PP1 | SN5S330_SET_RCP_MODE_PP2); - if (status) { - ppc_prints("Failed to set FUNC_SET3!", port); - return status; - } - - /* Turn off PP1 FET. */ - status = sn5s330_pp_fet_enable(port, SN5S330_PP1, 0); - if (status) { - ppc_prints("Failed to turn off PP1 FET!", port); - } - - /* - * Don't proceed with the rest of initialization if we're sysjumping. - * We would have already done this before. - */ - if (system_jumped_late()) - return EC_SUCCESS; - - /* - * Clear the digital reset bit, and mask off and clear vSafe0V - * interrupts. Leave the dead battery mode bit unchanged since it - * is checked below. - */ - regval = SN5S330_DIG_RES | SN5S330_VSAFE0V_MASK; - status = i2c_write8(i2c_port, i2c_addr_flags, - SN5S330_INT_STATUS_REG4, regval); - if (status) { - ppc_prints("Failed to write INT_STATUS_REG4!", port); - return status; - } - - /* - * Before turning on the PP2 FET, mask off all unwanted interrupts and - * then clear all pending interrupts. - * - * TODO(aaboagye): Unmask fast-role swap events once fast-role swap is - * implemented in the PD stack. - */ - - /* Enable PP1 overcurrent interrupts. */ - regval = ~SN5S330_ILIM_PP1_MASK; - status = i2c_write8(i2c_port, i2c_addr_flags, - SN5S330_INT_MASK_RISE_REG1, regval); - if (status) { - ppc_prints("Failed to write INT_MASK_RISE1!", port); - return status; - } - - status = i2c_write8(i2c_port, i2c_addr_flags, - SN5S330_INT_MASK_FALL_REG1, 0xFF); - if (status) { - ppc_prints("Failed to write INT_MASK_FALL1!", port); - return status; - } - - /* Enable VCONN overcurrent and CC1/CC2 overvoltage interrupts. */ - regval = ~(SN5S330_VCONN_ILIM | SN5S330_CC1_CON | SN5S330_CC2_CON); - status = i2c_write8(i2c_port, i2c_addr_flags, - SN5S330_INT_MASK_RISE_REG2, regval); - if (status) { - ppc_prints("Failed to write INT_MASK_RISE2!", port); - return status; - } - - status = i2c_write8(i2c_port, i2c_addr_flags, - SN5S330_INT_MASK_FALL_REG2, 0xFF); - if (status) { - ppc_prints("Failed to write INT_MASK_FALL2!", port); - return status; - } - -#if defined(CONFIG_USB_PD_VBUS_DETECT_PPC) && defined(CONFIG_USB_CHARGER) - /* If PPC is being used to detect VBUS, enable VBUS interrupts. */ - regval = ~SN5S330_VBUS_GOOD_MASK; -#else - regval = 0xFF; -#endif /* CONFIG_USB_PD_VBUS_DETECT_PPC && CONFIG_USB_CHARGER */ - - status = i2c_write8(i2c_port, i2c_addr_flags, - SN5S330_INT_MASK_RISE_REG3, regval); - if (status) { - ppc_prints("Failed to write INT_MASK_RISE3!", port); - return status; - } - - status = i2c_write8(i2c_port, i2c_addr_flags, - SN5S330_INT_MASK_FALL_REG3, regval); - if (status) { - ppc_prints("Failed to write INT_MASK_FALL3!", port); - return status; - } - - /* Now clear any pending interrupts. */ - for (reg = SN5S330_INT_TRIP_RISE_REG1; - reg <= SN5S330_INT_TRIP_FALL_REG3; - reg++) { - status = i2c_write8(i2c_port, i2c_addr_flags, - reg, 0xFF); - if (status) { - CPRINTS("ppc p%d: Failed to write reg 0x%2x!", - port, reg); - return status; - } - } - - - /* - * For PP2, check to see if we booted in dead battery mode. If we - * booted in dead battery mode, the PP2 FET will already be enabled. - */ - status = i2c_read8(i2c_port, i2c_addr_flags, - SN5S330_INT_STATUS_REG4, ®val); - if (status) { - ppc_prints("Failed to read INT_STATUS_REG4!", port); - return status; - } - - if (regval & SN5S330_DB_BOOT) { - /* - * Clear the bit by writing 1 and keep vSafe0V_MASK - * unchanged. - */ - i2c_write8(i2c_port, i2c_addr_flags, - SN5S330_INT_STATUS_REG4, regval); - - /* Turn on PP2 FET. */ - status = sn5s330_pp_fet_enable(port, SN5S330_PP2, 1); - if (status) { - ppc_prints("Failed to turn on PP2 FET!", port); - return status; - } - } - - return EC_SUCCESS; -} - -#ifdef CONFIG_USB_PD_VBUS_DETECT_PPC -static int sn5s330_is_vbus_present(int port) -{ - int regval; - int rv; - - rv = read_reg(port, SN5S330_INT_STATUS_REG3, ®val); - if (rv) { - ppc_err_prints("VBUS present error", port, rv); - return 0; - } - - return !!(regval & SN5S330_VBUS_GOOD); -} -#endif /* defined(CONFIG_USB_PD_VBUS_DETECT_PPC) */ - -static int sn5s330_is_sourcing_vbus(int port) -{ - return source_enabled[port]; -} - -#ifdef CONFIG_USBC_PPC_POLARITY -static int sn5s330_set_polarity(int port, int polarity) -{ - if (polarity) - /* CC2 active. */ - return set_flags(port, SN5S330_FUNC_SET4, SN5S330_CC_POLARITY); - else - /* CC1 active. */ - return clr_flags(port, SN5S330_FUNC_SET4, SN5S330_CC_POLARITY); -} -#endif - -static int sn5s330_set_vbus_source_current_limit(int port, - enum tcpc_rp_value rp) -{ - int regval; - int status; - - status = read_reg(port, SN5S330_FUNC_SET1, ®val); - if (status) - return status; - - /* - * Note that we chose the lowest current limit setting that is just - * above indicated Rp value. This is because these are minimum values - * and we must be able to provide the current that we advertise. - */ - regval &= ~0x1F; /* The current limit settings are 4:0. */ - switch (rp) { - case TYPEC_RP_3A0: - regval |= SN5S330_ILIM_3_06; - break; - - case TYPEC_RP_1A5: - regval |= SN5S330_ILIM_1_62; - break; - - case TYPEC_RP_USB: - default: - regval |= SN5S330_ILIM_0_63; - break; - }; - - status = write_reg(port, SN5S330_FUNC_SET1, regval); - - return status; -} - -static int sn5s330_discharge_vbus(int port, int enable) -{ - int status = enable ? set_flags(port, SN5S330_FUNC_SET3, - SN5S330_VBUS_DISCH_EN) - : clr_flags(port, SN5S330_FUNC_SET3, - SN5S330_VBUS_DISCH_EN); - - if (status) { - CPRINTS("ppc p%d: Failed to %s vbus discharge", - port, enable ? "enable" : "disable"); - return status; - } - - return EC_SUCCESS; -} - -static int sn5s330_enter_low_power_mode(int port) -{ - int rv; - - /* Turn off both SRC and SNK FETs */ - rv = clr_flags(port, SN5S330_FUNC_SET3, - SN5S330_PP1_EN | SN5S330_PP2_EN); - - if (rv) { - ppc_err_prints("Could not disable both FETS", port, rv); - return rv; - } - - /* Turn off Vconn power */ - rv = clr_flags(port, SN5S330_FUNC_SET4, SN5S330_VCONN_EN); - - if (rv) { - ppc_err_prints("Could not disable Vconn", port, rv); - return rv; - } - - /* Turn off SBU path */ - rv = clr_flags(port, SN5S330_FUNC_SET2, SN5S330_SBU_EN); - - if (rv) { - ppc_err_prints("Could not disable SBU path", port, rv); - return rv; - } - - /* - * Turn off the Over Voltage Protection circuits. Needs to happen after - * FETs are disabled, otherwise OVP can automatically turned back on. - * Since FETs are off, any over voltage does not make it to the board - * side of the PPC. - */ - rv = clr_flags(port, SN5S330_FUNC_SET9, - SN5S330_FORCE_OVP_EN_SBU | SN5S330_FORCE_ON_VBUS_OVP | - SN5S330_FORCE_ON_VBUS_UVP); - - if (rv) { - ppc_err_prints("Could not disable OVP circuit", port, rv); - return rv; - } - - return EC_SUCCESS; -} - -#ifdef CONFIG_USBC_PPC_VCONN -static int sn5s330_set_vconn(int port, int enable) -{ - int regval; - int status; - - status = read_reg(port, SN5S330_FUNC_SET4, ®val); - if (status) - return status; - - if (enable) - regval |= SN5S330_VCONN_EN; - else - regval &= ~SN5S330_VCONN_EN; - - return write_reg(port, SN5S330_FUNC_SET4, regval); -} -#endif - -static int sn5s330_vbus_sink_enable(int port, int enable) -{ - return sn5s330_pp_fet_enable(port, SN5S330_PP2, !!enable); -} - -static int sn5s330_vbus_source_enable(int port, int enable) -{ - return sn5s330_pp_fet_enable(port, SN5S330_PP1, !!enable); -} - -#ifdef CONFIG_USBC_PPC_SBU -static int sn5s330_set_sbu(int port, int enable) -{ - int rv; - - if (enable) - rv = set_flags(port, SN5S330_FUNC_SET2, SN5S330_SBU_EN); - else - rv = clr_flags(port, SN5S330_FUNC_SET2, SN5S330_SBU_EN); - - return rv; -} -#endif /* CONFIG_USBC_PPC_SBU */ - -static void sn5s330_handle_interrupt(int port) -{ - int attempt = 0; - - /* - * SN5S330's /INT pin is level, so process interrupts until it - * deasserts if the chip has a dedicated interrupt pin. - */ -#ifdef CONFIG_USBC_PPC_DEDICATED_INT - while (ppc_get_alert_status(port)) -#endif - { - int rise = 0; - int fall = 0; - - attempt++; - - if (attempt > 1) - ppc_prints("Could not clear interrupts on first " - "try, retrying", port); - - read_reg(port, SN5S330_INT_TRIP_RISE_REG1, &rise); - read_reg(port, SN5S330_INT_TRIP_FALL_REG1, &fall); - - /* Notify the system about the overcurrent event. */ - if (rise & SN5S330_ILIM_PP1_MASK) - pd_handle_overcurrent(port); - - /* Clear the interrupt sources. */ - write_reg(port, SN5S330_INT_TRIP_RISE_REG1, rise); - write_reg(port, SN5S330_INT_TRIP_FALL_REG1, fall); - - read_reg(port, SN5S330_INT_TRIP_RISE_REG2, &rise); - read_reg(port, SN5S330_INT_TRIP_FALL_REG2, &fall); - - /* - * VCONN may be latched off due to an overcurrent. Indicate - * when the VCONN overcurrent happens. - */ - if (rise & SN5S330_VCONN_ILIM) - ppc_prints("VCONN OC!", port); - - /* Notify the system about the CC overvoltage event. */ - if (rise & SN5S330_CC1_CON || rise & SN5S330_CC2_CON) { - ppc_prints("CC OV!", port); - pd_handle_cc_overvoltage(port); - } - - /* Clear the interrupt sources. */ - write_reg(port, SN5S330_INT_TRIP_RISE_REG2, rise); - write_reg(port, SN5S330_INT_TRIP_FALL_REG2, fall); - -#if defined(CONFIG_USB_PD_VBUS_DETECT_PPC) && defined(CONFIG_USB_CHARGER) - read_reg(port, SN5S330_INT_TRIP_RISE_REG3, &rise); - read_reg(port, SN5S330_INT_TRIP_FALL_REG3, &fall); - - /* Inform other modules about VBUS level */ - if (rise & SN5S330_VBUS_GOOD_MASK - || fall & SN5S330_VBUS_GOOD_MASK) - usb_charger_vbus_change(port, - sn5s330_is_vbus_present(port)); - - /* Clear the interrupt sources. */ - write_reg(port, SN5S330_INT_TRIP_RISE_REG3, rise); - write_reg(port, SN5S330_INT_TRIP_FALL_REG3, fall); -#endif /* CONFIG_USB_PD_VBUS_DETECT_PPC && CONFIG_USB_CHARGER */ - - } -} - -static void sn5s330_irq_deferred(void) -{ - int i; - uint32_t pending = atomic_clear(&irq_pending); - - for (i = 0; i < board_get_usb_pd_port_count(); i++) - if (BIT(i) & pending) - sn5s330_handle_interrupt(i); -} -DECLARE_DEFERRED(sn5s330_irq_deferred); - -void sn5s330_interrupt(int port) -{ - atomic_or(&irq_pending, BIT(port)); - hook_call_deferred(&sn5s330_irq_deferred_data, 0); -} - -const struct ppc_drv sn5s330_drv = { - .init = &sn5s330_init, - .is_sourcing_vbus = &sn5s330_is_sourcing_vbus, - .vbus_sink_enable = &sn5s330_vbus_sink_enable, - .vbus_source_enable = &sn5s330_vbus_source_enable, - .set_vbus_source_current_limit = &sn5s330_set_vbus_source_current_limit, - .discharge_vbus = &sn5s330_discharge_vbus, - .enter_low_power_mode = &sn5s330_enter_low_power_mode, -#ifdef CONFIG_CMD_PPC_DUMP - .reg_dump = &sn5s330_dump, -#endif -#ifdef CONFIG_USB_PD_VBUS_DETECT_PPC - .is_vbus_present = &sn5s330_is_vbus_present, -#endif -#ifdef CONFIG_USBC_PPC_POLARITY - .set_polarity = &sn5s330_set_polarity, -#endif -#ifdef CONFIG_USBC_PPC_SBU - .set_sbu = &sn5s330_set_sbu, -#endif /* defined(CONFIG_USBC_PPC_SBU) */ -#ifdef CONFIG_USBC_PPC_VCONN - .set_vconn = &sn5s330_set_vconn, -#endif -}; diff --git a/driver/ppc/sn5s330.h b/driver/ppc/sn5s330.h deleted file mode 100644 index f94a3e8e10..0000000000 --- a/driver/ppc/sn5s330.h +++ /dev/null @@ -1,161 +0,0 @@ -/* Copyright 2017 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. - */ - -/* TI SN5S330 Type-C Power Path Controller */ - -#ifndef __CROS_EC_SN5S330_H -#define __CROS_EC_SN5S330_H - -#include "common.h" - -#include "driver/ppc/sn5s330_public.h" - -struct sn5s330_config { - uint8_t i2c_port; - uint8_t i2c_addr_flags; -}; - -extern const struct sn5s330_config sn5s330_chips[]; -extern const unsigned int sn5s330_cnt; - -/* Power Path Indices */ -enum sn5s330_pp_idx { - SN5S330_PP1, - SN5S330_PP2, - SN5S330_PP_COUNT, -}; - -#define SN5S330_FUNC_SET1 0x50 -#define SN5S330_FUNC_SET2 0x51 -#define SN5S330_FUNC_SET3 0x52 -#define SN5S330_FUNC_SET4 0x53 -#define SN5S330_FUNC_SET5 0x54 -#define SN5S330_FUNC_SET6 0x55 -#define SN5S330_FUNC_SET7 0x56 -#define SN5S330_FUNC_SET8 0x57 -#define SN5S330_FUNC_SET9 0x58 -#define SN5S330_FUNC_SET10 0x59 -#define SN5S330_FUNC_SET11 0x5A -#define SN5S330_FUNC_SET12 0x5B - -#define SN5S330_INT_STATUS_REG1 0x2F -#define SN5S330_INT_STATUS_REG2 0x30 -#define SN5S330_INT_STATUS_REG3 0x31 -#define SN5S330_INT_STATUS_REG4 0x32 - -#define SN5S330_INT_TRIP_RISE_REG1 0x20 -#define SN5S330_INT_TRIP_RISE_REG2 0x21 -#define SN5S330_INT_TRIP_RISE_REG3 0x22 -#define SN5S330_INT_TRIP_FALL_REG1 0x23 -#define SN5S330_INT_TRIP_FALL_REG2 0x24 -#define SN5S330_INT_TRIP_FALL_REG3 0x25 - -#define SN5S330_INT_MASK_RISE_REG1 0x26 -#define SN5S330_INT_MASK_RISE_REG2 0x27 -#define SN5S330_INT_MASK_RISE_REG3 0x28 -#define SN5S330_INT_MASK_FALL_REG1 0x29 -#define SN5S330_INT_MASK_FALL_REG2 0x2A -#define SN5S330_INT_MASK_FALL_REG3 0x2B - -#define PPX_ILIM_DEGLITCH_0_US_20 0x1 -#define PPX_ILIM_DEGLITCH_0_US_50 0x2 -#define PPX_ILIM_DEGLITCH_0_US_100 0x3 -#define PPX_ILIM_DEGLITCH_0_US_200 0x4 -#define PPX_ILIM_DEGLITCH_0_US_1000 0x5 -#define PPX_ILIM_DEGLITCH_0_US_2000 0x6 -#define PPX_ILIM_DEGLITCH_0_US_10000 0x7 - -/* Internal VBUS Switch Current Limit Settings (min) */ -#define SN5S330_ILIM_0_35 0 -#define SN5S330_ILIM_0_63 1 -#define SN5S330_ILIM_0_90 2 -#define SN5S330_ILIM_1_14 3 -#define SN5S330_ILIM_1_38 4 -#define SN5S330_ILIM_1_62 5 -#define SN5S330_ILIM_1_86 6 -#define SN5S330_ILIM_2_10 7 -#define SN5S330_ILIM_2_34 8 -#define SN5S330_ILIM_2_58 9 -#define SN5S330_ILIM_2_82 10 -#define SN5S330_ILIM_3_06 11 -#define SN5S330_ILIM_3_30 12 - -/* FUNC_SET_2 */ -#define SN5S330_SBU_EN BIT(4) - -/* FUNC_SET_3 */ -#define SN5S330_PP1_EN BIT(0) -#define SN5S330_PP2_EN BIT(1) -#define SN5S330_VBUS_DISCH_EN BIT(2) -#define SN5S330_SET_RCP_MODE_PP1 BIT(5) -#define SN5S330_SET_RCP_MODE_PP2 BIT(6) - -/* FUNC_SET_4 */ -#define SN5S330_VCONN_EN BIT(0) -#define SN5S330_CC_POLARITY BIT(1) -#define SN5S330_CC_EN BIT(4) -#define SN5S330_VCONN_ILIM_SEL BIT(5) - -/* FUNC_SET_8 */ -#define SN5S330_VCONN_DEGLITCH_MASK (3 << 6) -#define SN5S330_VCONN_DEGLITCH_63_US (0 << 6) -#define SN5S330_VCONN_DEGLITCH_125_US BIT(6) -#define SN5S330_VCONN_DEGLITCH_640_US (2 << 6) -#define SN5S330_VCONN_DEGLITCH_1280_US (3 << 6) - -/* FUNC_SET_9 */ -#define SN5S330_FORCE_OVP_EN_SBU BIT(1) -#define SN5S330_PP2_CONFIG BIT(2) -#define SN5S330_OVP_EN_CC BIT(4) -#define SN5S330_CONFIG_UVP BIT(5) -#define SN5S330_FORCE_ON_VBUS_OVP BIT(6) -#define SN5S330_FORCE_ON_VBUS_UVP BIT(7) - -/* INT_STATUS_REG3 */ -#define SN5S330_VBUS_GOOD BIT(0) - -/* INT_STATUS_REG4 */ -#define SN5S330_DIG_RES BIT(0) -#define SN5S330_DB_BOOT BIT(1) -#define SN5S330_VSAFE0V_STAT BIT(2) -#define SN5S330_VSAFE0V_MASK BIT(3) - -/* - * INT_MASK_RISE/FALL_EDGE_1 - * - * The ILIM_PP1 bit indicates an overcurrent condition when sourcing on power - * path 1. For rising edge registers, this indicates an overcurrent has - * occured; similarly for falling edge, it means the overcurrent condition is no - * longer present. - */ -#define SN5S330_ILIM_PP1_MASK BIT(4) - -/* - * INT_MASK_RISE/FALL_EDGE2 - * - * The VCONN_ILIM bit indicates an overcurrent condition on VCONN. By default, - * VCONN will be latched off. - */ -#define SN5S330_VCONN_ILIM (1 << 1) - -/* - * INT_MASK_RISE/FALL_EDGE2 - * - * The OV_CC1_CON/OV_CC2_CON bit indicates an over-voltage occurred on - * C_CC1/C_CC2. - */ -#define SN5S330_CC1_CON (1 << 2) -#define SN5S330_CC2_CON (1 << 3) - -/* - * INT_MASK_RISE/FALL_EDGE_3 - * - * The VBUS_GOOD bit indicates VBUS has increased beyond a 4.0V threshold. - * For rising edge registers, this indicates VBUS has risen above 4.0V. - * For falling edge registers, this indicates VBUS has fallen below 4.0V. - */ -#define SN5S330_VBUS_GOOD_MASK BIT(0) - -#endif /* defined(__CROS_EC_SN5S330_H) */ diff --git a/driver/ppc/syv682x.c b/driver/ppc/syv682x.c deleted file mode 100644 index 0e49abdf6a..0000000000 --- a/driver/ppc/syv682x.c +++ /dev/null @@ -1,837 +0,0 @@ -/* Copyright 2018 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. - */ - -/* Silergy SYV682x USB-C Power Path Controller */ -#include "atomic.h" -#include "common.h" -#include "config.h" -#include "console.h" -#include "syv682x.h" -#include "hooks.h" -#include "i2c.h" -#include "system.h" -#include "timer.h" -#include "usb_charge.h" -#include "usb_pd_tcpm.h" -#include "usbc_ppc.h" -#include "usb_pd.h" -#include "util.h" - -#define SYV682X_FLAGS_SOURCE_ENABLED BIT(0) -#define SYV682X_FLAGS_SINK_ENABLED BIT(1) -/* 0 -> CC1, 1 -> CC2 */ -#define SYV682X_FLAGS_CC_POLARITY BIT(2) -#define SYV682X_FLAGS_VBUS_PRESENT BIT(3) -#define SYV682X_FLAGS_TSD BIT(4) -#define SYV682X_FLAGS_OVP BIT(5) -#define SYV682X_FLAGS_5V_OC BIT(6) -#define SYV682X_FLAGS_FRS BIT(7) -#define SYV682X_FLAGS_VCONN_OCP BIT(8) - -static uint32_t irq_pending; /* Bitmask of ports signaling an interrupt. */ -static uint32_t flags[CONFIG_USB_PD_PORT_MAX_COUNT]; -/* Running count of sink ocp events */ -static uint32_t sink_ocp_count[CONFIG_USB_PD_PORT_MAX_COUNT]; -static timestamp_t vbus_oc_timer[CONFIG_USB_PD_PORT_MAX_COUNT]; -static timestamp_t vconn_oc_timer[CONFIG_USB_PD_PORT_MAX_COUNT]; - -#define SYV682X_VBUS_DET_THRESH_MV 4000 -/* Longest time that can be programmed in DSG_TIME field */ -#define SYV682X_MAX_VBUS_DISCHARGE_TIME_MS 400 -/* - * Delay between checks when polling the interrupt registers. Must be longer - * than the HW deglitch on OC (10ms) - */ -#define INTERRUPT_DELAY_MS 15 -/* Deglitch in ms of sourcing overcurrent detection */ -#define SOURCE_OC_DEGLITCH_MS 100 -#define VCONN_OC_DEGLITCH_MS 100 -/* Max. number of OC events allowed before disabling port */ -#define OCP_COUNT_LIMIT 3 - -#if INTERRUPT_DELAY_MS <= SYV682X_HW_OC_DEGLITCH_MS -#error "INTERRUPT_DELAY_MS should be greater than SYV682X_HW_OC_DEGLITCH_MS" -#endif - -#if SOURCE_OC_DEGLITCH_MS < INTERRUPT_DELAY_MS -#error "SOURCE_OC_DEGLITCH_MS should be at least INTERRUPT_DELAY_MS" -#endif - -/* When FRS is enabled, the VCONN line isn't passed through to the TCPC */ -#if defined(CONFIG_USB_PD_FRS_PPC) && defined(CONFIG_USBC_VCONN) && \ - !defined(CONFIG_USBC_PPC_VCONN) -#error "if FRS is enabled on the SYV682X, VCONN must be supplied by the PPC " -"instead of the TCPC" -#endif - -#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) - -static int syv682x_vbus_sink_enable(int port, int enable); - -static int syv682x_init(int port); - -static void syv682x_interrupt_delayed(int port, int delay); - -static int read_reg(uint8_t port, int reg, int *regval) -{ - return i2c_read8(ppc_chips[port].i2c_port, - ppc_chips[port].i2c_addr_flags, - reg, - regval); -} - -#ifdef CONFIG_USBC_PPC_SYV682C -__overridable int syv682x_board_is_syv682c(int port) -{ - return true; -} -#endif - -/* - * During channel transition or discharge, the SYV682X silently ignores I2C - * writes. Poll the BUSY bit until the SYV682A is ready. - */ -static int syv682x_wait_for_ready(int port, int reg) -{ - int regval; - int rv; - timestamp_t deadline; - -#ifdef CONFIG_USBC_PPC_SYV682C - /* On SYV682C, busy bit is not applied to CONTROL_4 */ - if (syv682x_board_is_syv682c(port) && reg == SYV682X_CONTROL_4_REG) - return EC_SUCCESS; -#endif - - deadline.val = get_time().val - + (SYV682X_MAX_VBUS_DISCHARGE_TIME_MS * MSEC); - - do { - rv = read_reg(port, SYV682X_CONTROL_3_REG, ®val); - if (rv) - return rv; - - if (!(regval & SYV682X_BUSY)) - break; - - if (timestamp_expired(deadline, NULL)) { - ppc_prints("busy timeout", port); - return EC_ERROR_TIMEOUT; - } - - msleep(1); - } while (1); - - return EC_SUCCESS; -} - -static int write_reg(uint8_t port, int reg, int regval) -{ - int rv; - - rv = syv682x_wait_for_ready(port, reg); - if (rv) - return rv; - - return i2c_write8(ppc_chips[port].i2c_port, - ppc_chips[port].i2c_addr_flags, - reg, - regval); -} - -static int syv682x_is_sourcing_vbus(int port) -{ - return !!(flags[port] & SYV682X_FLAGS_SOURCE_ENABLED); -} - -static int syv682x_discharge_vbus(int port, int enable) -{ -#ifndef CONFIG_USBC_PPC_SYV682X_SMART_DISCHARGE - int regval; - int rv; - - rv = read_reg(port, SYV682X_CONTROL_2_REG, ®val); - if (rv) - return rv; - - if (enable) - regval |= SYV682X_CONTROL_2_FDSG; - else - regval &= ~SYV682X_CONTROL_2_FDSG; - - return write_reg(port, SYV682X_CONTROL_2_REG, regval); -#else - /* - * Smart discharge mode is enabled, nothing to do - */ - return EC_SUCCESS; -#endif -} - -static int syv682x_vbus_source_enable(int port, int enable) -{ - int regval; - int rv; - /* - * For source mode need to make sure 5V power path is connected - * and source mode is selected. - */ - rv = read_reg(port, SYV682X_CONTROL_1_REG, ®val); - if (rv) - return rv; - - if (enable) { - /* Select 5V path and turn on channel */ - regval &= ~(SYV682X_CONTROL_1_CH_SEL | - SYV682X_CONTROL_1_PWR_ENB); - /* Disable HV Sink path */ - regval |= SYV682X_CONTROL_1_HV_DR; - } else if (flags[port] & SYV682X_FLAGS_SOURCE_ENABLED) { - /* - * For the disable case, make sure that VBUS was being sourced - * prior to disabling the source path. Because the source/sink - * paths can't be independently disabled, and this function will - * get called as part of USB PD initialization, setting the - * PWR_ENB always can lead to broken dead battery behavior. - * - * No need to change the voltage path or channel direction. But, - * turn both paths off. - * - * De-assert the FRS GPIO, which will be asserted if we got to - * be a source via an FRS. - */ - regval |= SYV682X_CONTROL_1_PWR_ENB; - if (IS_ENABLED(CONFIG_USB_PD_FRS_PPC)) - gpio_set_level(ppc_chips[port].frs_en, 0); - } - - rv = write_reg(port, SYV682X_CONTROL_1_REG, regval); - if (rv) - return rv; - - if (enable) { - atomic_or(&flags[port], SYV682X_FLAGS_SOURCE_ENABLED); - atomic_clear_bits(&flags[port], SYV682X_FLAGS_SINK_ENABLED); - } else { - atomic_clear_bits(&flags[port], SYV682X_FLAGS_SOURCE_ENABLED); - } - -#if defined(CONFIG_USB_CHARGER) && defined(CONFIG_USB_PD_VBUS_DETECT_PPC) - /* - * Since the VBUS state could be changing here, need to wake the - * USB_CHG_N task so that BC 1.2 detection will be triggered. - */ - usb_charger_vbus_change(port, enable); -#endif - - return EC_SUCCESS; -} - -/* Filter interrupts with rising edge trigger */ -static bool syv682x_interrupt_filter(int port, int regval, int regmask, - int flagmask) -{ - if (regval & regmask) { - if (!(flags[port] & flagmask)) { - atomic_or(&flags[port], flagmask); - return true; - } - } else { - atomic_clear_bits(&flags[port], flagmask); - } - return false; -} - -/* - * Two status registers can trigger the ALERT_L pin, STATUS and CONTROL_4 - * These registers are clear on read if the condition has been cleared. - * The ALERT_L pin will not de-assert if the alert condition has not been - * cleared. Since they are clear on read, we should check the alerts whenever we - * read these registers to avoid race conditions. - */ -static void syv682x_handle_status_interrupt(int port, int regval) -{ - /* - * An FRS will automatically disable sinking immediately, and enable the - * source path if VBUS is <5V. The FRS GPIO must remain asserted until - * VBUS falls below 5V. SYV682X_FLAGS_FRS signals that the SRC state was - * entered via an FRS. - * - * Note the FRS Alert will remain asserted until VBUS has fallen below - * 5V or the frs_en gpio is de-asserted. So use the rising edge trigger. - */ - if (IS_ENABLED(CONFIG_USB_PD_FRS_PPC)) { - if (syv682x_interrupt_filter(port, regval, SYV682X_STATUS_FRS, - SYV682X_FLAGS_FRS)) { - atomic_or(&flags[port], SYV682X_FLAGS_SOURCE_ENABLED); - atomic_clear_bits(&flags[port], - SYV682X_FLAGS_SINK_ENABLED); - if (!IS_ENABLED(CONFIG_USB_PD_FRS_TCPC)) - pd_got_frs_signal(port); - } - } - - /* - * 5V OC is actually notifying that it is current limiting - * to 3.3A. If this happens for a long time, we will trip TSD - * which will disable the channel. We should disable the sourcing path - * before that happens for safety reasons. - * - * On first check, set the flag and set the timer. This also clears the - * flag if the OC is gone. - */ - if (syv682x_interrupt_filter(port, regval, SYV682X_STATUS_OC_5V, - SYV682X_FLAGS_5V_OC)) { - vbus_oc_timer[port].val = - get_time().val + SOURCE_OC_DEGLITCH_MS * MSEC; - } else if ((regval & SYV682X_STATUS_OC_5V) && - (get_time().val > vbus_oc_timer[port].val)) { - vbus_oc_timer[port].val = UINT64_MAX; - atomic_clear_bits(&flags[port], SYV682X_FLAGS_5V_OC); - syv682x_vbus_source_enable(port, 0); - pd_handle_overcurrent(port); - } - - /* - * No PD handling for VBUS OVP or TSD events. - * For TSD, this means we are in danger of burning the device so turn - * everything off and leave it off. The power paths will be - * automatically disabled. - * In the case of OVP, the channels will be - * disabled but don't unset the sink flag, since a sink OCP can - * inadvertently cause an OVP, and we'd want to re-enable the sink - * path in that situation. - */ - if (syv682x_interrupt_filter(port, regval, SYV682X_STATUS_TSD, - SYV682X_FLAGS_TSD)) { - ppc_prints("TSD!", port); - atomic_clear_bits(&flags[port], - SYV682X_FLAGS_SOURCE_ENABLED | - SYV682X_FLAGS_SINK_ENABLED); - } - if (syv682x_interrupt_filter(port, regval, SYV682X_STATUS_OVP, - SYV682X_FLAGS_OVP)) { - ppc_prints("VBUS OVP!", port); - atomic_clear_bits(&flags[port], SYV682X_FLAGS_SOURCE_ENABLED); - } - - /* - * HV OC is a hard limit that will disable the sink path (automatically - * removing this alert condition), so try re-enabling if we hit an OCP. - * If we get multiple OCPs, don't re-enable. The OCP counter is reset on - * the sink path being explicitly disabled or on a PPC init. - */ - if (regval & SYV682X_STATUS_OC_HV) { - ppc_prints("Sink OCP!", port); - atomic_add(&sink_ocp_count[port], 1); - if ((sink_ocp_count[port] < OCP_COUNT_LIMIT) && - (flags[port] & SYV682X_FLAGS_SINK_ENABLED)) { - syv682x_vbus_sink_enable(port, 1); - } else { - ppc_prints("Disable sink", port); - atomic_clear_bits(&flags[port], - SYV682X_FLAGS_SINK_ENABLED); - } - } -} - -static int syv682x_handle_control_4_interrupt(int port, int regval) -{ - /* - * VCONN OC is actually notifying that it is current limiting - * to 600mA. If this happens for a long time, we will trip TSD - * which will disable the channel. We should disable the sourcing path - * before that happens for safety reasons. - * - * On first check, set the flag and set the timer. This also clears the - * flag if the OC is gone. - */ - if (syv682x_interrupt_filter(port, regval, SYV682X_CONTROL_4_VCONN_OCP, - SYV682X_FLAGS_VCONN_OCP)) { - vconn_oc_timer[port].val = - get_time().val + VCONN_OC_DEGLITCH_MS * MSEC; - } else if ((regval & SYV682X_CONTROL_4_VCONN_OCP) && - (get_time().val > vconn_oc_timer[port].val)) { - vconn_oc_timer[port].val = UINT64_MAX; - atomic_clear_bits(&flags[port], SYV682X_FLAGS_VCONN_OCP); - - /* Disable VCONN */ - regval &= - ~(SYV682X_CONTROL_4_VCONN2 | SYV682X_CONTROL_4_VCONN1); - write_reg(port, SYV682X_CONTROL_4_REG, regval); - - ppc_prints("VCONN OC!", port); - } - - /* - * On VBAT OVP, CC/VCONN are cut. Re-enable before sending the hard - * reset using a PPC re-init. We could reconfigure CC based on flags, - * but these will be updated anyway due to a hard reset so just re-init - * for simplicity. If this happens return an error since this isn't - * recoverable. - */ - if (regval & SYV682X_CONTROL_4_VBAT_OVP) { - ppc_prints("VBAT or CC OVP!", port); - syv682x_init(port); - pd_handle_cc_overvoltage(port); - return EC_ERROR_UNKNOWN; - } - return EC_SUCCESS; -} - -static int syv682x_vbus_sink_enable(int port, int enable) -{ - int regval; - int rv; - - if (!enable) { - atomic_clear(&sink_ocp_count[port]); - atomic_clear_bits(&flags[port], SYV682X_FLAGS_SINK_ENABLED); - /* - * We're currently a source, so nothing more to do - */ - if (syv682x_is_sourcing_vbus(port)) - return EC_SUCCESS; - } else if (sink_ocp_count[port] > OCP_COUNT_LIMIT) { - /* - * Don't re-enable the channel until an explicit sink disable - * resets the ocp counter. - */ - return EC_ERROR_UNKNOWN; - } - - /* - * For sink mode need to make sure high voltage power path is connected - * and sink mode is selected. - */ - rv = read_reg(port, SYV682X_CONTROL_1_REG, ®val); - if (rv) - return rv; - - if (enable) { - /* Select high voltage path */ - regval |= SYV682X_CONTROL_1_CH_SEL; - /* Select Sink mode and turn on the channel */ - regval &= ~(SYV682X_CONTROL_1_HV_DR | - SYV682X_CONTROL_1_PWR_ENB); - /* Set sink current limit to the configured value */ - regval |= CONFIG_SYV682X_HV_ILIM << SYV682X_HV_ILIM_BIT_SHIFT; - atomic_clear_bits(&flags[port], SYV682X_FLAGS_SOURCE_ENABLED); - atomic_or(&flags[port], SYV682X_FLAGS_SINK_ENABLED); - } else { - /* - * No need to change the voltage path or channel direction. But, - * turn both paths off because we are currently a sink. - */ - regval |= SYV682X_CONTROL_1_PWR_ENB; - } - - return write_reg(port, SYV682X_CONTROL_1_REG, regval); -} - -#ifdef CONFIG_USB_PD_VBUS_DETECT_PPC -static int syv682x_is_vbus_present(int port) -{ - int val; - int vbus = 0; - - if (read_reg(port, SYV682X_STATUS_REG, &val)) - return vbus; - /* - * The status register interrupt bits are clear on read, check - * register value to see if there are interrupts to avoid race - * conditions with the interrupt handler - */ - syv682x_handle_status_interrupt(port, val); - - /* - * VBUS is considered present if VSafe5V is detected or neither VSafe5V - * or VSafe0V is detected, which implies VBUS > 5V. - */ - if ((val & SYV682X_STATUS_VSAFE_5V) || - !(val & (SYV682X_STATUS_VSAFE_5V | SYV682X_STATUS_VSAFE_0V))) - vbus = 1; -#ifdef CONFIG_USB_CHARGER - if (!!(flags[port] & SYV682X_FLAGS_VBUS_PRESENT) != vbus) - usb_charger_vbus_change(port, vbus); - - if (vbus) - atomic_or(&flags[port], SYV682X_FLAGS_VBUS_PRESENT); - else - atomic_clear_bits(&flags[port], SYV682X_FLAGS_VBUS_PRESENT); -#endif - - return vbus; -} -#endif - -static int syv682x_set_vbus_source_current_limit(int port, - enum tcpc_rp_value rp) -{ - int rv; - int limit; - int regval; - - rv = read_reg(port, SYV682X_CONTROL_1_REG, ®val); - if (rv) - return rv; - - /* We need buffer room for all current values. */ - switch (rp) { - case TYPEC_RP_3A0: - limit = SYV682X_5V_ILIM_3_30; - break; - - case TYPEC_RP_1A5: - limit = SYV682X_5V_ILIM_1_75; - break; - - case TYPEC_RP_USB: - default: - /* 1.25 A is lowest current limit setting for SVY682 */ - limit = SYV682X_5V_ILIM_1_25; - break; - }; - - regval &= ~SYV682X_5V_ILIM_MASK; - regval |= (limit << SYV682X_5V_ILIM_BIT_SHIFT); - return write_reg(port, SYV682X_CONTROL_1_REG, regval); -} - -#ifdef CONFIG_USBC_PPC_POLARITY -static int syv682x_set_polarity(int port, int polarity) -{ - /* - * The SYV682x does not explicitly set CC polarity. However, if VCONN is - * being used then the polarity is required to connect 5V to the correct - * CC line. So this function saves the CC polarity as a bit in the flags - * variable so VCONN is connected the correct CC line. The flag bit - * being set means polarity = CC2, the flag bit clear means - * polarity = CC1. - */ - if (polarity) - atomic_or(&flags[port], SYV682X_FLAGS_CC_POLARITY); - else - atomic_clear_bits(&flags[port], SYV682X_FLAGS_CC_POLARITY); - - return EC_SUCCESS; -} -#endif - -#ifdef CONFIG_USBC_PPC_VCONN -static int syv682x_set_vconn(int port, int enable) -{ - int regval; - int rv; - - rv = read_reg(port, SYV682X_CONTROL_4_REG, ®val); - if (rv) - return rv; - /* - * The control4 register interrupt bits are clear on read, check - * register value to see if there are interrupts to avoid race - * conditions with the interrupt handler - */ - rv = syv682x_handle_control_4_interrupt(port, regval); - if (rv) - return rv; - - regval &= ~(SYV682X_CONTROL_4_VCONN2 | SYV682X_CONTROL_4_VCONN1); - if (enable) { - regval |= flags[port] & SYV682X_FLAGS_CC_POLARITY ? - SYV682X_CONTROL_4_VCONN1 : - SYV682X_CONTROL_4_VCONN2; - } - - return write_reg(port, SYV682X_CONTROL_4_REG, regval); -} -#endif - -#ifdef CONFIG_CMD_PPC_DUMP -static int syv682x_dump(int port) -{ - int reg_addr; - int data; - int rv; - const int i2c_port = ppc_chips[port].i2c_port; - const int i2c_addr_flags = ppc_chips[port].i2c_addr_flags; - - for (reg_addr = SYV682X_STATUS_REG; reg_addr <= SYV682X_CONTROL_4_REG; - reg_addr++) { - rv = i2c_read8(i2c_port, i2c_addr_flags, reg_addr, &data); - if (rv) - ccprintf("ppc_syv682[p%d]: Failed to read reg 0x%02x\n", - port, reg_addr); - else - ccprintf("ppc_syv682[p%d]: reg 0x%02x = 0x%02x\n", - port, reg_addr, data); - } - - cflush(); - - return EC_SUCCESS; -} -#endif /* defined(CONFIG_CMD_PPC_DUMP) */ - -static void syv682x_handle_interrupt(int port) -{ - int control4; - int status; - - /* Both interrupt registers are clear on read */ - read_reg(port, SYV682X_CONTROL_4_REG, &control4); - syv682x_handle_control_4_interrupt(port, control4); - - read_reg(port, SYV682X_STATUS_REG, &status); - syv682x_handle_status_interrupt(port, status); - - /* - * Since ALERT_L is level-triggered, check the alert status and repeat - * until all interrupts are cleared. The SYV682B and later have a 10ms - * deglitch on OC, so make sure not to check the status register again - * for at least 10ms to give it time to re-trigger. This will not spam - * indefinitely on OCP, but may on OVP, RVS, or TSD. - */ - - if (status & SYV682X_STATUS_INT_MASK || - control4 & SYV682X_CONTROL_4_INT_MASK) { - syv682x_interrupt_delayed(port, INTERRUPT_DELAY_MS); - } -} - -static void syv682x_irq_deferred(void) -{ - int i; - uint32_t pending = atomic_clear(&irq_pending); - - for (i = 0; i < board_get_usb_pd_port_count(); i++) - if (BIT(i) & pending) - syv682x_handle_interrupt(i); -} -DECLARE_DEFERRED(syv682x_irq_deferred); - -static void syv682x_interrupt_delayed(int port, int delay) -{ - atomic_or(&irq_pending, BIT(port)); - hook_call_deferred(&syv682x_irq_deferred_data, delay * MSEC); -} - -void syv682x_interrupt(int port) -{ - /* FRS timings require <15ms response to an FRS event */ - syv682x_interrupt_delayed(port, 0); -} - -/* - * The frs_en signal can be driven from the TCPC as well (preferred). - * In that case, no PPC configuration needs to be done to enable FRS - */ -#ifdef CONFIG_USB_PD_FRS_PPC -static int syv682x_set_frs_enable(int port, int enable) -{ - int regval; - - read_reg(port, SYV682X_CONTROL_4_REG, ®val); - syv682x_handle_control_4_interrupt(port, regval); - - if (enable) { - /* - * The CC line is the FRS trigger, and VCONN should - * be ignored. The SYV682 uses the CCx_BPS fields to - * determine if CC1 or CC2 is CC and should be used for - * FRS. This CCx is also connected through to the TCPC. - * The other CCx signal (VCONN) is isolated from the - * TCPC with this write (VCONN must be provided by PPC). - * - * It is not a valid state to have both or neither - * CC_BPS bits set and the CC_FRS enabled, exactly 1 - * should be set. - */ - regval &= ~(SYV682X_CONTROL_4_CC1_BPS | - SYV682X_CONTROL_4_CC2_BPS); - regval |= flags[port] & SYV682X_FLAGS_CC_POLARITY ? - SYV682X_CONTROL_4_CC2_BPS : - SYV682X_CONTROL_4_CC1_BPS; - /* set GPIO after configuring */ - write_reg(port, SYV682X_CONTROL_4_REG, regval); - gpio_set_level(ppc_chips[port].frs_en, 1); - } else { - /* - * Reconnect CC lines to TCPC. Since the FRS GPIO needs to be - * asserted until VBUS falls below 5V during an FRS, if - * SYV682X_FLAGS_FRS is set then don't deassert it, instead - * disable when sourcing is disabled. - */ - regval |= SYV682X_CONTROL_4_CC1_BPS | SYV682X_CONTROL_4_CC2_BPS; - write_reg(port, SYV682X_CONTROL_4_REG, regval); - if (!(flags[port] & SYV682X_FLAGS_FRS)) - gpio_set_level(ppc_chips[port].frs_en, 0); - } - return EC_SUCCESS; -} -#endif /*CONFIG_USB_PD_FRS_PPC*/ - -#ifndef CONFIG_USBC_PPC_SYV682X_SMART_DISCHARGE -static int syv682x_dev_is_connected(int port, enum ppc_device_role dev) -{ - /* - * (b:160548079) We disable the smart discharge(SDSG), so we should - * turn off the discharge FET if a source is connected. - */ - if (dev == PPC_DEV_SRC) - return syv682x_discharge_vbus(port, 0); - else if (dev == PPC_DEV_DISCONNECTED) - return syv682x_discharge_vbus(port, 1); - - return EC_SUCCESS; -} -#endif - -static bool syv682x_is_sink(uint8_t control_1) -{ - /* - * The SYV682 integrates power paths: 5V and HV (high voltage). - * The SYV682 can source either 5V or HV, but only sinks on the HV path. - * - * PD analyzer without a device connected confirms the SYV682 acts as - * a source under these conditions: - * HV_DR && !CH_SEL: source 5V - * HV_DR && CH_SEL: source 15V - * !HV_DR && !CH_SEL: source 5V - * - * The SYV682 is only a sink when !HV_DR && CH_SEL - */ - if (!(control_1 & SYV682X_CONTROL_1_PWR_ENB) - && !(control_1 & SYV682X_CONTROL_1_HV_DR) - && (control_1 & SYV682X_CONTROL_1_CH_SEL)) - return true; - - return false; -} - -static int syv682x_init(int port) -{ - int rv; - int regval; - int status, control_1; - enum tcpc_rp_value initial_current_limit; - - rv = read_reg(port, SYV682X_STATUS_REG, &status); - if (rv) - return rv; - - rv = read_reg(port, SYV682X_CONTROL_1_REG, &control_1); - if (rv) - return rv; - atomic_clear(&sink_ocp_count[port]); - - /* - * Disable FRS prior to configuring the power paths - */ - if (IS_ENABLED(CONFIG_USB_PD_FRS_PPC)) - gpio_set_level(ppc_chips[port].frs_en, 0); - - if (!syv682x_is_sink(control_1) - || (status & SYV682X_STATUS_VSAFE_0V)) { - /* - * Disable both power paths, - * set HV_ILIM to 3.3A, - * set 5V_ILIM to 3.3A, - * set HV direction to sink, - * select HV channel. - */ - regval = SYV682X_CONTROL_1_PWR_ENB | - (CONFIG_SYV682X_HV_ILIM << SYV682X_HV_ILIM_BIT_SHIFT) | - /* !SYV682X_CONTROL_1_HV_DR */ - SYV682X_CONTROL_1_CH_SEL; - rv = write_reg(port, SYV682X_CONTROL_1_REG, regval); - if (rv) - return rv; - } else { - /* Dead battery mode, or an existing PD contract is in place */ - rv = syv682x_vbus_sink_enable(port, 1); - if (rv) - return rv; - } - -#ifdef CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT - initial_current_limit = CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT; -#else - initial_current_limit = CONFIG_USB_PD_PULLUP; -#endif - rv = syv682x_set_vbus_source_current_limit(port, initial_current_limit); - if (rv) - return rv; - - /* - * Set Control Reg 2 to defaults except 50ms smart discharge time. - * Note: On SYV682A/B, enable smart discharge would block i2c - * transactions for 50ms (discharge time) and this - * prevents us from disabling Vconn when stop sourcing Vbus and has - * tVconnOff (35ms) timeout. - * On SYV682C, we are allowed to access CONTROL4 while the i2c busy. - */ - regval = (SYV682X_OC_DELAY_10MS << SYV682X_OC_DELAY_SHIFT) - | (SYV682X_DSG_RON_200_OHM << SYV682X_DSG_RON_SHIFT) - | (SYV682X_DSG_TIME_50MS << SYV682X_DSG_TIME_SHIFT); - - if (IS_ENABLED(CONFIG_USBC_PPC_SYV682X_SMART_DISCHARGE)) - regval |= SYV682X_CONTROL_2_SDSG; - - rv = write_reg(port, SYV682X_CONTROL_2_REG, regval); - if (rv) - return rv; - - /* - * Always set the over voltage setting to the maximum to support - * sinking from a 20V PD charger. The common PPC code doesn't provide - * any hooks for indicating what the currently negotiated voltage is. - * - * Mask Alerts due to Reverse Voltage. - */ - regval = (SYV682X_OVP_23_7 << SYV682X_OVP_BIT_SHIFT) | SYV682X_RVS_MASK; - rv = write_reg(port, SYV682X_CONTROL_3_REG, regval); - if (rv) - return rv; - - /* - * Remove Rd and connect CC1/CC2 lines to TCPC - * Disable Vconn - * Enable CC detection of Fast Role Swap (FRS) - */ - regval = SYV682X_CONTROL_4_CC1_BPS | SYV682X_CONTROL_4_CC2_BPS; - rv = write_reg(port, SYV682X_CONTROL_4_REG, regval); - if (rv) - return rv; - - return EC_SUCCESS; -} - -const struct ppc_drv syv682x_drv = { - .init = &syv682x_init, - .is_sourcing_vbus = &syv682x_is_sourcing_vbus, - .vbus_sink_enable = &syv682x_vbus_sink_enable, - .vbus_source_enable = &syv682x_vbus_source_enable, -#ifdef CONFIG_CMD_PPC_DUMP - .reg_dump = &syv682x_dump, -#endif /* defined(CONFIG_CMD_PPC_DUMP) */ -#ifdef CONFIG_USB_PD_FRS_PPC - .set_frs_enable = &syv682x_set_frs_enable, -#endif -#ifdef CONFIG_USB_PD_VBUS_DETECT_PPC - .is_vbus_present = &syv682x_is_vbus_present, -#endif /* defined(CONFIG_USB_PD_VBUS_DETECT_PPC) */ - .set_vbus_source_current_limit = &syv682x_set_vbus_source_current_limit, - .discharge_vbus = &syv682x_discharge_vbus, -#ifndef CONFIG_USBC_PPC_SYV682X_SMART_DISCHARGE - .dev_is_connected = &syv682x_dev_is_connected, -#endif /* defined(CONFIG_USBC_PPC_SYV682X_SMART_DISCHARGE) */ -#ifdef CONFIG_USBC_PPC_POLARITY - .set_polarity = &syv682x_set_polarity, -#endif -#ifdef CONFIG_USBC_PPC_VCONN - .set_vconn = &syv682x_set_vconn, -#endif -}; diff --git a/driver/ppc/syv682x.h b/driver/ppc/syv682x.h deleted file mode 100644 index d9416f47f1..0000000000 --- a/driver/ppc/syv682x.h +++ /dev/null @@ -1,112 +0,0 @@ -/* Copyright 2018 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. - */ - -/* Silergy SYV682x Type-C Power Path Controller */ - -#ifndef __CROS_EC_SYV682X_H -#define __CROS_EC_SYV682X_H - -#include "common.h" -#include "driver/ppc/syv682x_public.h" - -/* Source OC deglitch implemented in HW for SYV682B */ -#define SYV682X_HW_OC_DEGLITCH_MS 10 - -/* SYV682x register addresses */ -#define SYV682X_STATUS_REG 0x00 -#define SYV682X_CONTROL_1_REG 0x01 -#define SYV682X_CONTROL_2_REG 0x02 -#define SYV682X_CONTROL_3_REG 0x03 -#define SYV682X_CONTROL_4_REG 0x04 - -/* Status Register */ -#define SYV682X_STATUS_OC_HV BIT(7) -#define SYV682X_STATUS_RVS BIT(6) -#define SYV682X_STATUS_OC_5V BIT(5) -#define SYV682X_STATUS_OVP BIT(4) -#define SYV682X_STATUS_FRS BIT(3) -#define SYV682X_STATUS_TSD BIT(2) -#define SYV682X_STATUS_VSAFE_5V BIT(1) -#define SYV682X_STATUS_VSAFE_0V BIT(0) -#define SYV682X_STATUS_INT_MASK 0xfc - -/* Control Register 1 */ -#define SYV682X_CONTROL_1_CH_SEL BIT(1) -#define SYV682X_CONTROL_1_HV_DR BIT(2) -#define SYV682X_CONTROL_1_PWR_ENB BIT(7) - -#define SYV682X_5V_ILIM_MASK 0x18 -#define SYV682X_5V_ILIM_BIT_SHIFT 3 -#define SYV682X_5V_ILIM_1_25 0 -#define SYV682X_5V_ILIM_1_75 1 -#define SYV682X_5V_ILIM_2_25 2 -#define SYV682X_5V_ILIM_3_30 3 - -#define SYV682X_HV_ILIM_MASK 0x60 -#define SYV682X_HV_ILIM_BIT_SHIFT 5 -#define SYV682X_HV_ILIM_1_25 0 -#define SYV682X_HV_ILIM_1_75 1 -#define SYV682X_HV_ILIM_3_30 2 -#define SYV682X_HV_ILIM_5_50 3 - -/* Control Register 2 */ -#define SYV682X_OC_DELAY_MASK GENMASK(7, 6) -#define SYV682X_OC_DELAY_SHIFT 6 -#define SYV682X_OC_DELAY_1MS 0 -#define SYV682X_OC_DELAY_10MS 1 -#define SYV682X_OC_DELAY_50MS 2 -#define SYV682X_OC_DELAY_100MS 3 -#define SYV682X_DSG_TIME_MASK GENMASK(5, 4) -#define SYV682X_DSG_TIME_SHIFT 4 -#define SYV682X_DSG_TIME_50MS 0 -#define SYV682X_DSG_TIME_100MS 1 -#define SYV682X_DSG_TIME_200MS 2 -#define SYV682X_DSG_TIME_400MS 3 -#define SYV682X_DSG_RON_MASK GENMASK(3, 2) -#define SYV682X_DSG_RON_SHIFT 2 -#define SYV682X_DSG_RON_200_OHM 0 -#define SYV682X_DSG_RON_400_OHM 1 -#define SYV682X_DSG_RON_800_OHM 2 -#define SYV682X_DSG_RON_1600_OHM 3 -#define SYV682X_CONTROL_2_SDSG BIT(1) -#define SYV682X_CONTROL_2_FDSG BIT(0) - -/* Control Register 3 */ -#define SYV682X_BUSY BIT(7) -#define SYV682X_RVS_MASK BIT(3) -#define SYV682X_RST_REG BIT(0) -#define SYV682X_OVP_MASK 0x70 -#define SYV682X_OVP_BIT_SHIFT 4 -#define SYV682X_OVP_06_0 0 -#define SYV682X_OVP_08_0 1 -#define SYV682X_OVP_11_1 2 -#define SYV682X_OVP_12_1 3 -#define SYV682X_OVP_14_2 4 -#define SYV682X_OVP_17_9 5 -#define SYV682X_OVP_21_6 6 -#define SYV682X_OVP_23_7 7 - -/* Control Register 4 */ -#define SYV682X_CONTROL_4_CC1_BPS BIT(7) -#define SYV682X_CONTROL_4_CC2_BPS BIT(6) -#define SYV682X_CONTROL_4_VCONN1 BIT(5) -#define SYV682X_CONTROL_4_VCONN2 BIT(4) -#define SYV682X_CONTROL_4_VBAT_OVP BIT(3) -#define SYV682X_CONTROL_4_VCONN_OCP BIT(2) -#define SYV682X_CONTROL_4_CC_FRS BIT(1) -#define SYV682X_CONTROL_4_INT_MASK 0x0c - -/* - * syv682x_board_is_syv682c - * - * b:160548079 This is a function to workaround that some board revisions - * might have different SYV682 sub-version. - * - * @param port the query port - * @return 1 if the PPC is SYV682C else 0 - */ -__override_proto int syv682x_board_is_syv682c(int port); - -#endif /* defined(__CROS_EC_SYV682X_H) */ diff --git a/driver/regulator_ir357x.c b/driver/regulator_ir357x.c deleted file mode 100644 index 4721146367..0000000000 --- a/driver/regulator_ir357x.c +++ /dev/null @@ -1,247 +0,0 @@ -/* Copyright 2012 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. - * - * IR357x driver. - */ - -#include "common.h" -#include "console.h" -#include "hooks.h" -#include "i2c.h" -#include "timer.h" -#include "util.h" - -/* Console output macros */ -#define CPUTS(outstr) cputs(CC_CHIPSET, outstr) -#define CPRINTF(format, args...) cprintf(CC_CHIPSET, format, ## args) - -/* I2C address */ -#define IR357x_I2C_ADDR_FLAGS 0x08 - -struct ir_setting { - uint8_t reg; - uint8_t value; -}; - -static struct ir_setting ir3570_settings[] = { - {0x10, 0x22}, {0x11, 0x22}, {0x12, 0x88}, {0x13, 0x10}, - {0x14, 0x0d}, {0x15, 0x21}, {0x16, 0x21}, {0x17, 0x00}, - {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00}, - {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00}, - {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x60}, {0x23, 0x60}, - {0x24, 0x74}, {0x25, 0x4e}, {0x26, 0xff}, {0x27, 0x80}, - {0x28, 0x00}, {0x29, 0x20}, {0x2a, 0x15}, {0x2b, 0x26}, - {0x2c, 0xb6}, {0x2d, 0x21}, {0x2e, 0x11}, {0x2f, 0x20}, - {0x30, 0xab}, {0x31, 0x14}, {0x32, 0x90}, {0x33, 0x4d}, - {0x34, 0x75}, {0x35, 0x64}, {0x36, 0x64}, {0x37, 0x09}, - {0x38, 0xc4}, {0x39, 0x20}, {0x3a, 0x80}, {0x3b, 0x00}, - {0x3c, 0x00}, {0x3d, 0xaa}, {0x3e, 0x00}, {0x3f, 0x05}, - {0x40, 0x50}, {0x41, 0x40}, {0x42, 0x00}, {0x43, 0x00}, - {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00}, - {0x48, 0x1c}, {0x49, 0x0c}, {0x4a, 0x0f}, {0x4b, 0x40}, - {0x4c, 0x80}, {0x4d, 0x40}, {0x4e, 0x80}, - {0x51, 0x00}, {0x52, 0x45}, {0x53, 0x59}, - {0x54, 0x23}, {0x55, 0xae}, {0x56, 0x68}, {0x57, 0x24}, - {0x58, 0x62}, {0x59, 0x42}, {0x5a, 0x34}, {0x5b, 0x00}, - {0x5c, 0x30}, {0x5d, 0x05}, {0x5e, 0x02}, {0x5f, 0x35}, - {0x60, 0x30}, {0x61, 0x00}, {0x62, 0xd8}, {0x63, 0x00}, - {0x64, 0x52}, {0x65, 0x28}, {0x66, 0x14}, {0x67, 0x87}, - {0x68, 0x80}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00}, - {0x6c, 0x00}, {0x6d, 0xff}, {0x6e, 0x06}, {0x6f, 0xff}, - {0x70, 0xff}, {0x71, 0x20}, {0x72, 0x00}, {0x73, 0x01}, - {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00}, - {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00}, - {0x7c, 0x15}, {0x7d, 0x15}, {0x7e, 0x00}, {0x7f, 0x00}, - {0x80, 0x00}, {0x81, 0x00}, {0x82, 0x00}, {0x83, 0x00}, - {0x84, 0x00}, {0x85, 0x00}, {0x86, 0x00}, {0x87, 0x00}, - {0x88, 0x88}, {0x89, 0x88}, {0x8a, 0x01}, {0x8b, 0x42}, - {0x8d, 0x00}, {0x8e, 0x00}, {0x8f, 0x1f}, - {0, 0} -}; - -static struct ir_setting ir3571_settings[] = { - {0x18, 0x22}, {0x19, 0x22}, {0x1a, 0x08}, {0x1b, 0x10}, - {0x1c, 0x06}, {0x1d, 0x21}, {0x1e, 0x21}, {0x1f, 0x83}, - {0x20, 0x83}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00}, - {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x34}, - {0x28, 0x34}, {0x29, 0x74}, {0x2a, 0x4e}, {0x2b, 0xff}, - {0x2c, 0x00}, {0x2d, 0x1d}, {0x2e, 0x14}, {0x2f, 0x1f}, - {0x30, 0x88}, {0x31, 0x9a}, {0x32, 0x1e}, {0x33, 0x19}, - {0x34, 0xe9}, {0x35, 0x40}, {0x36, 0x90}, {0x37, 0x6d}, - {0x38, 0x75}, {0x39, 0xa0}, {0x3a, 0x84}, {0x3b, 0x08}, - {0x3c, 0xc5}, {0x3d, 0xa0}, {0x3e, 0x80}, {0x3f, 0xaa}, - {0x40, 0x50}, {0x41, 0x4b}, {0x42, 0x02}, {0x43, 0x04}, - {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x78}, - {0x48, 0x56}, {0x49, 0x18}, {0x4a, 0x88}, {0x4b, 0x00}, - {0x4c, 0x80}, {0x4d, 0x60}, {0x4e, 0x60}, {0x4f, 0xff}, - {0x50, 0xff}, {0x51, 0x00}, {0x52, 0x9b}, {0x53, 0xaa}, - {0x54, 0xd8}, {0x55, 0x56}, {0x56, 0x31}, {0x57, 0x1a}, - {0x58, 0x12}, {0x59, 0x63}, {0x5a, 0x00}, {0x5b, 0x09}, - {0x5c, 0x02}, {0x5d, 0x00}, {0x5e, 0xea}, {0x5f, 0x00}, - {0x60, 0xb0}, {0x61, 0x1e}, {0x62, 0x00}, {0x63, 0x56}, - {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00}, - {0x68, 0x28}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00}, - {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00}, - {0x70, 0x80}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00}, - {0x74, 0x00}, {0x75, 0xbf}, {0x76, 0x06}, {0x77, 0xff}, - {0x78, 0xff}, {0x79, 0x04}, {0x7a, 0x00}, {0x7b, 0x1d}, - {0x7c, 0xa0}, {0x7d, 0x10}, {0x7e, 0x00}, {0x7f, 0x8a}, - {0x80, 0x1b}, {0x81, 0x11}, {0x82, 0x00}, {0x83, 0x00}, - {0x84, 0x00}, {0x85, 0x00}, {0x86, 0x00}, {0x87, 0x00}, - {0x88, 0x00}, {0x89, 0x00}, {0x8a, 0x00}, {0x8b, 0x00}, - {0x8c, 0x00}, {0x8d, 0x00}, {0x8e, 0x00}, {0x8f, 0x00}, - {0, 0} -}; - -static uint8_t ir357x_read(uint8_t reg) -{ - int res; - int val; - - res = i2c_read8(I2C_PORT_REGULATOR, IR357x_I2C_ADDR, reg, &val); - if (res) - return 0xee; - - return val; -} - -static void ir357x_write(uint8_t reg, uint8_t val) -{ - int res; - - res = i2c_write8(I2C_PORT_REGULATOR, IR357x_I2C_ADDR, reg, val); - if (res) - CPRINTF("IR I2C write failed\n"); -} - -static int ir357x_get_version(void) -{ - /* IR3571 on Link EVT */ - if ((ir357x_read(0xfc) == 'I') && (ir357x_read(0xfd) == 'R') && - ((ir357x_read(0x0a) & 0xe) == 0)) - return 3571; - - /* IR3570A on Link Proto 0/1 and Link DVT */ - if ((ir357x_read(0x92) == 'C') && (ir357x_read(0xcd) == 0x24)) - return 3570; - - /* Unknown and unsupported chip */ - return -1; -} - -struct ir_setting *ir357x_get_settings(void) -{ - int version = ir357x_get_version(); - - if (version == 3570) - return ir3570_settings; - else if (version == 3571) - return ir3571_settings; - else - return NULL; -} - -static void ir357x_prog(void) -{ - struct ir_setting *settings = ir357x_get_settings(); - - if (settings) { - for (; settings->reg; settings++) - ir357x_write(settings->reg, settings->value); - } else { - CPRINTF("IR%d chip unsupported. Skip writing settings!\n", - ir357x_get_version()); - return; - } - - CPRINTF("IR%d registers UPDATED\n", ir357x_get_version()); -} - -static void ir357x_dump(void) -{ - int i; - - for (i = 0; i < 256; i++) { - if (!(i & 0xf)) { - ccprintf("\n%02x: ", i); - cflush(); - } - ccprintf("%02x ", ir357x_read(i)); - } - ccprintf("\n"); -} - -static int ir357x_check(void) -{ - uint8_t val; - int diff = 0; - struct ir_setting *settings = ir357x_get_settings(); - - if (!settings) { - ccprintf("no setting for chip IR%d !\n", ir357x_get_version()); - return 1; - } - - for (; settings->reg; settings++) { - val = ir357x_read(settings->reg); - if (val != settings->value) { - ccprintf("DIFF reg 0x%02x %02x->%02x\n", - settings->reg, settings->value, val); - cflush(); - diff++; - } - } - return !!diff; -} - -#ifdef CONFIG_CMD_REGULATOR -static int command_ir357x(int argc, char **argv) -{ - int reg, val; - char *rem; - - if (1 == argc) { /* dump all registers */ - ir357x_dump(); - return EC_SUCCESS; - } else if (2 == argc) { - if (!strcasecmp(argv[1], "check")) { - ir357x_check(); - } else { /* read one register */ - reg = strtoi(argv[1], &rem, 16); - if (*rem) { - ccprintf("Invalid register: %s\n", argv[1]); - return EC_ERROR_INVAL; - } - ccprintf("reg 0x%02x = 0x%02x\n", reg, - ir357x_read(reg)); - } - return EC_SUCCESS; - } else if (3 == argc) { /* write one register */ - reg = strtoi(argv[1], &rem, 16); - if (*rem) { - ccprintf("Invalid register: %s\n", argv[1]); - return EC_ERROR_INVAL; - } - val = strtoi(argv[2], &rem, 16); - if (*rem) { - ccprintf("Invalid value: %s\n", argv[2]); - return EC_ERROR_INVAL; - } - ir357x_write(reg, val); - return EC_SUCCESS; - } - - return EC_ERROR_INVAL; -} -DECLARE_CONSOLE_COMMAND(ir357x, command_ir357x, - "[check|write]", - "IR357x core regulator control"); -#endif - -static void ir357x_hot_settings(void) -{ - /* dynamically apply settings to workaround issue */ - ir357x_prog(); -} -DECLARE_HOOK(HOOK_CHIPSET_RESUME, ir357x_hot_settings, HOOK_PRIO_DEFAULT); diff --git a/driver/retimer/anx7491.h b/driver/retimer/anx7491.h deleted file mode 100644 index 045cf9f411..0000000000 --- a/driver/retimer/anx7491.h +++ /dev/null @@ -1,17 +0,0 @@ -/* Copyright 2021 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. - * - * ANX7491:10G USB 3.2 Re-timer (1-Port) - */ - -#ifndef __CROS_EC_USB_RETIMER_ANX7491_H -#define __CROS_EC_USB_RETIMER_ANX7491_H - -/* I2C interface addresses */ -#define ANX7491_I2C_ADDR0_FLAGS 0x10 -#define ANX7491_I2C_ADDR1_FLAGS 0x14 -#define ANX7491_I2C_ADDR2_FLAGS 0x16 -#define ANX7491_I2C_ADDR3_FLAGS 0x11 - -#endif /* __CROS_EC_USB_RETIMER_ANX7491_H */ diff --git a/driver/retimer/bb_retimer.c b/driver/retimer/bb_retimer.c deleted file mode 100644 index bf3da60b32..0000000000 --- a/driver/retimer/bb_retimer.c +++ /dev/null @@ -1,623 +0,0 @@ -/* Copyright 2019 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. - * - * Driver for Intel Burnside Bridge - Thunderbolt/USB/DisplayPort Retimer - */ - -#include "driver/retimer/bb_retimer.h" -#include "chipset.h" -#include "common.h" -#include "console.h" -#include "i2c.h" -#include "task.h" -#include "timer.h" -#include "usb_pd.h" -#include "util.h" - -#define BB_RETIMER_REG_SIZE 4 -#define BB_RETIMER_READ_SIZE (BB_RETIMER_REG_SIZE + 1) -#define BB_RETIMER_WRITE_SIZE (BB_RETIMER_REG_SIZE + 2) -#define BB_RETIMER_MUX_DATA_PRESENT (USB_PD_MUX_USB_ENABLED \ - | USB_PD_MUX_DP_ENABLED \ - | USB_PD_MUX_SAFE_MODE \ - | USB_PD_MUX_TBT_COMPAT_ENABLED \ - | USB_PD_MUX_USB4_ENABLED) - -#define BB_RETIMER_MUX_USB_ALT_MODE (USB_PD_MUX_USB_ENABLED\ - | USB_PD_MUX_DP_ENABLED \ - | USB_PD_MUX_TBT_COMPAT_ENABLED \ - | USB_PD_MUX_USB4_ENABLED) - -#define BB_RETIMER_MUX_USB_DP_MODE (USB_PD_MUX_USB_ENABLED \ - | USB_PD_MUX_DP_ENABLED \ - | USB_PD_MUX_USB4_ENABLED) - -#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args) - -#define BB_RETIMER_I2C_RETRY 5 - -/** - * Utility functions - */ -static int bb_retimer_read(const struct usb_mux *me, - const uint8_t offset, uint32_t *data) -{ - int rv, retry = 0; - uint8_t buf[BB_RETIMER_READ_SIZE]; - - /* - * This I2C message will trigger retimer's internal read sequence - * if its a NAK, sleep and resend same I2C - */ - while (1) { - /* - * Read sequence - * Addr flags (w) - Reg offset - repeated start - Addr flags(r) - * byte[0] : Read size - * byte[1:4] : Data [LSB -> MSB] - * Stop - */ - rv = i2c_xfer(me->i2c_port, me->i2c_addr_flags, - &offset, 1, buf, BB_RETIMER_READ_SIZE); - - if (rv == EC_SUCCESS) - break; - - if (++retry >= BB_RETIMER_I2C_RETRY) { - CPRINTS("C%d: Retimer I2C read err=%d", - me->usb_port, rv); - return rv; - } - msleep(10); - } - - if (buf[0] != BB_RETIMER_REG_SIZE) - return EC_ERROR_UNKNOWN; - - *data = buf[1] | (buf[2] << 8) | (buf[3] << 16) | (buf[4] << 24); - - return EC_SUCCESS; -} - -static int bb_retimer_write(const struct usb_mux *me, - const uint8_t offset, uint32_t data) -{ - int rv, retry = 0; - uint8_t buf[BB_RETIMER_WRITE_SIZE]; - - /* - * Write sequence - * Addr flags(w) - * byte[0] : Reg offset - * byte[1] : Write Size - * byte[2:5] : Data [LSB -> MSB] - * stop - */ - buf[0] = offset; - buf[1] = BB_RETIMER_REG_SIZE; - buf[2] = data & 0xFF; - buf[3] = (data >> 8) & 0xFF; - buf[4] = (data >> 16) & 0xFF; - buf[5] = (data >> 24) & 0xFF; - - /* - * This I2C message will trigger retimer's internal write sequence - * if its a NAK, sleep and resend same I2C - */ - while (1) { - rv = i2c_xfer(me->i2c_port, me->i2c_addr_flags, buf, - BB_RETIMER_WRITE_SIZE, NULL, 0); - - if (rv == EC_SUCCESS) - break; - - if (++retry >= BB_RETIMER_I2C_RETRY) { - CPRINTS("C%d: Retimer I2C write err=%d", - me->usb_port, rv); - break; - } - msleep(10); - } - return rv; -} - -__overridable int bb_retimer_power_enable(const struct usb_mux *me, bool enable) -{ - const struct bb_usb_control *control = &bb_controls[me->usb_port]; - - /* handle retimer's power domain */ - - if (enable) { - gpio_set_level(control->usb_ls_en_gpio, 1); - /* - * Tpw, minimum time from VCC to RESET_N de-assertion is 100us. - * For boards that don't provide a load switch control, the - * retimer_init() function ensures power is up before calling - * this function. - */ - msleep(1); - gpio_set_level(control->retimer_rst_gpio, 1); - /* - * Allow 1ms time for the retimer to power up lc_domain - * which powers I2C controller within retimer - */ - msleep(1); - } else { - gpio_set_level(control->retimer_rst_gpio, 0); - msleep(1); - gpio_set_level(control->usb_ls_en_gpio, 0); - } - return EC_SUCCESS; -} - -static void retimer_set_state_dfp(int port, mux_state_t mux_state, - uint32_t *set_retimer_con) -{ - union tbt_mode_resp_cable cable_resp = { - .raw_value = pd_get_tbt_mode_vdo(port, TCPCI_MSG_SOP_PRIME) }; - union tbt_mode_resp_device dev_resp; - enum idh_ptype cable_type = get_usb_pd_cable_type(port); - - /* - * Bit 2: RE_TIMER_DRIVER - * 0 - Re-driver - * 1 - Re-timer - * - * If Alternate mode is USB/DP/USB4, RE_TIMER_DRIVER is - * set according to SOP' VDO2 response Bit 9. - * - */ - if (is_active_cable_element_retimer(port) && - (mux_state & BB_RETIMER_MUX_USB_DP_MODE)) - *set_retimer_con |= BB_RETIMER_RE_TIMER_DRIVER; - - /* - * Bit 22: ACTIVE/PASSIVE - * 0 - Passive cable - * 1 - Active cable - * - * If the mode is USB/DP/Thunderbolt_compat/USB4, ACTIVE/PASIVE is - * set according to Discover mode SOP' response. - */ - if ((mux_state & BB_RETIMER_MUX_USB_ALT_MODE) && - ((cable_type == IDH_PTYPE_ACABLE) || - cable_resp.tbt_active_passive == TBT_CABLE_ACTIVE)) - *set_retimer_con |= BB_RETIMER_ACTIVE_PASSIVE; - - if (mux_state & USB_PD_MUX_TBT_COMPAT_ENABLED || - mux_state & USB_PD_MUX_USB4_ENABLED) { - dev_resp.raw_value = pd_get_tbt_mode_vdo(port, TCPCI_MSG_SOP); - - /* - * Bit 2: RE_TIMER_DRIVER - * 0 - Re-driver - * 1 - Re-timer - * - * If Alternate mode is Thunderbolt-Compat, RE_TIMER_DRIVER is - * set according to Discover Mode SOP' response, - * Bit 22: Retimer Type. - */ - if (cable_resp.retimer_type == USB_RETIMER) - *set_retimer_con |= BB_RETIMER_RE_TIMER_DRIVER; - - /* - * Bit 17: TBT_TYPE - * 0 - Type-C to Type-C Cable - * 1 - Type-C Legacy TBT Adapter - */ - if (dev_resp.tbt_adapter == TBT_ADAPTER_TBT2_LEGACY) - *set_retimer_con |= BB_RETIMER_TBT_TYPE; - - /* - * Bit 18: CABLE_TYPE - * 0 - Electrical cable - * 1 - Optical cable - */ - if (cable_resp.tbt_cable == TBT_CABLE_OPTICAL) - *set_retimer_con |= BB_RETIMER_TBT_CABLE_TYPE; - - /* - * Bit 19: VPO_DOCK_DETECTED_OR_DP_OVERDRIVE - * 0 - No vPro Dock.No DP Overdrive - * detected - * 1 - vPro Dock or DP Overdrive - * detected - */ - if (dev_resp.intel_spec_b0 == VENDOR_SPECIFIC_SUPPORTED || - dev_resp.vendor_spec_b1 == VENDOR_SPECIFIC_SUPPORTED) - *set_retimer_con |= BB_RETIMER_VPRO_DOCK_DP_OVERDRIVE; - - /* - * Bit 20: TBT_ACTIVE_LINK_TRAINING - * 0 - Active with bi-directional LSRX communication - * 1 - Active with uni-directional LSRX communication - * Set to "0" when passive cable plug - */ - if ((cable_type == IDH_PTYPE_ACABLE || - cable_resp.tbt_active_passive == TBT_CABLE_ACTIVE) && - cable_resp.lsrx_comm == UNIDIR_LSRX_COMM) - *set_retimer_con |= BB_RETIMER_TBT_ACTIVE_LINK_TRAINING; - - /* - * Bit 27-25: USB4/TBT Cable speed - * 000b - No functionality - * 001b - USB3.1 Gen1 Cable - * 010b - 10Gb/s - * 011b - 10Gb/s and 20Gb/s - * 10..11b - Reserved - */ - *set_retimer_con |= BB_RETIMER_USB4_TBT_CABLE_SPEED_SUPPORT( - mux_state & USB_PD_MUX_TBT_COMPAT_ENABLED ? - get_tbt_cable_speed(port) : - get_usb4_cable_speed(port)); - - /* - * Bits 29-28: TBT_GEN_SUPPORT - * 00b - 3rd generation TBT (10.3125 and 20.625Gb/s) - * 01b - 4th generation TBT (10.00005Gb/s, 10.3125Gb/s, - * 20.0625Gb/s, 20.000Gb/s) - * 10..11b - Reserved - */ - *set_retimer_con |= BB_RETIMER_TBT_CABLE_GENERATION( - cable_resp.tbt_rounded); - } -} - -static void retimer_set_state_ufp(int port, mux_state_t mux_state, - uint32_t *set_retimer_con) -{ - /* - * Bit 7: USB_DATA_ROLE for the Burnside Bridge side of - * connection. - * 0 - DFP - * 1 - UFP - */ - *set_retimer_con |= BB_RETIMER_USB_DATA_ROLE; - - if (!IS_ENABLED(CONFIG_USB_PD_ALT_MODE_UFP)) - return; - - /* TODO:b/168890624: Set USB4 retimer config for UFP */ - if (mux_state & USB_PD_MUX_TBT_COMPAT_ENABLED) { - union tbt_dev_mode_enter_cmd ufp_tbt_enter_mode = { - .raw_value = pd_ufp_get_enter_mode(port)}; - /* - * Bit 2: RE_TIMER_DRIVER - * 0 - Re-driver - * 1 - Re-timer - * - * Set according to TBT3 Enter Mode bit 22. - */ - if (ufp_tbt_enter_mode.retimer_type == USB_RETIMER) - *set_retimer_con |= BB_RETIMER_RE_TIMER_DRIVER; - - /* - * Bit 18: CABLE_TYPE - * 0 - Electrical cable - * 1 - Optical cable - * - * Set according to TBT3 Enter Mode bit 21. - */ - if (ufp_tbt_enter_mode.tbt_cable == TBT_CABLE_OPTICAL) - *set_retimer_con |= BB_RETIMER_TBT_CABLE_TYPE; - - /* - * Bit 19: VPO_DOCK_DETECTED_OR_DP_OVERDRIVE - * 0 - No vPro Dock.No DP Overdrive - * detected - * 1 - vPro Dock or DP Overdrive - * detected - * - * Set according to TBT3 Enter Mode bit 26 or bit 31 - */ - if (ufp_tbt_enter_mode.intel_spec_b0 == - VENDOR_SPECIFIC_SUPPORTED || - ufp_tbt_enter_mode.vendor_spec_b1 == - VENDOR_SPECIFIC_SUPPORTED) - *set_retimer_con |= BB_RETIMER_VPRO_DOCK_DP_OVERDRIVE; - - /* - * Bit 20: TBT_ACTIVE_LINK_TRAINING - * 0 - Active with bi-directional LSRX communication - * 1 - Active with uni-directional LSRX communication - * - * Set according to TBT3 Enter Mode bit 23 - */ - if (ufp_tbt_enter_mode.lsrx_comm == UNIDIR_LSRX_COMM) - *set_retimer_con |= BB_RETIMER_TBT_ACTIVE_LINK_TRAINING; - - /* - * Bit 22: ACTIVE/PASSIVE - * 0 - Passive cable - * 1 - Active cable - * - * Set according to TBT3 Enter Mode bit 24 - */ - if (ufp_tbt_enter_mode.cable == TBT_ENTER_ACTIVE_CABLE) - *set_retimer_con |= BB_RETIMER_ACTIVE_PASSIVE; - - /* - * Bit 27-25: TBT Cable speed - * 000b - No functionality - * 001b - USB3.1 Gen1 Cable - * 010b - 10Gb/s - * 011b - 10Gb/s and 20Gb/s - * 10..11b - Reserved - * - * Set according to TBT3 Enter Mode bit 18:16 - */ - *set_retimer_con |= BB_RETIMER_USB4_TBT_CABLE_SPEED_SUPPORT( - ufp_tbt_enter_mode.tbt_cable_speed); - /* - * Bits 29-28: TBT_GEN_SUPPORT - * 00b - 3rd generation TBT (10.3125 and 20.625Gb/s) - * 01b - 4th generation TBT (10.00005Gb/s, 10.3125Gb/s, - * 20.0625Gb/s, 20.000Gb/s) - * 10..11b - Reserved - * - * Set according to TBT3 Enter Mode bit 20:19 - */ - *set_retimer_con |= BB_RETIMER_TBT_CABLE_GENERATION( - ufp_tbt_enter_mode.tbt_rounded); - } -} - -/** - * Driver interface functions - */ -static int retimer_set_state(const struct usb_mux *me, mux_state_t mux_state, - bool *ack_required) -{ - uint32_t set_retimer_con = 0; - uint8_t dp_pin_mode; - int port = me->usb_port; - - /* This driver does not use host command ACKs */ - *ack_required = false; - - /* - * Bit 0: DATA_CONNECTION_PRESENT - * 0 - No connection present - * 1 - Connection present - */ - if (mux_state & BB_RETIMER_MUX_DATA_PRESENT) - set_retimer_con |= BB_RETIMER_DATA_CONNECTION_PRESENT; - - /* - * Bit 1: CONNECTION_ORIENTATION - * 0 - Normal - * 1 - reversed - */ - if (mux_state & USB_PD_MUX_POLARITY_INVERTED) - set_retimer_con |= BB_RETIMER_CONNECTION_ORIENTATION; - - /* - * Bit 5: USB_3_CONNECTION - * 0 - No USB3.1 Connection - * 1 - USB3.1 connection - */ - if (mux_state & USB_PD_MUX_USB_ENABLED) { - set_retimer_con |= BB_RETIMER_USB_3_CONNECTION; - - /* - * Bit 6: USB3_Speed - * 0 – USB3 is limited to Gen1 - * 1 – USB3 Gen1/Gen2 supported - */ - if (is_cable_speed_gen2_capable(port)) - set_retimer_con |= BB_RETIMER_USB_3_SPEED; - } - - /* - * Bit 8: DP_CONNECTION - * 0 – No DP connection - * 1 – DP connected - */ - if (mux_state & USB_PD_MUX_DP_ENABLED) { - set_retimer_con |= BB_RETIMER_DP_CONNECTION; - - /* - * Bit 11-10: DP_PIN_ASSIGNMENT (ignored if BIT8 = 0) - * 00 – Pin assignments E/E’ - * 01 – Pin assignments C/C’/D/D’1,2 - * 10, 11 - reserved - */ - dp_pin_mode = get_dp_pin_mode(port); - if (dp_pin_mode == MODE_DP_PIN_C || - dp_pin_mode == MODE_DP_PIN_D) - set_retimer_con |= BB_RETIMER_DP_PIN_ASSIGNMENT; - - /* - * Bit 14: IRQ_HPD (ignored if BIT8 = 0) - * 0 - No IRQ_HPD - * 1 - IRQ_HPD received - */ - if (mux_state & USB_PD_MUX_HPD_IRQ) - set_retimer_con |= BB_RETIMER_IRQ_HPD; - - /* - * Bit 15: HPD_LVL (ignored if BIT8 = 0) - * 0 - HPD_State Low - * 1 - HPD_State High - */ - if (mux_state & USB_PD_MUX_HPD_LVL) - set_retimer_con |= BB_RETIMER_HPD_LVL; - } - - /* - * Bit 16: TBT_CONNECTION - * 0 - TBT not configured - * 1 - TBT configured - */ - if (mux_state & USB_PD_MUX_TBT_COMPAT_ENABLED) - set_retimer_con |= BB_RETIMER_TBT_CONNECTION; - - /* - * Bit 23: USB4_CONNECTION - * 0 - USB4 not configured - * 1 - USB4 Configured - */ - if (mux_state & USB_PD_MUX_USB4_ENABLED) - set_retimer_con |= BB_RETIMER_USB4_ENABLED; - - if (pd_get_data_role(port) == PD_ROLE_DFP) - retimer_set_state_dfp(port, mux_state, &set_retimer_con); - else - retimer_set_state_ufp(port, mux_state, &set_retimer_con); - - /* Writing the register4 */ - return bb_retimer_write(me, BB_RETIMER_REG_CONNECTION_STATE, - set_retimer_con); -} - -void bb_retimer_hpd_update(const struct usb_mux *me, mux_state_t mux_state) -{ - uint32_t retimer_con_reg = 0; - - if (bb_retimer_read(me, BB_RETIMER_REG_CONNECTION_STATE, - &retimer_con_reg) != EC_SUCCESS) - return; - - /* - * Bit 14: IRQ_HPD (ignored if BIT8 = 0) - * 0 - No IRQ_HPD - * 1 - IRQ_HPD received - */ - if (mux_state & USB_PD_MUX_HPD_IRQ) - retimer_con_reg |= BB_RETIMER_IRQ_HPD; - else - retimer_con_reg &= ~BB_RETIMER_IRQ_HPD; - - /* - * Bit 15: HPD_LVL (ignored if BIT8 = 0) - * 0 - HPD_State Low - * 1 - HPD_State High - */ - if (mux_state & USB_PD_MUX_HPD_LVL) - retimer_con_reg |= BB_RETIMER_HPD_LVL; - else - retimer_con_reg &= ~BB_RETIMER_HPD_LVL; - - /* Writing the register4 */ - bb_retimer_write(me, BB_RETIMER_REG_CONNECTION_STATE, retimer_con_reg); -} - -static int retimer_low_power_mode(const struct usb_mux *me) -{ - return bb_retimer_power_enable(me, false); -} - -static bool is_retimer_fw_update_capable(void) -{ - return true; -} - -static int retimer_init(const struct usb_mux *me) -{ - int rv; - uint32_t data; - - /* Burnside Bridge is powered by main AP rail */ - if (chipset_in_or_transitioning_to_state(CHIPSET_STATE_ANY_OFF)) { - /* Ensure reset is asserted while chip is not powered */ - bb_retimer_power_enable(me, false); - return EC_ERROR_NOT_POWERED; - } - - rv = bb_retimer_power_enable(me, true); - if (rv != EC_SUCCESS) - return rv; - - rv = bb_retimer_read(me, BB_RETIMER_REG_VENDOR_ID, &data); - if (rv != EC_SUCCESS) - return rv; - if ((data != BB_RETIMER_VENDOR_ID_1) && - data != BB_RETIMER_VENDOR_ID_2) - return EC_ERROR_INVAL; - - rv = bb_retimer_read(me, BB_RETIMER_REG_DEVICE_ID, &data); - if (rv != EC_SUCCESS) - return rv; - if (data != BB_RETIMER_DEVICE_ID) - return EC_ERROR_INVAL; - - return EC_SUCCESS; -} - -const struct usb_mux_driver bb_usb_retimer = { - .init = retimer_init, - .set = retimer_set_state, - .enter_low_power_mode = retimer_low_power_mode, - .is_retimer_fw_update_capable = is_retimer_fw_update_capable, -}; - -#ifdef CONFIG_CMD_RETIMER -static int console_command_bb_retimer(int argc, char **argv) -{ - char rw, *e; - int port, reg, data, val = 0; - int rv = EC_SUCCESS; - const struct usb_mux *mux; - - if (argc < 4) - return EC_ERROR_PARAM_COUNT; - - /* Get port number */ - port = strtoi(argv[1], &e, 0); - if (*e || !board_is_usb_pd_port_present(port)) - return EC_ERROR_PARAM1; - - mux = &usb_muxes[port]; - while (mux) { - if (mux->driver == &bb_usb_retimer) - break; - mux = mux->next_mux; - } - - if (!mux) - return EC_ERROR_PARAM1; - - /* Validate r/w selection */ - rw = argv[2][0]; - if (rw != 'w' && rw != 'r') - return EC_ERROR_PARAM2; - - /* Get register address */ - reg = strtoi(argv[3], &e, 0); - if (*e || reg < 0) - return EC_ERROR_PARAM3; - - /* Get value to be written */ - if (rw == 'w') { - val = strtoi(argv[4], &e, 0); - if (*e || val < 0) - return EC_ERROR_PARAM4; - } - - for (; mux != NULL; mux = mux->next_mux) { - if (mux->driver == &bb_usb_retimer) { - if (rw == 'r') - rv = bb_retimer_read(mux, reg, &data); - else { - rv = bb_retimer_write(mux, reg, val); - if (rv == EC_SUCCESS) { - rv = bb_retimer_read( - mux, reg, &data); - if (rv == EC_SUCCESS && data != val) - rv = EC_ERROR_UNKNOWN; - } - } - if (rv == EC_SUCCESS) - CPRINTS("Addr 0x%x register %d = 0x%x", - mux->i2c_addr_flags, reg, data); - } - } - - return rv; -} -DECLARE_CONSOLE_COMMAND(bb, console_command_bb_retimer, - "<port> <r/w> <reg> | <val>", - "Read or write to BB retimer register"); -#endif /* CONFIG_CMD_RETIMER */ diff --git a/driver/retimer/kb800x.c b/driver/retimer/kb800x.c deleted file mode 100644 index 48e47404c2..0000000000 --- a/driver/retimer/kb800x.c +++ /dev/null @@ -1,543 +0,0 @@ -/* Copyright 2021 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. - * - * Driver for Kandou KB800x USB-C 40 Gb/s multiprotocol switch. - */ - -#include "common.h" -#include "console.h" -#include "i2c.h" -#include "kb800x.h" -#include "time.h" - -/* Time between load switch enable and the reset being de-asserted */ -#define KB800X_POWER_ON_DELAY_MS 20 - -static mux_state_t cached_mux_state[CONFIG_USB_PD_PORT_MAX_COUNT]; - -static int kb800x_write(const struct usb_mux *me, uint16_t address, - uint8_t data) -{ - uint8_t kb800x_config[3] = { 0x00, 0x00, 0x00 }; - - kb800x_config[0] = (address >> 8) & 0xff; - kb800x_config[1] = address & 0xff; - kb800x_config[2] = data; - return i2c_xfer(me->i2c_port, me->i2c_addr_flags, kb800x_config, - sizeof(kb800x_config), NULL, 0); -} - -static int kb800x_read(const struct usb_mux *me, uint16_t address, - uint8_t *data) -{ - uint8_t kb800x_config[2] = { 0x00, 0x00 }; - - kb800x_config[0] = (address >> 8) & 0xff; - kb800x_config[1] = address & 0xff; - return i2c_xfer(me->i2c_port, me->i2c_addr_flags, kb800x_config, - sizeof(kb800x_config), data, 1); -} - -#ifdef CONFIG_KB800X_CUSTOM_XBAR - -/* These lookup tables are derived from the KB8001 EVB GUI register map */ - -/* Map elastic buffer (EB) to register field for TX configuration. */ -static const uint8_t tx_eb_to_field_ab[] = { - [KB800X_EB1] = 4, [KB800X_EB2] = 0, [KB800X_EB3] = 0, - [KB800X_EB4] = 1, [KB800X_EB5] = 2, [KB800X_EB6] = 3 -}; -static const uint8_t tx_eb_to_field_cd[] = { - [KB800X_EB1] = 1, [KB800X_EB2] = 2, [KB800X_EB3] = 3, - [KB800X_EB4] = 4, [KB800X_EB5] = 0, [KB800X_EB6] = 0 -}; -/* Map phy lane to register field for RX configuration */ -static const uint8_t rx_phy_lane_to_field[] = { - [KB800X_A0] = 1, [KB800X_A1] = 2, [KB800X_B0] = 5, [KB800X_B1] = 6, - [KB800X_C0] = 1, [KB800X_C1] = 2, [KB800X_D0] = 5, [KB800X_D1] = 6 -}; -/* Map EB to address for RX configuration */ -static const uint16_t rx_eb_to_address[] = { - [KB800X_EB1] = KB800X_REG_XBAR_EB1SEL, - [KB800X_EB2] = KB800X_REG_XBAR_EB23SEL, - [KB800X_EB3] = KB800X_REG_XBAR_EB23SEL, - [KB800X_EB4] = KB800X_REG_XBAR_EB4SEL, - [KB800X_EB5] = KB800X_REG_XBAR_EB56SEL, - [KB800X_EB6] = KB800X_REG_XBAR_EB56SEL -}; -/* Map SS lane to EB for DP or USB/CIO protocols */ -static const uint8_t dp_ss_lane_to_eb[] = { [KB800X_TX0] = KB800X_EB4, - [KB800X_TX1] = KB800X_EB5, - [KB800X_RX0] = KB800X_EB6, - [KB800X_RX1] = KB800X_EB1 }; -static const uint8_t usb_ss_lane_to_eb[] = { [KB800X_TX0] = KB800X_EB4, - [KB800X_TX1] = KB800X_EB5, - [KB800X_RX0] = KB800X_EB1, - [KB800X_RX1] = KB800X_EB2 }; - -/* Assign a phy TX to an elastic buffer */ -static int kb800x_assign_tx_to_eb(const struct usb_mux *me, - enum kb800x_phy_lane phy_lane, enum kb800x_eb eb) -{ - uint8_t field_value = 0; - uint8_t regval; - int rv; - - field_value = KB800X_PHY_IS_AB(phy_lane) ? tx_eb_to_field_ab[eb] : - tx_eb_to_field_cd[eb]; - - /* For lane1 of each PHY, shift by 3 bits */ - field_value <<= 3 * KB800X_LANE_NUMBER_FROM_PHY(phy_lane); - - rv = kb800x_read(me, KB800X_REG_TXSEL_FROM_PHY(phy_lane), ®val); - if (rv) - return rv; - return kb800x_write(me, KB800X_REG_TXSEL_FROM_PHY(phy_lane), - regval | field_value); -} - - -/* Assign a phy RX to an elastic buffer */ -static int kb800x_assign_rx_to_eb(const struct usb_mux *me, - enum kb800x_phy_lane phy_lane, enum kb800x_eb eb) -{ - uint16_t address = 0; - uint8_t field_value = 0; - uint8_t regval = 0; - int rv; - - - field_value = rx_phy_lane_to_field[phy_lane]; - address = rx_eb_to_address[eb]; - - /* - * need to shift by 4 for reverse EB or 3rd EB in set based on the - * register definition from the KB8001 EVB register map - */ - switch (eb) { - case KB800X_EB1: - if (!KB800X_PHY_IS_AB(phy_lane)) - field_value <<= 4; - break; - case KB800X_EB4: - if (KB800X_PHY_IS_AB(phy_lane)) - field_value <<= 4; - break; - case KB800X_EB3: - case KB800X_EB6: - field_value <<= 4; - break; - default: - break; - } - - rv = kb800x_read(me, address, ®val); - if (rv) - return rv; - return kb800x_write(me, address, regval | field_value); -} - -static bool kb800x_in_dpmf(const struct usb_mux *me) -{ - if ((cached_mux_state[me->usb_port] & USB_PD_MUX_DP_ENABLED) && - (cached_mux_state[me->usb_port] & USB_PD_MUX_USB_ENABLED)) - return true; - else - return false; -} - -static bool kb800x_is_dp_lane(const struct usb_mux *me, - enum kb800x_ss_lane ss_lane) -{ - if (cached_mux_state[me->usb_port] & USB_PD_MUX_DP_ENABLED) { - /* DP ALT mode */ - if (kb800x_in_dpmf(me)) { - /* DPMF pin configuration */ - if ((ss_lane == KB800X_TX1) || - (ss_lane == KB800X_RX1)) { - return true; /* ML0 or ML1 */ - } - } else { - /* Pure, 4-lane DP mode */ - return true; - } - } - /* Not a DP mode or ML2/3 while in DPMF */ - return false; -} - -/* Assigning this PHY to this SS lane means it should be RX */ -static bool kb800x_phy_ss_lane_is_rx(enum kb800x_phy_lane phy_lane, - enum kb800x_ss_lane ss_lane) -{ - bool rx; - - switch (ss_lane) { - case KB800X_TX0: - case KB800X_TX1: - rx = false; - break; - case KB800X_RX0: - case KB800X_RX1: - rx = true; - break; - } - /* invert for C/D (host side), since it is receiving the TX signal*/ - if (!KB800X_PHY_IS_AB(phy_lane)) - return !rx; - return rx; -} - -/* Assign SS lane to PHY. Assumes A/B is connector-side, and C/D is host-side */ -static int kb800x_assign_lane(const struct usb_mux *me, - enum kb800x_phy_lane phy_lane, - enum kb800x_ss_lane ss_lane) -{ - enum kb800x_eb eb = 0; - - /* - * Easiest way to handle flipping is to just swap lane 1/0. This assumes - * lanes are flipped in the AP. If they are not, they shouldn't be - * flipped for the AP-side lanes, but should for connector-side - */ - if (cached_mux_state[me->usb_port] & USB_PD_MUX_POLARITY_INVERTED) - ss_lane = KB800X_FLIP_SS_LANE(ss_lane); - - if (kb800x_is_dp_lane(me, ss_lane)) { - if (kb800x_in_dpmf(me)) { - /* Route USB3 RX/TX to EB1/4, and ML0/1 to EB5/6 */ - switch (ss_lane) { - case KB800X_TX1: /* ML1 */ - eb = KB800X_EB6; - break; - case KB800X_RX1: /* ML0 */ - eb = KB800X_EB5; - break; - default: - break; - } - } else { - /* Route ML0/1/2/3 through EB1/5/4/6 */ - eb = dp_ss_lane_to_eb[ss_lane]; - } - - /* For DP lanes, always DFP so A/B is TX, C/D is RX */ - if (KB800X_PHY_IS_AB(phy_lane)) - return kb800x_assign_tx_to_eb(me, phy_lane, eb); - else - return kb800x_assign_rx_to_eb(me, phy_lane, eb); - } - - /* Lane is either USB3 or CIO */ - if (kb800x_phy_ss_lane_is_rx(phy_lane, ss_lane)) - return kb800x_assign_rx_to_eb(me, phy_lane, - usb_ss_lane_to_eb[ss_lane]); - else - return kb800x_assign_tx_to_eb(me, phy_lane, - usb_ss_lane_to_eb[ss_lane]); -} - -static int kb800x_xbar_override(const struct usb_mux *me) -{ - int rv; - int i; - - for (i = KB800X_A0; i < KB800X_PHY_LANE_COUNT; ++i) { - rv = kb800x_assign_lane( - me, i, - kb800x_control[me->usb_port].ss_lanes[i]); - if (rv) - return rv; - } - return kb800x_write(me, KB800X_REG_XBAR_OVR, - KB800X_XBAR_OVR_EN); -} -#endif /* CONFIG_KB800X_CUSTOM_XBAR */ - -/* - * The initialization writes for each protocol can be found in the KB8001/KB8002 - * Programming Guidelines - */ -static const uint16_t global_init_addresses[] = { - 0x5058, 0x5059, 0xFF63, 0xF021, 0xF022, 0xF057, 0xF058, - 0x8194, 0xF0C9, 0xF0CA, 0xF0CB, 0xF0CC, 0xF0CD, 0xF0CE, - 0xF0DF, 0xF0E0, 0xF0E1, 0x8198, 0x8191 -}; -static const uint8_t global_init_values[] = { 0x12, 0x12, 0x3C, 0x02, 0x02, - 0x02, 0x02, 0x37, 0x0C, 0x0B, - 0x0A, 0x09, 0x08, 0x07, 0x57, - 0x66, 0x66, 0x33, 0x00 }; -static const uint16_t usb3_init_addresses[] = { 0xF020, 0xF056 }; -static const uint8_t usb3_init_values[] = { 0x2f, 0x2f }; -static const uint16_t dp_init_addresses[] = { 0xF2CB, 0x0011 }; -static const uint8_t dp_init_values[] = { 0x30, 0x00 }; -/* - * The first 2 CIO writes apply an SBRX pullup to the host side (C/D) - * This is required when the CPU doesn't apply a pullup. - */ -static const uint16_t cio_init_addresses[] = { 0x81fd, 0x81fe, 0xF26B, 0xF26E }; -static const uint8_t cio_init_values[] = { 0x08, 0x80, 0x01, 0x19 }; - -static int kb800x_bulk_write(const struct usb_mux *me, - const uint16_t *addresses, const uint8_t *values, - const uint8_t size) -{ - int i; - int rv; - - for (i = 0; i < size; ++i) { - rv = kb800x_write(me, addresses[i], values[i]); - if (rv != EC_SUCCESS) - return rv; - } - - return EC_SUCCESS; -} - -static int kb800x_global_init(const struct usb_mux *me) -{ - return kb800x_bulk_write(me, global_init_addresses, global_init_values, - sizeof(global_init_values)); -} - -static int kb800x_dp_init(const struct usb_mux *me, mux_state_t mux_state) -{ - int rv; - - rv = kb800x_bulk_write(me, dp_init_addresses, dp_init_values, - sizeof(dp_init_values)); - if (rv) - return rv; - return kb800x_write( - me, KB800X_REG_ORIENTATION, - KB800X_ORIENTATION_DP_DFP | - ((mux_state & USB_PD_MUX_POLARITY_INVERTED) ? - KB800X_ORIENTATION_POLARITY : - 0x0)); -} - -static int kb800x_usb3_init(const struct usb_mux *me, mux_state_t mux_state) -{ - int rv; - - rv = kb800x_bulk_write(me, usb3_init_addresses, usb3_init_values, - sizeof(usb3_init_values)); - if (rv) - return rv; - if (mux_state & USB_PD_MUX_POLARITY_INVERTED) - /* This will be overwritten in the DPMF case */ - return kb800x_write(me, KB800X_REG_ORIENTATION, - KB800X_ORIENTATION_POLARITY); - return EC_SUCCESS; -} - -static int kb800x_cio_init(const struct usb_mux *me, mux_state_t mux_state) -{ - uint8_t orientation = 0x0; - int rv; - - enum idh_ptype cable_type = get_usb_pd_cable_type(me->usb_port); - union tbt_mode_resp_cable cable_resp = { - .raw_value = - pd_get_tbt_mode_vdo(me->usb_port, TCPCI_MSG_SOP_PRIME) - }; - - rv = kb800x_bulk_write(me, cio_init_addresses, cio_init_values, - sizeof(cio_init_values)); - if (rv) - return rv; - - if (mux_state & USB_PD_MUX_POLARITY_INVERTED) - orientation = KB800X_ORIENTATION_CIO_LANE_SWAP | - KB800X_ORIENTATION_POLARITY; - - if (!(mux_state & USB_PD_MUX_USB4_ENABLED)) { - /* Special configuration only for legacy mode */ - if (cable_type == IDH_PTYPE_ACABLE || - cable_resp.tbt_active_passive == TBT_CABLE_ACTIVE) { - /* Active cable */ - if (cable_resp.lsrx_comm == UNIDIR_LSRX_COMM) { - orientation |= - KB800X_ORIENTATION_CIO_LEGACY_UNIDIR; - } else { - /* 'Pre-Coding on a TBT3-Compatible Link' ECN */ - rv = kb800x_write(me, 0x8194, 0x31); - if (rv) - return rv; - orientation |= - KB800X_ORIENTATION_CIO_LEGACY_BIDIR; - } - } else { - /* Passive Cable */ - orientation |= KB800X_ORIENTATION_CIO_LEGACY_PASSIVE; - } - } - return kb800x_write(me, KB800X_REG_ORIENTATION, orientation); -} - -static int kb800x_set_state(const struct usb_mux *me, mux_state_t mux_state, - bool *ack_required) -{ - int rv; - - /* This driver does not use host command ACKs */ - *ack_required = false; - - cached_mux_state[me->usb_port] = mux_state; - rv = kb800x_write(me, KB800X_REG_RESET, KB800X_RESET_MASK); - if (rv) - return rv; - /* Release memory map reset */ - rv = kb800x_write(me, KB800X_REG_RESET, - KB800X_RESET_MASK & ~KB800X_RESET_MM); - if (rv) - return rv; - - /* Already in reset, nothing to do */ - if ((mux_state == USB_PD_MUX_NONE) || - (mux_state & USB_PD_MUX_SAFE_MODE)) - return EC_SUCCESS; - - rv = kb800x_global_init(me); - if (rv) - return rv; - - /* CIO mode (USB4/TBT) */ - if (mux_state & - (USB_PD_MUX_USB4_ENABLED | USB_PD_MUX_TBT_COMPAT_ENABLED)) { - rv = kb800x_cio_init(me, mux_state); - if (rv) - return rv; - rv = kb800x_write(me, KB800X_REG_PROTOCOL, KB800X_PROTOCOL_CIO); - } else { - /* USB3 enabled (USB3-only or DPMF) */ - if (mux_state & USB_PD_MUX_USB_ENABLED) { - rv = kb800x_usb3_init(me, mux_state); - if (rv) - return rv; - /* USB3-only is the default KB800X_REG_PROTOCOL value */ - } - - /* DP alt modes (DP-only or DPMF) */ - if (mux_state & USB_PD_MUX_DP_ENABLED) { - rv = kb800x_dp_init(me, mux_state); - if (rv) - return rv; - if (mux_state & USB_PD_MUX_USB_ENABLED) - rv = kb800x_write(me, KB800X_REG_PROTOCOL, - KB800X_PROTOCOL_DPMF); - else - rv = kb800x_write(me, KB800X_REG_PROTOCOL, - KB800X_PROTOCOL_DP); - } - } - if (rv) - return rv; - -#ifdef CONFIG_KB800X_CUSTOM_XBAR - rv = kb800x_xbar_override(me); - if (rv) - return rv; -#endif /* CONFIG_KB800X_CUSTOM_XBAR */ - - return kb800x_write(me, KB800X_REG_RESET, 0x00); -} - -static int kb800x_init(const struct usb_mux *me) -{ - gpio_set_level(kb800x_control[me->usb_port].usb_ls_en_gpio, 1); - gpio_set_level(kb800x_control[me->usb_port].retimer_rst_gpio, 1); - - /* - * Delay after enabling power and releasing the reset to allow the power - * to come up and the reset to be released by the power sequencing - * logic. If after the delay, the reset is still held low - return an - * error. - */ - msleep(KB800X_POWER_ON_DELAY_MS); - if (!gpio_get_level(kb800x_control[me->usb_port].retimer_rst_gpio)) - return EC_ERROR_NOT_POWERED; - - return kb800x_set_state(me, USB_PD_MUX_NONE); -} - -static int kb800x_enter_low_power_mode(const struct usb_mux *me) -{ - gpio_set_level(kb800x_control[me->usb_port].retimer_rst_gpio, 0); - /* Power-down sequencing must be handled in HW */ - gpio_set_level(kb800x_control[me->usb_port].usb_ls_en_gpio, 0); - - return EC_SUCCESS; -} - -#ifdef CONFIG_CMD_RETIMER - -static int console_command_kb800x_xfer(int argc, char **argv) -{ - char rw, *e; - int rv, port, reg, val; - uint8_t data; - const struct usb_mux *mux; - - if (argc < 4) - return EC_ERROR_PARAM_COUNT; - - /* Get port number */ - port = strtoi(argv[1], &e, 0); - if (*e || !board_is_usb_pd_port_present(port)) - return EC_ERROR_PARAM1; - - mux = &usb_muxes[port]; - while (mux) { - if (mux->driver == &kb800x_usb_mux_driver) - break; - mux = mux->next_mux; - } - - if (!mux) - return EC_ERROR_PARAM1; - - /* Validate r/w selection */ - rw = argv[2][0]; - if (rw != 'w' && rw != 'r') - return EC_ERROR_PARAM2; - - /* Get register address */ - reg = strtoi(argv[3], &e, 0); - if (*e || reg < 0) - return EC_ERROR_PARAM3; - rv = EC_SUCCESS; - if (rw == 'r') - rv = kb800x_read(mux, reg, &data); - else { - if (argc < 5) - return EC_ERROR_PARAM_COUNT; - /* Get value to be written */ - val = strtoi(argv[4], &e, 0); - if (*e || val < 0) - return EC_ERROR_PARAM4; - rv = kb800x_write(mux, reg, val); - if (rv == EC_SUCCESS) { - rv = kb800x_read(mux, reg, &data); - if (rv == EC_SUCCESS && data != val) - rv = EC_ERROR_UNKNOWN; - } - } - - if (rv == EC_SUCCESS) - ccprintf("register 0x%x [%d] = 0x%x [%d]\n", reg, reg, data, - data); - - return rv; -} -DECLARE_CONSOLE_COMMAND(kbxfer, console_command_kb800x_xfer, - "<port> <r/w> <reg> | <val>", - "Read or write to KB retimer register"); -#endif /* CONFIG_CMD_RETIMER */ - -const struct usb_mux_driver kb800x_usb_mux_driver = { - .init = kb800x_init, - .set = kb800x_set_state, - .enter_low_power_mode = kb800x_enter_low_power_mode, -}; diff --git a/driver/retimer/kb800x.h b/driver/retimer/kb800x.h deleted file mode 100644 index 5f8cf2810d..0000000000 --- a/driver/retimer/kb800x.h +++ /dev/null @@ -1,110 +0,0 @@ -/* Copyright 2021 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. - * - * Driver for Kandou KB8001 USB-C 40 Gb/s multiprotocol switch. - */ - -#ifndef __CROS_EC_KB800X_H -#define __CROS_EC_KB800X_H - -#include "compile_time_macros.h" -#include "gpio_signal.h" -#include "usb_mux.h" - -#define KB800X_I2C_ADDR0_FLAGS 0x08 -#define KB800X_I2C_ADDR1_FLAGS 0x0C - -extern const struct usb_mux_driver kb800x_usb_mux_driver; - -/* Set the protocol */ -#define KB800X_REG_PROTOCOL 0x0001 -#define KB800X_PROTOCOL_USB3 0x0 -#define KB800X_PROTOCOL_DPMF 0x1 -#define KB800X_PROTOCOL_DP 0x2 -#define KB800X_PROTOCOL_CIO 0x3 - -/* Configure the lane orientaitons */ -#define KB800X_REG_ORIENTATION 0x0002 -#define KB800X_ORIENTATION_POLARITY 0x1 -#define KB800X_ORIENTATION_DP_UFP 0x4 -#define KB800X_ORIENTATION_DP_DFP 0x6 -#define KB800X_ORIENTATION_CIO_LANE_SWAP 0x8 -/* Select one, 0x0 for non-legacy */ -#define KB800X_ORIENTATION_CIO_LEGACY_PASSIVE (0x1 << 4) -#define KB800X_ORIENTATION_CIO_LEGACY_UNIDIR (0x2 << 4) -#define KB800X_ORIENTATION_CIO_LEGACY_BIDIR (0x3 << 4) - -#define KB800X_REG_RESET 0x0006 -#define KB800X_RESET_FSM BIT(0) -#define KB800X_RESET_MM BIT(1) -#define KB800X_RESET_SERDES BIT(2) -#define KB800X_RESET_COM BIT(3) -#define KB800X_RESET_MASK GENMASK(3, 0) - -#define KB800X_REG_XBAR_OVR 0x5040 -#define KB800X_XBAR_OVR_EN BIT(6) - -/* Registers to configure the elastic buffer input connection */ -#define KB800X_REG_XBAR_EB1SEL 0x5044 -#define KB800X_REG_XBAR_EB23SEL 0x5045 -#define KB800X_REG_XBAR_EB4SEL 0x5046 -#define KB800X_REG_XBAR_EB56SEL 0x5047 - -/* Registers to configure the elastic buffer output connection (x=0-7) */ -#define KB800X_REG_TXSEL_FROM_PHY(x) (0x5048+((x)/2)) - -enum kb800x_ss_lane { - KB800X_TX0 = 0, - KB800X_TX1, - KB800X_RX0, - KB800X_RX1 -}; - -enum kb800x_phy_lane { - KB800X_A0 = 0, - KB800X_A1, - KB800X_B0, - KB800X_B1, - KB800X_C0, - KB800X_C1, - KB800X_D0, - KB800X_D1, - KB800X_PHY_LANE_COUNT -}; - -enum kb800x_eb { - KB800X_EB1 = 0, - KB800X_EB2, - KB800X_EB3, - KB800X_EB4, - KB800X_EB5, - KB800X_EB6 -}; - -#define KB800X_FLIP_SS_LANE(x) ((x) + 1 - 2*((x) & 0x1)) -#define KB800X_LANE_NUMBER_FROM_PHY(x) ((x) & 0x1) -#define KB800X_PHY_IS_AB(x) ((x) <= KB800X_B1) - -struct kb800x_control_t { - enum gpio_signal retimer_rst_gpio; - enum gpio_signal usb_ls_en_gpio; -#ifdef CONFIG_KB800X_CUSTOM_XBAR - enum kb800x_ss_lane ss_lanes[KB800X_PHY_LANE_COUNT]; -#endif /* CONFIG_KB800X_CUSTOM_XBAR */ -}; - -/* - * Default 'example' lane mapping. With this mapping, CONFIG_KB800X_CUSTOM_XBAR - * can be undefined, since a custom xbar mapping is not needed. - * ss_lanes = { - * [KB800X_A0] = KB800X_TX0, [KB800X_A1] = KB800X_RX0, - * [KB800X_B0] = KB800X_RX1, [KB800X_B1] = KB800X_TX1, - * [KB800X_C0] = KB800X_RX0, [KB800X_C1] = KB800X_TX0, - * [KB800X_D0] = KB800X_TX1, [KB800X_D1] = KB800X_RX1,} - */ - -extern struct kb800x_control_t kb800x_control[]; - - -#endif /* __CROS_EC_KB800X_H */ diff --git a/driver/retimer/nb7v904m.c b/driver/retimer/nb7v904m.c deleted file mode 100644 index 94e96230b2..0000000000 --- a/driver/retimer/nb7v904m.c +++ /dev/null @@ -1,228 +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. - * - * ON Semiconductor NB7V904M USB Type-C DisplayPort Alt Mode Redriver - */ -#include <stdbool.h> -#include "common.h" -#include "console.h" -#include "ec_commands.h" -#include "i2c.h" -#include "nb7v904m.h" -#include "usb_mux.h" - -#define CPRINTS(format, args...) cprints(CC_USB, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_USB, format, ## args) - -#ifdef CONFIG_NB7V904M_LPM_OVERRIDE -int nb7v904m_lpm_disable = 0; -#endif - -static int nb7v904m_write(const struct usb_mux *me, int offset, int data) -{ - return i2c_write8(me->i2c_port, - me->i2c_addr_flags, - offset, data); - -} - -static int nb7v904m_read(const struct usb_mux *me, int offset, int *regval) -{ - return i2c_read8(me->i2c_port, - me->i2c_addr_flags, - offset, regval); - -} - -static int set_low_power_mode(const struct usb_mux *me, bool enable) -{ - int regval; - int rv; - - rv = nb7v904m_read(me, NB7V904M_REG_GEN_DEV_SETTINGS, ®val); - if (rv) - return rv; -#ifdef CONFIG_NB7V904M_LPM_OVERRIDE - if (nb7v904m_lpm_disable) - enable = 0; -#endif - - if (enable) - regval &= ~NB7V904M_CHIP_EN; - else - regval |= NB7V904M_CHIP_EN; - - return nb7v904m_write(me, NB7V904M_REG_GEN_DEV_SETTINGS, regval); -} - -static int nb7v904m_enter_low_power_mode(const struct usb_mux *me) -{ - int rv = set_low_power_mode(me, 1); - - if (rv) - CPRINTS("C%d: NB7V904M: Failed to enter low power mode!", - me->usb_port); - return rv; -} - -/* Tune USB Eq All: This must be called on board_init context */ -int nb7v904m_tune_usb_set_eq(const struct usb_mux *me, uint8_t eq_a, - uint8_t eq_b, uint8_t eq_c, uint8_t eq_d) -{ - int rv = EC_SUCCESS; - - if (eq_a != NB7V904M_CH_ALL_SKIP_EQ) - rv = nb7v904m_write(me, NB7V904M_REG_CH_A_EQ_SETTINGS, eq_a); - - if (eq_b != NB7V904M_CH_ALL_SKIP_EQ) - rv |= nb7v904m_write(me, NB7V904M_REG_CH_B_EQ_SETTINGS, eq_b); - - if (eq_c != NB7V904M_CH_ALL_SKIP_EQ) - rv |= nb7v904m_write(me, NB7V904M_REG_CH_C_EQ_SETTINGS, eq_c); - - if (eq_d != NB7V904M_CH_ALL_SKIP_EQ) - rv |= nb7v904m_write(me, NB7V904M_REG_CH_D_EQ_SETTINGS, eq_d); - - return rv; -} - -/* Tune USB Flat Gain: This must be called on board_init context */ -int nb7v904m_tune_usb_flat_gain(const struct usb_mux *me, uint8_t gain_a, - uint8_t gain_b, uint8_t gain_c, uint8_t gain_d) -{ - int rv = EC_SUCCESS; - - if (gain_a != NB7V904M_CH_ALL_SKIP_GAIN) - rv = nb7v904m_write(me, NB7V904M_REG_CH_A_FLAT_GAIN, gain_a); - - if (gain_b != NB7V904M_CH_ALL_SKIP_GAIN) - rv |= nb7v904m_write(me, NB7V904M_REG_CH_B_FLAT_GAIN, gain_b); - - if (gain_c != NB7V904M_CH_ALL_SKIP_GAIN) - rv |= nb7v904m_write(me, NB7V904M_REG_CH_C_FLAT_GAIN, gain_c); - - if (gain_d != NB7V904M_CH_ALL_SKIP_GAIN) - rv |= nb7v904m_write(me, NB7V904M_REG_CH_D_FLAT_GAIN, gain_d); - - return rv; -} - -/* Set Loss Profile Matching : This must be called on board_init context */ -int nb7v904m_set_loss_profile_match(const struct usb_mux *me, uint8_t loss_a, - uint8_t loss_b, uint8_t loss_c, uint8_t loss_d) -{ - int rv = EC_SUCCESS; - - if (loss_a != NB7V904M_CH_ALL_SKIP_LOSS) - rv |= nb7v904m_write(me, NB7V904M_REG_CH_A_LOSS_CTRL, loss_a); - - if (loss_b != NB7V904M_CH_ALL_SKIP_LOSS) - rv |= nb7v904m_write(me, NB7V904M_REG_CH_B_LOSS_CTRL, loss_b); - - if (loss_c != NB7V904M_CH_ALL_SKIP_LOSS) - rv |= nb7v904m_write(me, NB7V904M_REG_CH_C_LOSS_CTRL, loss_c); - - if (loss_d != NB7V904M_CH_ALL_SKIP_LOSS) - rv |= nb7v904m_write(me, NB7V904M_REG_CH_D_LOSS_CTRL, loss_d); - - return rv; -} - -/* Set AUX control switch */ -int nb7v904m_set_aux_ch_switch(const struct usb_mux *me, uint8_t aux_ch) -{ - int rv = EC_SUCCESS; - - rv = nb7v904m_write(me, NB7V904M_REG_AUX_CH_CTRL, aux_ch); - return rv; -} - -static int nb7v904m_init(const struct usb_mux *me) -{ - int rv = set_low_power_mode(me, 0); - - if (rv) - CPRINTS("C%d: NB7V904M: init failed!", me->usb_port); - return rv; -} - -static int nb7v904m_set_mux(const struct usb_mux *me, mux_state_t mux_state, - bool *ack_required) -{ - int rv = EC_SUCCESS; - int regval; - int flipped = !!(mux_state & USB_PD_MUX_POLARITY_INVERTED); - - /* This driver does not use host command ACKs */ - *ack_required = false; - - /* Turn off redriver if it's not needed at all. */ - if (mux_state == USB_PD_MUX_NONE) - return nb7v904m_enter_low_power_mode(me); - - rv = nb7v904m_init(me); - if (rv) - return rv; - - /* Clear operation mode field */ - rv = nb7v904m_read(me, NB7V904M_REG_GEN_DEV_SETTINGS, ®val); - if (rv) { - CPRINTS("C%d %s: Failed to obtain dev settings!", - me->usb_port, __func__); - return rv; - } - regval &= ~NB7V904M_OP_MODE_MASK; - - if (mux_state & USB_PD_MUX_USB_ENABLED) { - /* USB with DP */ - if (mux_state & USB_PD_MUX_DP_ENABLED) { - if (flipped) - regval |= NB7V904M_USB_DP_FLIPPED; - else - regval |= NB7V904M_USB_DP_NORMAL; - } else { - /* USB only */ - regval |= NB7V904M_USB_ONLY; - } - - } else if (mux_state & USB_PD_MUX_DP_ENABLED) { - /* 4 lanes DP */ - regval |= NB7V904M_DP_ONLY; - } - - if (mux_state & USB_PD_MUX_DP_ENABLED) { - /* Connect AUX */ - rv = nb7v904m_write(me, NB7V904M_REG_AUX_CH_CTRL, flipped ? - NB7V904M_AUX_CH_FLIPPED : - NB7V904M_AUX_CH_NORMAL); - /* Enable all channels for DP */ - regval |= NB7V904M_CH_EN_MASK; - } else { - /* Disconnect AUX since it's not being used. */ - rv = nb7v904m_write(me, NB7V904M_REG_AUX_CH_CTRL, - NB7V904M_AUX_CH_HI_Z); - - /* Disable the unused channels to save power */ - regval &= ~NB7V904M_CH_EN_MASK; - if (flipped) { - /* Only enable channels A & B */ - regval |= NB7V904M_CH_A_EN | NB7V904M_CH_B_EN; - } else { - /* Only enable channels C & D */ - regval |= NB7V904M_CH_C_EN | NB7V904M_CH_D_EN; - } - } - - rv |= nb7v904m_write(me, NB7V904M_REG_GEN_DEV_SETTINGS, regval); - if (rv) - CPRINTS("C%d: %s failed!", me->usb_port, __func__); - - return rv; -} - -const struct usb_mux_driver nb7v904m_usb_redriver_drv = { - .enter_low_power_mode = &nb7v904m_enter_low_power_mode, - .init = &nb7v904m_init, - .set = &nb7v904m_set_mux, -}; diff --git a/driver/retimer/nb7v904m.h b/driver/retimer/nb7v904m.h deleted file mode 100644 index d19602153c..0000000000 --- a/driver/retimer/nb7v904m.h +++ /dev/null @@ -1,133 +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. - * - * ON Semiconductor NB7V904M USB Type-C DisplayPort Alt Mode Redriver - */ - -#ifndef __CROS_EC_USB_REDRIVER_NB7V904M_H -#define __CROS_EC_USB_REDRIVER_NB7V904M_H - -#include "compile_time_macros.h" -#include "usb_mux.h" - -#define NB7V904M_I2C_ADDR0 0x19 -#define NB7V904M_I2C_ADDR1 0x1A -#define NB7V904M_I2C_ADDR2 0x1C - -/* Registers */ -#define NB7V904M_REG_GEN_DEV_SETTINGS 0x00 -#define NB7V904M_REG_CH_A_EQ_SETTINGS 0x01 -#define NB7V904M_REG_CH_B_EQ_SETTINGS 0x03 -#define NB7V904M_REG_CH_C_EQ_SETTINGS 0x05 -#define NB7V904M_REG_CH_D_EQ_SETTINGS 0x07 -#define NB7V904M_REG_AUX_CH_CTRL 0x09 -#define NB7V904M_REG_CH_A_FLAT_GAIN 0x18 -#define NB7V904M_REG_CH_A_LOSS_CTRL 0x19 -#define NB7V904M_REG_CH_B_FLAT_GAIN 0x1a -#define NB7V904M_REG_CH_B_LOSS_CTRL 0x1b -#define NB7V904M_REG_CH_C_FLAT_GAIN 0x1c -#define NB7V904M_REG_CH_C_LOSS_CTRL 0x1d -#define NB7V904M_REG_CH_D_FLAT_GAIN 0x1e -#define NB7V904M_REG_CH_D_LOSS_CTRL 0x1f - -/* 0x00 - General Device Settings */ -#define NB7V904M_CHIP_EN BIT(0) -#define NB7V904M_USB_DP_NORMAL BIT(1) -#define NB7V904M_USB_DP_FLIPPED 0 -#define NB7V904M_DP_ONLY BIT(2) -#define NB7V904M_USB_ONLY (BIT(3) | BIT(1)) -#define NB7V904M_OP_MODE_MASK GENMASK(3, 1) -#define NB7V904M_CH_A_EN BIT(4) -#define NB7V904M_CH_B_EN BIT(5) -#define NB7V904M_CH_C_EN BIT(6) -#define NB7V904M_CH_D_EN BIT(7) -#define NB7V904M_CH_EN_MASK GENMASK(7, 4) - -/* 0x01 - Channel A Equalization Settings */ -#define NB7V904M_CH_A_EQ_0_DB 0x0a -#define NB7V904M_CH_A_EQ_2_DB 0x08 -#define NB7V904M_CH_A_EQ_4_DB 0x0e -#define NB7V904M_CH_A_EQ_6_DB 0x0c -#define NB7V904M_CH_A_EQ_8_DB 0x02 -#define NB7V904M_CH_A_EQ_10_DB 0x00 - -/* 0x03 - Channel B Equalization Settings */ -#define NB7V904M_CH_B_EQ_0_DB 0x0e -#define NB7V904M_CH_B_EQ_2_DB 0x0c -#define NB7V904M_CH_B_EQ_4_DB 0x0a -#define NB7V904M_CH_B_EQ_6_DB 0x08 -#define NB7V904M_CH_B_EQ_8_DB 0x06 -#define NB7V904M_CH_B_EQ_10_DB 0x00 - -/* 0x05 - Channel C Equalization Settings */ -#define NB7V904M_CH_C_EQ_0_DB 0x0e -#define NB7V904M_CH_C_EQ_2_DB 0x0c -#define NB7V904M_CH_C_EQ_4_DB 0x0a -#define NB7V904M_CH_C_EQ_6_DB 0x08 -#define NB7V904M_CH_C_EQ_8_DB 0x06 -#define NB7V904M_CH_C_EQ_10_DB 0x00 - -/* 0x07 - Channel D Equalization Settings */ -#define NB7V904M_CH_D_EQ_0_DB 0x0a -#define NB7V904M_CH_D_EQ_2_DB 0x08 -#define NB7V904M_CH_D_EQ_4_DB 0x0e -#define NB7V904M_CH_D_EQ_6_DB 0x0c -#define NB7V904M_CH_D_EQ_8_DB 0x02 -#define NB7V904M_CH_D_EQ_10_DB 0x00 - -/* 0x09 - Auxiliary Channel Control */ -#define NB7V904M_AUX_CH_NORMAL 0 -#define NB7V904M_AUX_CH_FLIPPED BIT(0) -#define NB7V904M_AUX_CH_HI_Z BIT(1) - -/* 0x18 - Channel A Flag Gain */ -#define NB7V904M_CH_A_GAIN_0_DB 0x00 -#define NB7V904M_CH_A_GAIN_1P5_DB 0x02 -#define NB7V904M_CH_A_GAIN_3P5_DB 0x03 - -/* 0x1a - Channel B Flag Gain */ -#define NB7V904M_CH_B_GAIN_0_DB 0x03 -#define NB7V904M_CH_B_GAIN_1P5_DB 0x01 -#define NB7V904M_CH_B_GAIN_3P5_DB 0x00 - -/* 0x1c - Channel C Flag Gain */ -#define NB7V904M_CH_C_GAIN_0_DB 0x03 -#define NB7V904M_CH_C_GAIN_1P5_DB 0x01 -#define NB7V904M_CH_C_GAIN_3P5_DB 0x00 - -/* 0x1e - Channel D Flag Gain */ -#define NB7V904M_CH_D_GAIN_0_DB 0x00 -#define NB7V904M_CH_D_GAIN_1P5_DB 0x02 -#define NB7V904M_CH_D_GAIN_3P5_DB 0x03 - -/* 0x19 - Channel A Loss Profile Matching Control */ -/* 0x1b - Channel B Loss Profile Matching Control */ -/* 0x1d - Channel C Loss Profile Matching Control */ -/* 0x1f - Channel D Loss Profile Matching Control */ -#define NB7V904M_LOSS_PROFILE_A 0x00 -#define NB7V904M_LOSS_PROFILE_B 0x01 -#define NB7V904M_LOSS_PROFILE_C 0x02 -#define NB7V904M_LOSS_PROFILE_D 0x03 - -extern const struct usb_mux_driver nb7v904m_usb_redriver_drv; -#ifdef CONFIG_NB7V904M_LPM_OVERRIDE -extern int nb7v904m_lpm_disable; -#endif - -/* Use this value if tuning eq wants to be skipped */ -#define NB7V904M_CH_ALL_SKIP_EQ 0xff -int nb7v904m_tune_usb_set_eq(const struct usb_mux *me, uint8_t eq_a, - uint8_t eq_b, uint8_t eq_c, uint8_t eq_d); -/* Use this value if tuning gain wants to be skipped */ -#define NB7V904M_CH_ALL_SKIP_GAIN 0xff -int nb7v904m_tune_usb_flat_gain(const struct usb_mux *me, uint8_t gain_a, - uint8_t gain_b, uint8_t gain_c, uint8_t gain_d); -/* Use this value if loss profile control wants to be skipped */ -#define NB7V904M_CH_ALL_SKIP_LOSS 0xff -/* Control channel Loss Profile Matching */ -int nb7v904m_set_loss_profile_match(const struct usb_mux *me, uint8_t loss_a, - uint8_t loss_b, uint8_t loss_c, uint8_t loss_d); -/* Control mapping between AUX and SBU */ -int nb7v904m_set_aux_ch_switch(const struct usb_mux *me, uint8_t aux_ch); -#endif /* __CROS_EC_USB_REDRIVER_NB7V904M_H */ diff --git a/driver/retimer/pi3dpx1207.c b/driver/retimer/pi3dpx1207.c deleted file mode 100644 index 8829c508a1..0000000000 --- a/driver/retimer/pi3dpx1207.c +++ /dev/null @@ -1,146 +0,0 @@ -/* Copyright 2019 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. - * - * PI3DPX1207 retimer. - */ - -#include "pi3dpx1207.h" -#include "common.h" -#include "console.h" -#include "gpio.h" -#include "i2c.h" -#include "ioexpander.h" -#include "usb_mux.h" - -#define I2C_MAX_RETRIES 2 - -/* Stack space is limited, so put the buffer somewhere else */ -static uint8_t buf[PI3DPX1207_NUM_REGISTERS]; - -/** - * Local utility functions - */ -static int pi3dpx1207_i2c_write(const struct usb_mux *me, - uint8_t offset, - uint8_t val) -{ - int rv = EC_SUCCESS; - int attempt; - - if (offset >= PI3DPX1207_NUM_REGISTERS) - return EC_ERROR_INVAL; - - /* - * PI3DPX1207 does not support device register offset in - * the typical I2C sense. Have to read the values starting - * from 0, modify the byte and then write the block. - * - * NOTE: The device may not respond correctly if it was - * just powered or has gone to sleep. Allow for retries - * in case this happens. - */ - if (offset > 0) { - attempt = 0; - do { - attempt++; - rv = i2c_xfer(me->i2c_port, me->i2c_addr_flags, - NULL, 0, buf, offset); - } while ((rv != EC_SUCCESS) && (attempt < I2C_MAX_RETRIES)); - } - - if (rv == EC_SUCCESS) { - buf[offset] = val; - - attempt = 0; - do { - attempt++; - rv = i2c_xfer(me->i2c_port, me->i2c_addr_flags, - buf, offset + 1, NULL, 0); - } while ((rv != EC_SUCCESS) && (attempt < I2C_MAX_RETRIES)); - } - return rv; -} - -static void pi3dpx1207_shutoff_power(const struct usb_mux *me) -{ - const int port = me->usb_port; - const int gpio_enable = pi3dpx1207_controls[port].enable_gpio; - const int gpio_dp_enable = pi3dpx1207_controls[port].dp_enable_gpio; - - gpio_or_ioex_set_level(gpio_enable, 0); - gpio_or_ioex_set_level(gpio_dp_enable, 0); -} - -/** - * Driver interface code - */ -static int pi3dpx1207_init(const struct usb_mux *me) -{ - const int port = me->usb_port; - const int gpio_enable = pi3dpx1207_controls[port].enable_gpio; - - gpio_or_ioex_set_level(gpio_enable, 1); - return EC_SUCCESS; -} - -static int pi3dpx1207_enter_low_power_mode(const struct usb_mux *me) -{ - pi3dpx1207_shutoff_power(me); - return EC_SUCCESS; -} - -static int pi3dpx1207_set_mux(const struct usb_mux *me, mux_state_t mux_state, - bool *ack_required) -{ - int rv = EC_SUCCESS; - uint8_t mode_val = PI3DPX1207_MODE_WATCHDOG_EN; - const int port = me->usb_port; - const int gpio_enable = pi3dpx1207_controls[port].enable_gpio; - const int gpio_dp_enable = pi3dpx1207_controls[port].dp_enable_gpio; - - /* This driver does not use host command ACKs */ - *ack_required = false; - - /* USB */ - if (mux_state & USB_PD_MUX_USB_ENABLED) { - gpio_or_ioex_set_level(gpio_enable, 1); - /* USB with DP */ - if (mux_state & USB_PD_MUX_DP_ENABLED) { - gpio_or_ioex_set_level(gpio_dp_enable, 1); - mode_val |= (mux_state & USB_PD_MUX_POLARITY_INVERTED) - ? PI3DPX1207_MODE_CONF_USB_DP_FLIP - : PI3DPX1207_MODE_CONF_USB_DP; - } - /* USB without DP */ - else { - gpio_or_ioex_set_level(gpio_dp_enable, 0); - mode_val |= (mux_state & USB_PD_MUX_POLARITY_INVERTED) - ? PI3DPX1207_MODE_CONF_USB_FLIP - : PI3DPX1207_MODE_CONF_USB; - } - } - /* DP without USB */ - else if (mux_state & USB_PD_MUX_DP_ENABLED) { - gpio_or_ioex_set_level(gpio_enable, 1); - gpio_or_ioex_set_level(gpio_dp_enable, 1); - mode_val |= (mux_state & USB_PD_MUX_POLARITY_INVERTED) - ? PI3DPX1207_MODE_CONF_DP_FLIP - : PI3DPX1207_MODE_CONF_DP; - } - /* Nothing enabled, power down the retimer */ - else { - pi3dpx1207_shutoff_power(me); - return EC_SUCCESS; - } - - /* Write the retimer config byte */ - rv = pi3dpx1207_i2c_write(me, PI3DPX1207_MODE_OFFSET, mode_val); - return rv; -} - -const struct usb_mux_driver pi3dpx1207_usb_retimer = { - .init = pi3dpx1207_init, - .set = pi3dpx1207_set_mux, - .enter_low_power_mode = pi3dpx1207_enter_low_power_mode, -}; diff --git a/driver/retimer/pi3dpx1207.h b/driver/retimer/pi3dpx1207.h deleted file mode 100644 index 2e3405d1aa..0000000000 --- a/driver/retimer/pi3dpx1207.h +++ /dev/null @@ -1,54 +0,0 @@ -/* Copyright 2019 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. - * - * PI3DPX1207 retimer. - */ -#include "gpio.h" - -#ifndef __CROS_EC_USB_RETIMER_PI3PDX1207_H -#define __CROS_EC_USB_RETIMER_PI3PDX1207_H - -#define PI3DPX1207_I2C_ADDR_FLAGS 0x57 -#define PI3DPX1207_NUM_REGISTERS 32 - -/* Register Offset 0 - Revision and Vendor ID */ -#define PI3DPX1207_VID_OFFSET 0 - -#define PI3DPX1207B_VID 0x03 -#define PI3DPX1207C_VID 0x13 - -/* Register Offset 1 - Device Type/ID */ -#define PI3DPX1207_DID_OFFSET 1 - -#define PI3DPX1207_DID_ACTIVE_MUX 0x11 - -/* Register Offset 3 - Mode Control */ -#define PI3DPX1207_MODE_OFFSET 3 - -#define PI3DPX1207_MODE_WATCHDOG_EN 0x02 - -#define PI3DPX1207B_MODE_GEN_APP_EN 0x08 - -#define PI3DPX1207_MODE_CONF_SAFE 0x00 -#define PI3DPX1207_MODE_CONF_DP 0x20 -#define PI3DPX1207_MODE_CONF_DP_FLIP 0x30 -#define PI3DPX1207_MODE_CONF_USB 0x40 -#define PI3DPX1207_MODE_CONF_USB_FLIP 0x50 -#define PI3DPX1207_MODE_CONF_USB_DP 0x60 -#define PI3DPX1207_MODE_CONF_USB_DP_FLIP 0x70 -#define PI3DPX1207_MODE_CONF_USB_SUPER 0xC0 - -/* Supported USB retimer drivers */ -extern const struct usb_mux_driver pi3dpx1207_usb_retimer; - -/* Retimer driver hardware specific controls */ -struct pi3dpx1207_usb_control { - /* Retimer enable */ - const enum gpio_signal enable_gpio; - /* DP Mode enable */ - const enum gpio_signal dp_enable_gpio; -}; -extern const struct pi3dpx1207_usb_control pi3dpx1207_controls[]; - -#endif /* __CROS_EC_USB_RETIMER_PI3PDX1207_H */ diff --git a/driver/retimer/pi3hdx1204.c b/driver/retimer/pi3hdx1204.c deleted file mode 100644 index 3b0d80609f..0000000000 --- a/driver/retimer/pi3hdx1204.c +++ /dev/null @@ -1,37 +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. - * - * PI3HDX1204 retimer. - */ - -#include "i2c.h" -#include "pi3hdx1204.h" - -int pi3hdx1204_enable(const int i2c_port, - const uint16_t i2c_addr_flags, - const int enable) -{ - const uint8_t buf[PI3HDX1204_DE_OFFSET + 1] = { - [PI3HDX1204_ACTIVITY_OFFSET] = 0, /* Read Only */ - [PI3HDX1204_NOT_USED_OFFSET] = 0, /* Read Only */ - [PI3HDX1204_ENABLE_OFFSET] = - enable ? PI3HDX1204_ENABLE_ALL_CHANNELS : 0, - [PI3HDX1204_EQ_CH0_CH1_OFFSET] = - pi3hdx1204_tuning.eq_ch0_ch1_offset, - [PI3HDX1204_EQ_CH2_CH3_OFFSET] = - pi3hdx1204_tuning.eq_ch2_ch3_offset, - [PI3HDX1204_VOD_OFFSET] = pi3hdx1204_tuning.vod_offset, - [PI3HDX1204_DE_OFFSET] = pi3hdx1204_tuning.de_offset, - }; - int rv; - - rv = i2c_xfer(i2c_port, i2c_addr_flags, - buf, PI3HDX1204_DE_OFFSET + 1, - NULL, 0); - - if (rv) - ccprints("pi3hdx1204 enable failed: %d", rv); - - return rv; -} diff --git a/driver/retimer/pi3hdx1204.h b/driver/retimer/pi3hdx1204.h deleted file mode 100644 index 825f502602..0000000000 --- a/driver/retimer/pi3hdx1204.h +++ /dev/null @@ -1,77 +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. - * - * PI3HDX1204 retimer. - */ - -#ifndef __CROS_EC_USB_RETIMER_PI3HDX1204_H -#define __CROS_EC_USB_RETIMER_PI3HDX1204_H - -#define PI3HDX1204_I2C_ADDR_FLAGS 0x60 - -/* Register Offset 0 - Activity */ -#define PI3HDX1204_ACTIVITY_OFFSET 0 - -/* Register Offset 1 - Not Used */ -#define PI3HDX1204_NOT_USED_OFFSET 1 - -/* Register Offset 2 - Enable */ -#define PI3HDX1204_ENABLE_OFFSET 2 -#define PI3HDX1204_ENABLE_ALL_CHANNELS 0xF0 - -/* Register Offset 3 - EQ setting BIT7-4:CH1, BIT3-0:CH0 */ -#define PI3HDX1204_EQ_CH0_CH1_OFFSET 3 - -/* Register Offset 4 - EQ setting BIT7-4:CH3, BIT3-0:CH2 */ -#define PI3HDX1204_EQ_CH2_CH3_OFFSET 4 - -/* EQ setting for two channel */ -#define PI3HDX1204_EQ_DB25 0x00 -#define PI3HDX1204_EQ_DB80 0x11 -#define PI3HDX1204_EQ_DB110 0x22 -#define PI3HDX1204_EQ_DB220 0x33 -#define PI3HDX1204_EQ_DB410 0x44 -#define PI3HDX1204_EQ_DB710 0x55 -#define PI3HDX1204_EQ_DB900 0x66 -#define PI3HDX1204_EQ_DB1030 0x77 -#define PI3HDX1204_EQ_DB1180 0x88 -#define PI3HDX1204_EQ_DB1390 0x99 -#define PI3HDX1204_EQ_DB1530 0xAA -#define PI3HDX1204_EQ_DB1690 0xBB -#define PI3HDX1204_EQ_DB1790 0xCC -#define PI3HDX1204_EQ_DB1920 0xDD -#define PI3HDX1204_EQ_DB2050 0xEE -#define PI3HDX1204_EQ_DB2220 0xFF - -/* Register Offset 5 - Output Voltage Swing Setting */ -#define PI3HDX1204_VOD_OFFSET 5 -#define PI3HDX1204_VOD_80_ALL_CHANNELS 0x00 -#define PI3HDX1204_VOD_95_ALL_CHANNELS 0x55 -#define PI3HDX1204_VOD_115_ALL_CHANNELS 0xAA -#define PI3HDX1204_VOD_130_ALL_CHANNELS 0xFF - -/* Register Offset 6 - Output De-emphasis Setting */ -#define PI3HDX1204_DE_OFFSET 6 -#define PI3HDX1204_DE_DB_0 0x00 -#define PI3HDX1204_DE_DB_MINUS5 0x55 -#define PI3HDX1204_DE_DB_MINUS7 0xAA -#define PI3HDX1204_DE_DB_MINUS10 0xFF - -/* Delay for I2C to be ready after power on. */ -#define PI3HDX1204_POWER_ON_DELAY_MS 2 - -/* Enable or disable the PI3HDX1204. */ -int pi3hdx1204_enable(const int i2c_port, - const uint16_t i2c_addr_flags, - const int enable); - -struct pi3hdx1204_tuning { - uint8_t eq_ch0_ch1_offset; - uint8_t eq_ch2_ch3_offset; - uint8_t vod_offset; - uint8_t de_offset; -}; -extern const struct pi3hdx1204_tuning pi3hdx1204_tuning; - -#endif /* __CROS_EC_USB_RETIMER_PI3HDX1204_H */ diff --git a/driver/retimer/ps8802.c b/driver/retimer/ps8802.c deleted file mode 100644 index 9738123ace..0000000000 --- a/driver/retimer/ps8802.c +++ /dev/null @@ -1,317 +0,0 @@ -/* Copyright 2019 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. - * - * PS8802 retimer. - */ - -#include "chipset.h" -#include "common.h" -#include "console.h" -#include "i2c.h" -#include "ps8802.h" -#include "timer.h" -#include "usb_mux.h" - -#define PS8802_DEBUG 0 -#define PS8802_I2C_WAKE_DELAY 500 - -#define CPRINTS(format, args...) cprints(CC_USB, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_USB, format, ## args) - -int ps8802_i2c_read(const struct usb_mux *me, int page, int offset, int *data) -{ - int rv; - - rv = i2c_read8(me->i2c_port, - me->i2c_addr_flags + page, - offset, data); - - if (PS8802_DEBUG) - ccprintf("%s(%d:0x%02X, 0x%02X) =>0x%02X\n", __func__, - me->i2c_port, - me->i2c_addr_flags + page, - offset, *data); - - return rv; -} - -int ps8802_i2c_write(const struct usb_mux *me, int page, int offset, int data) -{ - int rv; - int pre_val, post_val; - - if (PS8802_DEBUG) - i2c_read8(me->i2c_port, - me->i2c_addr_flags + page, - offset, &pre_val); - - rv = i2c_write8(me->i2c_port, - me->i2c_addr_flags + page, - offset, data); - - if (PS8802_DEBUG) { - i2c_read8(me->i2c_port, - me->i2c_addr_flags + page, - offset, &post_val); - - ccprintf("%s(%d:0x%02X, 0x%02X, 0x%02X) " - "0x%02X=>0x%02X\n", - __func__, - me->i2c_port, - me->i2c_addr_flags + page, - offset, data, - pre_val, post_val); - } - - return rv; -} - -int ps8802_i2c_write16(const struct usb_mux *me, int page, int offset, - int data) -{ - int rv; - int pre_val, post_val; - - if (PS8802_DEBUG) - i2c_read16(me->i2c_port, - me->i2c_addr_flags + page, - offset, &pre_val); - - rv = i2c_write16(me->i2c_port, - me->i2c_addr_flags + page, - offset, data); - - if (PS8802_DEBUG) { - i2c_read16(me->i2c_port, - me->i2c_addr_flags + page, - offset, &post_val); - - ccprintf("%s(%d:0x%02X, 0x%02X, 0x%04X) " - "0x%04X=>0x%04X\n", - __func__, - me->i2c_port, - me->i2c_addr_flags + page, - offset, data, - pre_val, post_val); - } - - return rv; -} - -int ps8802_i2c_field_update8(const struct usb_mux *me, int page, int offset, - uint8_t field_mask, uint8_t set_value) -{ - int rv; - int pre_val, post_val; - - if (PS8802_DEBUG) - i2c_read8(me->i2c_port, - me->i2c_addr_flags + page, - offset, &pre_val); - - rv = i2c_field_update8(me->i2c_port, - me->i2c_addr_flags + page, - offset, - field_mask, - set_value); - - if (PS8802_DEBUG) { - i2c_read8(me->i2c_port, - me->i2c_addr_flags + page, - offset, &post_val); - - ccprintf("%s(%d:0x%02X, 0x%02X, 0x%02X, 0x%02X) " - "0x%02X=>0x%02X\n", - __func__, - me->i2c_port, - me->i2c_addr_flags + page, - offset, field_mask, set_value, - pre_val, post_val); - } - - return rv; -} - -int ps8802_i2c_field_update16(const struct usb_mux *me, int page, int offset, - uint16_t field_mask, uint16_t set_value) -{ - int rv; - int pre_val, post_val; - - if (PS8802_DEBUG) - i2c_read16(me->i2c_port, - me->i2c_addr_flags + page, - offset, &pre_val); - - rv = i2c_field_update16(me->i2c_port, - me->i2c_addr_flags + page, - offset, - field_mask, - set_value); - - if (PS8802_DEBUG) { - i2c_read16(me->i2c_port, - me->i2c_addr_flags + page, - offset, &post_val); - - ccprintf("%s(%d:0x%02X, 0x%02X, 0x%02X, 0x%04X) " - "0x%04X=>0x%04X\n", - __func__, - me->i2c_port, - me->i2c_addr_flags + page, - offset, field_mask, set_value, - pre_val, post_val); - } - - return rv; -} - -/* - * If PS8802 is in I2C standby mode, wake it up by reading PS8802_REG_MODE. - * From Application Note: 1) Activate by reading any Page 2 register. 2) Wait - * 500 microseconds. 3) After 5 seconds idle, PS8802 will return to standby. - */ -int ps8802_i2c_wake(const struct usb_mux *me) -{ - int data; - int rv = EC_ERROR_UNKNOWN; - - /* If in standby, first read will fail, second should succeed. */ - for (int i = 0; i < 2; i++) { - rv = ps8802_i2c_read(me, - PS8802_REG_PAGE2, - PS8802_REG2_MODE, - &data); - if (rv == EC_SUCCESS) - return rv; - - usleep(PS8802_I2C_WAKE_DELAY); - } - - return rv; -} - -/* - * Setting operation mode to standby mode - */ -static int ps8802_enter_low_power_mode(const struct usb_mux *me) -{ - int rv; - - rv = ps8802_i2c_write(me, PS8802_REG_PAGE2, PS8802_REG2_MODE, - PS8802_MODE_STANDBY_MODE); - - if (rv) - CPRINTS("C%d: PS8802: Failed to enter low power mode!", - me->usb_port); - - return rv; -} - -static int ps8802_init(const struct usb_mux *me) -{ - ps8802_enter_low_power_mode(me); - return EC_SUCCESS; -} - -static int ps8802_set_mux(const struct usb_mux *me, mux_state_t mux_state, - bool *ack_required) -{ - int val; - int rv; - - /* This driver does not use host command ACKs */ - *ack_required = false; - - if (chipset_in_state(CHIPSET_STATE_HARD_OFF)) - return (mux_state == USB_PD_MUX_NONE) ? EC_SUCCESS - : EC_ERROR_NOT_POWERED; - - /* Make sure the PS8802 is awake */ - rv = ps8802_i2c_wake(me); - if (rv) - return rv; - - if (PS8802_DEBUG) - ccprintf("%s(%d, 0x%02X) %s %s %s\n", - __func__, me->usb_port, mux_state, - (mux_state & USB_PD_MUX_USB_ENABLED) ? "USB" : "", - (mux_state & USB_PD_MUX_DP_ENABLED) ? "DP" : "", - (mux_state & USB_PD_MUX_POLARITY_INVERTED) - ? "FLIP" : ""); - - /* Set the mode and flip */ - val = (PS8802_MODE_DP_REG_CONTROL | - PS8802_MODE_USB_REG_CONTROL | - PS8802_MODE_FLIP_REG_CONTROL | - PS8802_MODE_IN_HPD_REG_CONTROL); - - if (mux_state & USB_PD_MUX_USB_ENABLED) - val |= PS8802_MODE_USB_ENABLE; - if (mux_state & USB_PD_MUX_DP_ENABLED) - val |= PS8802_MODE_DP_ENABLE | PS8802_MODE_IN_HPD_ENABLE; - if (mux_state & USB_PD_MUX_POLARITY_INVERTED) - val |= PS8802_MODE_FLIP_ENABLE; - - rv = ps8802_i2c_write(me, - PS8802_REG_PAGE2, - PS8802_REG2_MODE, - val); - - return rv; -} - -static int ps8802_get_mux(const struct usb_mux *me, mux_state_t *mux_state) -{ - int rv; - int val; - - *mux_state = USB_PD_MUX_NONE; - - if (chipset_in_state(CHIPSET_STATE_HARD_OFF)) - return EC_ERROR_NOT_POWERED; - - rv = ps8802_i2c_wake(me); - if (rv) - return rv; - - rv = ps8802_i2c_read(me, - PS8802_REG_PAGE2, - PS8802_REG2_MODE, - &val); - if (rv) - return rv; - - if (val & PS8802_MODE_USB_ENABLE) - *mux_state |= USB_PD_MUX_USB_ENABLED; - if (val & PS8802_MODE_DP_ENABLE) - *mux_state |= USB_PD_MUX_DP_ENABLED; - if (val & PS8802_MODE_FLIP_ENABLE) - *mux_state |= USB_PD_MUX_POLARITY_INVERTED; - - return rv; -} - -const struct usb_mux_driver ps8802_usb_mux_driver = { - .init = ps8802_init, - .set = ps8802_set_mux, - .get = ps8802_get_mux, - .enter_low_power_mode = &ps8802_enter_low_power_mode, -}; - -/* - * If PS8802 I2c address was conflicted, change - * the I2c address in page 0x0A, offset 0xB0 - * switch to 0x50 8-bit address - */ -int ps8802_chg_i2c_addr(int i2c_port) -{ - int rv; - - rv = i2c_write8(i2c_port, - PS8802_P1_ADDR, PS8802_ADDR_CFG, - PS8802_I2C_ADDR_FLAGS_ALT); - - return rv; -} diff --git a/driver/retimer/ps8802.h b/driver/retimer/ps8802.h deleted file mode 100644 index 858b83bfc7..0000000000 --- a/driver/retimer/ps8802.h +++ /dev/null @@ -1,114 +0,0 @@ -/* Copyright 2019 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. - * - * PS8802 retimer. - */ -#include "usb_mux.h" - -#ifndef __CROS_EC_USB_RETIMER_PS8802_H -#define __CROS_EC_USB_RETIMER_PS8802_H - -/* - * PS8802 uses 7-bit I2C addresses 0x08 to 0x17 (ADDR=L). - * Page 0 = 0x08, Page 1 = 0x09, Page 2 = 0x0A. - */ -#define PS8802_I2C_ADDR_FLAGS 0x08 - -/* - * PS8802 uses 7-bit I2C addresses 0x28 to 0x37. - * Page 0 = 0x028, Page 1 = 0x29, Page 2 = 0x2A. - */ -#define PS8802_I2C_ADDR_FLAGS_CUSTOM 0x28 - -/* - * PAGE 0 Register Definitions - */ -#define PS8802_REG_PAGE0 0x00 - -#define PS8802_REG0_TX_STATUS 0x72 -#define PS8802_REG0_RX_STATUS 0x76 -#define PS8802_STATUS_NORMAL_OPERATION BIT(7) -#define PS8802_STATUS_10_GBPS BIT(5) - -/* - * PAGE 1 Register Definitions - */ -#define PS8802_REG_PAGE1 0x01 - -#define PS8802_800MV_LEVEL_TUNING 0x8A -#define PS8802_EXTRA_SWING_LEVEL_P0_DEFAULT 0X00 -#define PS8802_EXTRA_SWING_LEVEL_P0_DOWN_1 0X01 -#define PS8802_EXTRA_SWING_LEVEL_P0_DOWN_2 0X02 -#define PS8802_EXTRA_SWING_LEVEL_P0_DOWN_3 0X03 -#define PS8802_EXTRA_SWING_LEVEL_P0_DOWN_4 0X04 -#define PS8802_EXTRA_SWING_LEVEL_P0_UP_1 0X05 -#define PS8802_EXTRA_SWING_LEVEL_P0_UP_2 0X06 -#define PS8802_EXTRA_SWING_LEVEL_P0_UP_3 0X07 -#define PS8802_EXTRA_SWING_LEVEL_P0_MASK 0X07 - -/* - * PAGE 2 Register Definitions - */ -#define PS8802_REG_PAGE2 0x02 - -#define PS8802_REG2_USB_SSEQ_LEVEL 0x02 -#define PS8802_REG2_USB_CEQ_LEVEL 0x04 -#define PS8802_USBEQ_LEVEL_UP_12DB (0x0000 | 0x0003) -#define PS8802_USBEQ_LEVEL_UP_13DB (0x0400 | 0x0007) -#define PS8802_USBEQ_LEVEL_UP_16DB (0x0C00 | 0x000F) -#define PS8802_USBEQ_LEVEL_UP_17DB (0x1C00 | 0x001F) -#define PS8802_USBEQ_LEVEL_UP_18DB (0x3C00 | 0x003F) -#define PS8802_USBEQ_LEVEL_UP_19DB (0x7C00 | 0x007F) -#define PS8802_USBEQ_LEVEL_UP_20DB (0xFC00 | 0x00FF) -#define PS8802_USBEQ_LEVEL_UP_23DB (0xFD00 | 0x01FF) -#define PS8802_USBEQ_LEVEL_UP_MASK 0xFDFF - -#define PS8802_REG2_MODE 0x06 -#define PS8802_MODE_DP_REG_CONTROL BIT(7) -#define PS8802_MODE_DP_ENABLE BIT(6) -#define PS8802_MODE_USB_REG_CONTROL BIT(5) -#define PS8802_MODE_USB_ENABLE BIT(4) -#define PS8802_MODE_FLIP_REG_CONTROL BIT(3) -#define PS8802_MODE_FLIP_ENABLE BIT(2) -#define PS8802_MODE_IN_HPD_REG_CONTROL BIT(1) -#define PS8802_MODE_IN_HPD_ENABLE BIT(0) - -/* - * Support power saving mode, Bit7 Disable - * CE_DP, Bit5 Disable CE_USB, Bit3 Disable - * FLIP pin, Bit1 Display IN_HPD pin, [Bit6 Bit4] - * 00: I2C standy by mode. - */ -#define PS8802_MODE_STANDBY_MODE 0xAA - -#define PS8802_REG2_DPEQ_LEVEL 0x07 -#define PS8802_DPEQ_LEVEL_UP_9DB 0x00 -#define PS8802_DPEQ_LEVEL_UP_11DB 0x01 -#define PS8802_DPEQ_LEVEL_UP_12DB 0x02 -#define PS8802_DPEQ_LEVEL_UP_14DB 0x03 -#define PS8802_DPEQ_LEVEL_UP_17DB 0x04 -#define PS8802_DPEQ_LEVEL_UP_18DB 0x05 -#define PS8802_DPEQ_LEVEL_UP_19DB 0x06 -#define PS8802_DPEQ_LEVEL_UP_20DB 0x07 -#define PS8802_DPEQ_LEVEL_UP_21DB 0x08 -#define PS8802_DPEQ_LEVEL_UP_MASK 0x0F - -#define PS8802_P1_ADDR 0x0A -#define PS8802_ADDR_CFG 0xB0 -#define PS8802_I2C_ADDR_FLAGS_ALT 0x50 - -extern const struct usb_mux_driver ps8802_usb_mux_driver; - -int ps8802_i2c_wake(const struct usb_mux *me); -int ps8802_i2c_read(const struct usb_mux *me, int page, int offset, int *data); -int ps8802_i2c_write(const struct usb_mux *me, int page, int offset, int data); -int ps8802_i2c_write16(const struct usb_mux *me, int page, int offset, - int data); -int ps8802_i2c_field_update8(const struct usb_mux *me, int page, int offset, - uint8_t field_mask, uint8_t set_value); -int ps8802_i2c_field_update16(const struct usb_mux *me, int page, int offset, - uint16_t field_mask, uint16_t set_value); -int ps8802_chg_i2c_addr(int i2c_port); - -#endif /* __CROS_EC_USB_RETIMER_PS8802_H */ diff --git a/driver/retimer/ps8811.c b/driver/retimer/ps8811.c deleted file mode 100644 index 6a66248d38..0000000000 --- a/driver/retimer/ps8811.c +++ /dev/null @@ -1,48 +0,0 @@ -/* Copyright 2021 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. - * - * PS8811 retimer. - */ - -#include "common.h" -#include "console.h" -#include "i2c.h" -#include "ps8811.h" -#include "usb_mux.h" - -int ps8811_i2c_read(const struct usb_mux *me, int page, int offset, int *data) -{ - int rv; - - rv = i2c_read8(me->i2c_port, - me->i2c_addr_flags + page, - offset, data); - - return rv; -} - -int ps8811_i2c_write(const struct usb_mux *me, int page, int offset, int data) -{ - int rv; - - rv = i2c_write8(me->i2c_port, - me->i2c_addr_flags + page, - offset, data); - - return rv; -} - -int ps8811_i2c_field_update(const struct usb_mux *me, int page, int offset, - uint8_t field_mask, uint8_t set_value) -{ - int rv; - - rv = i2c_field_update8(me->i2c_port, - me->i2c_addr_flags + page, - offset, - field_mask, - set_value); - - return rv; -} diff --git a/driver/retimer/ps8811.h b/driver/retimer/ps8811.h deleted file mode 100644 index c3a98c1660..0000000000 --- a/driver/retimer/ps8811.h +++ /dev/null @@ -1,99 +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. - * - * PS8811 retimer. - */ - -#include "usb_mux.h" - -#ifndef __CROS_EC_USB_RETIMER_PS8811_H -#define __CROS_EC_USB_RETIMER_PS8811_H - -/* - * PS8811 uses 7-bit I2C addresses 0x28 to 0x29 (ADDR=LL). - * Page 0 = 0x28, Page 1 = 0x29. - * PS8811 uses 7-bit I2C addresses 0x2A to 0x2B (ADDR=LH). - * Page 0 = 0x2A, Page 1 = 0x2B. - * PS8811 uses 7-bit I2C addresses 0x70 to 0x71 (ADDR=HL). - * Page 0 = 0x70, Page 1 = 0x71. - * PS8811 uses 7-bit I2C addresses 0x72 to 0x73 (ADDR=HH). - * Page 0 = 0x72, Page 1 = 0x73. - */ -#define PS8811_I2C_ADDR_FLAGS0 0x28 -#define PS8811_I2C_ADDR_FLAGS1 0x2A -#define PS8811_I2C_ADDR_FLAGS2 0x70 -#define PS8811_I2C_ADDR_FLAGS3 0x72 - -/* - * PAGE 1 Register Definitions - */ -#define PS8811_REG_PAGE1 0x01 - -#define PS8811_REG1_USB_BEQ_LEVEL 0x05 -#define PS8811_BEQ_PIN_LEVEL_UP_9DB 0x00 -#define PS8811_BEQ_PIN_LEVEL_UP_10_5DB 0x01 -#define PS8811_BEQ_PIN_LEVEL_UP_12DB 0x02 -#define PS8811_BEQ_PIN_LEVEL_UP_13DB 0x03 -#define PS8811_BEQ_PIN_LEVEL_UP_16DB 0x04 -#define PS8811_BEQ_PIN_LEVEL_UP_17DB 0x05 -#define PS8811_BEQ_PIN_LEVEL_UP_18DB 0x06 -#define PS8811_BEQ_PIN_LEVEL_UP_19DB 0x07 -#define PS8811_BEQ_PIN_LEVEL_UP_20DB 0x08 -#define PS8811_BEQ_PIN_LEVEL_UP_21DB 0x09 -#define PS8811_BEQ_PIN_LEVEL_UP_23DB 0x0A -#define PS8811_BEQ_I2C_LEVEL_UP_9DB 0x00 -#define PS8811_BEQ_I2C_LEVEL_UP_10_5DB 0x10 -#define PS8811_BEQ_I2C_LEVEL_UP_12DB 0x20 -#define PS8811_BEQ_I2C_LEVEL_UP_13DB 0x30 -#define PS8811_BEQ_I2C_LEVEL_UP_16DB 0x40 -#define PS8811_BEQ_I2C_LEVEL_UP_17DB 0x50 -#define PS8811_BEQ_I2C_LEVEL_UP_18DB 0x60 -#define PS8811_BEQ_I2C_LEVEL_UP_19DB 0x70 -#define PS8811_BEQ_I2C_LEVEL_UP_20DB 0x80 -#define PS8811_BEQ_I2C_LEVEL_UP_21DB 0x90 -#define PS8811_BEQ_I2C_LEVEL_UP_23DB 0xA0 - -#define PS8811_REG1_USB_BEQ_CONFIG 0x06 -#define PS8811_BEQ_CONFIG_REG_ENABLE BIT(0) - -#define PS8811_REG1_USB_CHAN_A_SWING 0x66 -#define PS8811_CHAN_A_SWING_MASK GENMASK(6, 4) -#define PS8811_CHAN_A_SWING_SHIFT 4 - -#define PS8811_REG1_USB_CHAN_B_SWING 0xA4 -#define PS8811_CHAN_B_SWING_MASK GENMASK(2, 0) -#define PS8811_CHAN_B_SWING_SHIFT 0 - -/* De-emphasis -2.2 dB, Pre-shoot 1.2 dB */ -#define PS8811_CHAN_B_DE_2_2_PS_1_2_LSB 0x1 -#define PS8811_CHAN_B_DE_2_2_PS_1_2_MSB 0x13 - -/* De-emphasis -3.5 dB, Pre-shoot 0 dB */ -#define PS8811_CHAN_B_DE_3_5_PS_0_LSB 0x0 -#define PS8811_CHAN_B_DE_3_5_PS_0_MSB 0x5 - -/* De-emphasis -4.5 dB, Pre-shoot 0 dB */ -#define PS8811_CHAN_B_DE_4_5_PS_0_LSB 0x0 -#define PS8811_CHAN_B_DE_4_5_PS_0_MSB 0x6 - -/* De-emphasis -6 dB, Pre-shoot 1.5 dB */ -#define PS8811_CHAN_B_DE_6_PS_1_5_LSB 0x2 -#define PS8811_CHAN_B_DE_6_PS_1_5_MSB 0x16 - -/* De-emphasis -6 dB, Pre-shoot 3 dB */ -#define PS8811_CHAN_B_DE_6_PS_3_LSB 0x4 -#define PS8811_CHAN_B_DE_6_PS_3_MSB 0x16 - -#define PS8811_REG1_USB_CHAN_B_DE_PS_LSB 0xA5 -#define PS8811_CHAN_B_DE_PS_LSB_MASK GENMASK(2, 0) - -#define PS8811_REG1_USB_CHAN_B_DE_PS_MSB 0xA6 -#define PS8811_CHAN_B_DE_PS_MSB_MASK GENMASK(5, 0) - -int ps8811_i2c_read(const struct usb_mux *me, int page, int offset, int *data); -int ps8811_i2c_write(const struct usb_mux *me, int page, int offset, int data); -int ps8811_i2c_field_update(const struct usb_mux *me, int page, int offset, - uint8_t field_mask, uint8_t set_value); - -#endif /* __CROS_EC_USB_RETIMER_PS8802_H */ diff --git a/driver/retimer/ps8818.c b/driver/retimer/ps8818.c deleted file mode 100644 index 2f8e353099..0000000000 --- a/driver/retimer/ps8818.c +++ /dev/null @@ -1,165 +0,0 @@ -/* Copyright 2019 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. - * - * PS8818 retimer. - */ - -#include "chipset.h" -#include "common.h" -#include "console.h" -#include "gpio.h" -#include "i2c.h" -#include "ioexpander.h" -#include "ps8818.h" -#include "usb_mux.h" - -#define PS8818_DEBUG 0 - -int ps8818_i2c_read(const struct usb_mux *me, int page, int offset, int *data) -{ - int rv; - - rv = i2c_read8(me->i2c_port, - me->i2c_addr_flags + page, - offset, data); - - if (PS8818_DEBUG) - ccprintf("%s(%d:0x%02X, 0x%02X) =>0x%02X\n", __func__, - me->usb_port, - me->i2c_addr_flags + page, - offset, *data); - - return rv; -} - -int ps8818_i2c_write(const struct usb_mux *me, int page, int offset, int data) -{ - int rv; - int pre_val, post_val; - - if (PS8818_DEBUG) - i2c_read8(me->i2c_port, - me->i2c_addr_flags + page, - offset, &pre_val); - - rv = i2c_write8(me->i2c_port, - me->i2c_addr_flags + page, - offset, data); - - if (PS8818_DEBUG) { - i2c_read8(me->i2c_port, - me->i2c_addr_flags + page, - offset, &post_val); - - ccprintf("%s(%d:0x%02X, 0x%02X, 0x%02X) " - "0x%02X=>0x%02X\n", - __func__, - me->usb_port, - me->i2c_addr_flags + page, - offset, data, - pre_val, post_val); - } - - return rv; -} - -int ps8818_i2c_field_update8(const struct usb_mux *me, int page, int offset, - uint8_t field_mask, uint8_t set_value) -{ - int rv; - int pre_val, post_val; - - if (PS8818_DEBUG) - i2c_read8(me->i2c_port, - me->i2c_addr_flags + page, - offset, &pre_val); - - rv = i2c_field_update8(me->i2c_port, - me->i2c_addr_flags + page, - offset, - field_mask, - set_value); - - if (PS8818_DEBUG) { - i2c_read8(me->i2c_port, - me->i2c_addr_flags + page, - offset, &post_val); - - ccprintf("%s(%d:0x%02X, 0x%02X, 0x%02X, 0x%02X) " - "0x%02X=>0x%02X\n", - __func__, - me->usb_port, - me->i2c_addr_flags + page, - offset, field_mask, set_value, - pre_val, post_val); - } - - return rv; -} - -static int ps8818_set_mux(const struct usb_mux *me, mux_state_t mux_state, - bool *ack_required) -{ - int rv; - int val = 0; - - /* This driver does not use host command ACKs */ - *ack_required = false; - - if (chipset_in_state(CHIPSET_STATE_HARD_OFF)) - return (mux_state == USB_PD_MUX_NONE) ? EC_SUCCESS - : EC_ERROR_NOT_POWERED; - - if (PS8818_DEBUG) - ccprintf("%s(%d, 0x%02X) %s %s %s\n", - __func__, me->usb_port, mux_state, - (mux_state & USB_PD_MUX_USB_ENABLED) ? "USB" : "", - (mux_state & USB_PD_MUX_DP_ENABLED) ? "DP" : "", - (mux_state & USB_PD_MUX_POLARITY_INVERTED) - ? "FLIP" : ""); - - /* Set the mode */ - if (mux_state & USB_PD_MUX_USB_ENABLED) - val |= PS8818_MODE_USB_ENABLE; - if (mux_state & USB_PD_MUX_DP_ENABLED) - val |= PS8818_MODE_DP_ENABLE; - - rv = ps8818_i2c_field_update8(me, - PS8818_REG_PAGE0, - PS8818_REG0_MODE, - PS8818_MODE_NON_RESERVED_MASK, - val); - if (rv) - return rv; - - /* Set the flip */ - val = 0; - if (mux_state & USB_PD_MUX_POLARITY_INVERTED) - val |= PS8818_FLIP_CONFIG; - - rv = ps8818_i2c_field_update8(me, - PS8818_REG_PAGE0, - PS8818_REG0_FLIP, - PS8818_FLIP_NON_RESERVED_MASK, - val); - if (rv) - return rv; - - /* Set the IN_HPD */ - val = PS8818_DPHPD_CONFIG_INHPD_DISABLE; - if (mux_state & USB_PD_MUX_DP_ENABLED) - val |= PS8818_DPHPD_PLUGGED; - - rv = ps8818_i2c_field_update8(me, - PS8818_REG_PAGE0, - PS8818_REG0_DPHPD_CONFIG, - PS8818_DPHPD_NON_RESERVED_MASK, - val); - - return rv; -} - -const struct usb_mux_driver ps8818_usb_retimer_driver = { - .set = ps8818_set_mux, -}; diff --git a/driver/retimer/ps8818.h b/driver/retimer/ps8818.h deleted file mode 100644 index b56df4b411..0000000000 --- a/driver/retimer/ps8818.h +++ /dev/null @@ -1,99 +0,0 @@ -/* Copyright 2019 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. - * - * PS8818 retimer. - */ -#include "usb_mux.h" - -#ifndef __CROS_EC_USB_RETIMER_PS8818_H -#define __CROS_EC_USB_RETIMER_PS8818_H - -#define PS8818_I2C_ADDR_FLAGS 0x28 - -/* - * PAGE 0 Register Definitions - */ -#define PS8818_REG_PAGE0 0x00 - -#define PS8818_REG0_FLIP 0x00 -#define PS8818_FLIP_CONFIG BIT(7) -#define PS8818_FLIP_NON_RESERVED_MASK 0xE0 - -#define PS8818_REG0_MODE 0x01 -#define PS8818_MODE_DP_ENABLE BIT(7) -#define PS8818_MODE_USB_ENABLE BIT(6) -#define PS8818_MODE_NON_RESERVED_MASK 0xC0 - -#define PS8818_REG0_DPHPD_CONFIG 0x02 -#define PS8818_DPHPD_CONFIG_INHPD_DISABLE BIT(7) -#define PS8818_DPHPD_PLUGGED BIT(6) -#define PS8818_DPHPD_NON_RESERVED_MASK 0xFC - -/* - * PAGE 1 Register Definitions - */ -#define PS8818_REG_PAGE1 0x01 - -#define PS8818_REG1_APTX1EQ_10G_LEVEL 0x00 -#define PS8818_REG1_APTX2EQ_10G_LEVEL 0x02 -#define PS8818_REG1_CRX1EQ_10G_LEVEL 0x08 -#define PS8818_REG1_CRX2EQ_10G_LEVEL 0x0A -#define PS8818_REG1_APRX1_DE_LEVEL 0x0C -#define PS8818_REG1_APTX1EQ_5G_LEVEL 0x70 -#define PS8818_REG1_APTX2EQ_5G_LEVEL 0x72 -#define PS8818_REG1_CRX1EQ_5G_LEVEL 0x78 -#define PS8818_REG1_CRX2EQ_5G_LEVEL 0x7A -#define PS8818_EQ_LEVEL_UP_9DB (0) -#define PS8818_EQ_LEVEL_UP_10DB (1) -#define PS8818_EQ_LEVEL_UP_12DB (2) -#define PS8818_EQ_LEVEL_UP_13DB (3) -#define PS8818_EQ_LEVEL_UP_16DB (4) -#define PS8818_EQ_LEVEL_UP_17DB (5) -#define PS8818_EQ_LEVEL_UP_18DB (6) -#define PS8818_EQ_LEVEL_UP_19DB (7) -#define PS8818_EQ_LEVEL_UP_20DB (8) -#define PS8818_EQ_LEVEL_UP_21DB (9) -#define PS8818_EQ_LEVEL_UP_MASK (0x0F) - -#define PS8818_REG1_RX_PHY 0x6D -#define PS8818_RX_INPUT_TERM_112_OHM (0 << 6) -#define PS8818_RX_INPUT_TERM_104_OHM (1 << 6) -#define PS8818_RX_INPUT_TERM_96_OHM (2 << 6) -#define PS8818_RX_INPUT_TERM_85_OHM (3 << 6) -#define PS8818_RX_INPUT_TERM_MASK (3 << 6) - -#define PS8818_REG1_DPEQ_LEVEL 0xB6 -#define PS8818_DPEQ_LEVEL_UP_9DB (0 << 3) -#define PS8818_DPEQ_LEVEL_UP_10DB (1 << 3) -#define PS8818_DPEQ_LEVEL_UP_12DB (2 << 3) -#define PS8818_DPEQ_LEVEL_UP_13DB (3 << 3) -#define PS8818_DPEQ_LEVEL_UP_16DB (4 << 3) -#define PS8818_DPEQ_LEVEL_UP_17DB (5 << 3) -#define PS8818_DPEQ_LEVEL_UP_18DB (6 << 3) -#define PS8818_DPEQ_LEVEL_UP_19DB (7 << 3) -#define PS8818_DPEQ_LEVEL_UP_20DB (8 << 3) -#define PS8818_DPEQ_LEVEL_UP_21DB (9 << 3) -#define PS8818_DPEQ_LEVEL_UP_MASK (0x0F << 3) - -/* - * PAGE 2 Register Definitions - */ -#define PS8818_REG_PAGE2 0x02 - -#define PS8818_REG2_TX_STATUS 0x42 -#define PS8818_REG2_RX_STATUS 0x46 -#define PS8818_STATUS_NORMAL_OPERATION BIT(7) -#define PS8818_STATUS_10_GBPS BIT(5) - -extern const struct usb_mux_driver ps8818_usb_retimer_driver; - -int ps8818_i2c_read(const struct usb_mux *me, - int page, int offset, int *data); -int ps8818_i2c_write(const struct usb_mux *me, - int page, int offset, int data); -int ps8818_i2c_field_update8(const struct usb_mux *me, - int page, int offset, - uint8_t field_mask, uint8_t set_value); - -#endif /* __CROS_EC_USB_RETIMER_PS8818_H */ diff --git a/driver/retimer/tdp142.c b/driver/retimer/tdp142.c deleted file mode 100644 index e1632150d0..0000000000 --- a/driver/retimer/tdp142.c +++ /dev/null @@ -1,42 +0,0 @@ -/* Copyright 2021 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. - * - * Texas Instruments TDP142 DisplayPort Linear Redriver - */ - -#include "common.h" -#include "ec_commands.h" -#include "i2c.h" -#include "tdp142.h" - -static enum ec_error_list tdp142_write(int offset, int data) -{ - return i2c_write8(TDP142_I2C_PORT, - TDP142_I2C_ADDR, - offset, data); - -} - -static enum ec_error_list tdp142_read(int offset, int *regval) -{ - return i2c_read8(TDP142_I2C_PORT, - TDP142_I2C_ADDR, - offset, regval); - -} - -enum ec_error_list tdp142_set_ctlsel(enum tdp142_ctlsel selection) -{ - int regval; - enum ec_error_list rv; - - rv = tdp142_read(TDP142_REG_GENERAL, ®val); - if (rv) - return rv; - - regval &= ~TDP142_GENERAL_CTLSEL; - regval |= selection; - - return tdp142_write(TDP142_REG_GENERAL, regval); -} diff --git a/driver/retimer/tdp142.h b/driver/retimer/tdp142.h deleted file mode 100644 index 8346a233a5..0000000000 --- a/driver/retimer/tdp142.h +++ /dev/null @@ -1,38 +0,0 @@ -/* Copyright 2021 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. - * - * Texas Instruments TDP142 DisplayPort Linear Redriver - */ - -#ifndef __CROS_EC_REDRIVER_TDP142_H -#define __CROS_EC_REDRIVER_TDP142_H - -#include "compile_time_macros.h" - -/* - * Note: Since DP redrivers do not have a standard EC structure, define a - * TDP142_I2C_PORT and TDP142_I2C_ADDR in board.h - */ -#define TDP142_I2C_ADDR0 0x44 -#define TDP142_I2C_ADDR1 0x47 -#define TDP142_I2C_ADDR2 0x0C -#define TDP142_I2C_ADDR3 0x0F - -/* Registers */ -#define TDP142_REG_GENERAL 0x0A -#define TDP142_GENERAL_CTLSEL GENMASK(1, 0) -#define TDP142_GENERAL_HPDIN_OVRRIDE BIT(3) -#define TDP142_GENERAL_EQ_OVERRIDE BIT(4) -#define TDP142_GENERAL_SWAP_HPDIN BIT(5) - -enum tdp142_ctlsel { - TDP142_CTLSEL_SHUTDOWN, - TDP142_CTLSEL_DISABLED, - TDP142_CTLSEL_ENABLED, -}; - -/* Control redriver enable */ -enum ec_error_list tdp142_set_ctlsel(enum tdp142_ctlsel selection); - -#endif /* __CROS_EC_REDRIVER_TDP142_H */ diff --git a/driver/retimer/tusb544.c b/driver/retimer/tusb544.c deleted file mode 100644 index 9de543fd42..0000000000 --- a/driver/retimer/tusb544.c +++ /dev/null @@ -1,116 +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. - * - * TI TUSB544 USB Type-C Multi-Protocol Linear Redriver - */ -#include "i2c.h" -#include "tusb544.h" -#include "usb_mux.h" - -static int tusb544_write(const struct usb_mux *me, int offset, int data) -{ - return i2c_write8(me->i2c_port, - me->i2c_addr_flags, - offset, data); -} - -static int tusb544_read(const struct usb_mux *me, int offset, int *data) -{ - return i2c_read8(me->i2c_port, - me->i2c_addr_flags, - offset, data); -} - -int tusb544_i2c_field_update8(const struct usb_mux *me, int offset, - uint8_t field_mask, uint8_t set_value) -{ - int rv; - - rv = i2c_field_update8(me->i2c_port, - me->i2c_addr_flags, - offset, - field_mask, - set_value); - - return rv; -} - -static int tusb544_enter_low_power_mode(const struct usb_mux *me) -{ - int reg; - int rv; - - rv = tusb544_read(me, TUSB544_REG_GENERAL4, ®); - if (rv) - return rv; - - /* Setting CTL_SEL[0,1] to 0 powers down, per Table 5 */ - reg &= ~TUSB544_GEN4_CTL_SEL; - /* Clear HPD */ - reg &= ~TUSB544_GEN4_HPDIN; - - return tusb544_write(me, TUSB544_REG_GENERAL4, reg); -} - -static int tusb544_init(const struct usb_mux *me) -{ - return EC_SUCCESS; -} - -static int tusb544_set_mux(const struct usb_mux *me, mux_state_t mux_state, - bool *ack_required) -{ - int reg; - int rv; - - /* This driver does not use host command ACKs */ - *ack_required = false; - - if (mux_state == USB_PD_MUX_NONE) - return tusb544_enter_low_power_mode(me); - - rv = tusb544_read(me, TUSB544_REG_GENERAL4, ®); - if (rv) - return rv; - - if (mux_state & USB_PD_MUX_POLARITY_INVERTED) - reg |= TUSB544_GEN4_FLIP_SEL; - else - reg &= ~TUSB544_GEN4_FLIP_SEL; - - reg &= ~TUSB544_GEN4_CTL_SEL; - - if (IS_ENABLED(CONFIG_TUSB544_EQ_BY_REGISTER)) - reg |= TUSB544_GEN4_EQ_OVRD; - - if ((mux_state & USB_PD_MUX_USB_ENABLED) && - (mux_state & USB_PD_MUX_DP_ENABLED)) { - reg |= TUSB544_CTL_SEL_DP_USB; - reg |= TUSB544_GEN4_HPDIN; - } else if (mux_state & USB_PD_MUX_DP_ENABLED) { - reg |= TUSB544_CTL_SEL_DP_ONLY; - reg |= TUSB544_GEN4_HPDIN; - } else if (mux_state & USB_PD_MUX_USB_ENABLED) - reg |= TUSB544_CTL_SEL_USB_ONLY; - - rv = tusb544_write(me, TUSB544_REG_GENERAL4, reg); - if (rv) - return rv; - - rv = tusb544_read(me, TUSB544_REG_GENERAL6, ®); - if (rv) - return rv; - - reg &= ~TUSB544_GEN6_DIR_SEL; - /* All chromebooks are DP SRC */ - reg |= TUSB544_DIR_SEL_USB_DP_SRC; - - return tusb544_write(me, TUSB544_REG_GENERAL6, reg); -} - -const struct usb_mux_driver tusb544_drv = { - .enter_low_power_mode = &tusb544_enter_low_power_mode, - .init = &tusb544_init, - .set = &tusb544_set_mux, -}; diff --git a/driver/retimer/tusb544.h b/driver/retimer/tusb544.h deleted file mode 100644 index e1599c78ca..0000000000 --- a/driver/retimer/tusb544.h +++ /dev/null @@ -1,109 +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. - * - * TI TUSB544 USB Type-C Multi-Protocol Linear Redriver - */ -#include "usb_mux.h" - -#ifndef __CROS_EC_USB_REDRIVER_TUSB544_H -#define __CROS_EC_USB_REDRIVER_TUSB544_H - - -#define TUSB544_I2C_ADDR_FLAGS0 0x44 - -#define TUSB544_REG_GENERAL4 0x0A -#define TUSB544_GEN4_CTL_SEL GENMASK(1, 0) -#define TUSB544_GEN4_FLIP_SEL BIT(2) -#define TUSB544_GEN4_HPDIN BIT(3) -#define TUSB544_GEN4_EQ_OVRD BIT(4) -#define TUSB544_GEN4_SWAP_SEL BIT(5) - -#define TUSB544_REG_DISPLAYPORT_1 0x10 -#define TUSB544_REG_DISPLAYPORT_2 0x11 -#define TUSB544_REG_USB3_1_1 0x20 -#define TUSB544_REG_USB3_1_2 0x21 -#define TUSB544_EQ_RX_DFP_MINUS14_UFP_MINUS33 (0) -#define TUSB544_EQ_RX_DFP_04_UFP_MINUS15 (1) -#define TUSB544_EQ_RX_DFP_17_UFP_0 (2) -#define TUSB544_EQ_RX_DFP_32_UFP_14 (3) -#define TUSB544_EQ_RX_DFP_41_UFP_24 (4) -#define TUSB544_EQ_RX_DFP_52_UFP_35 (5) -#define TUSB544_EQ_RX_DFP_61_UFP_43 (6) -#define TUSB544_EQ_RX_DFP_69_UFP_52 (7) -#define TUSB544_EQ_RX_DFP_77_UFP_60 (8) -#define TUSB544_EQ_RX_DFP_83_UFP_66 (9) -#define TUSB544_EQ_RX_DFP_88_UFP_72 (10) -#define TUSB544_EQ_RX_DFP_94_UFP_77 (11) -#define TUSB544_EQ_RX_DFP_98_UFP_81 (12) -#define TUSB544_EQ_RX_DFP_103_UFP_86 (13) -#define TUSB544_EQ_RX_DFP_106_UFP_90 (14) -#define TUSB544_EQ_RX_DFP_110_UFP_94 (15) -#define TUSB544_EQ_RX_MASK (0x0F) - -#define TUSB544_EQ_TX_DFP_MINUS14_UFP_MINUS33 (0 << 4) -#define TUSB544_EQ_TX_DFP_04_UFP_MINUS15 (1 << 4) -#define TUSB544_EQ_TX_DFP_17_UFP_0 (2 << 4) -#define TUSB544_EQ_TX_DFP_32_UFP_14 (3 << 4) -#define TUSB544_EQ_TX_DFP_41_UFP_24 (4 << 4) -#define TUSB544_EQ_TX_DFP_52_UFP_35 (5 << 4) -#define TUSB544_EQ_TX_DFP_61_UFP_43 (6 << 4) -#define TUSB544_EQ_TX_DFP_69_UFP_52 (7 << 4) -#define TUSB544_EQ_TX_DFP_77_UFP_60 (8 << 4) -#define TUSB544_EQ_TX_DFP_83_UFP_66 (9 << 4) -#define TUSB544_EQ_TX_DFP_88_UFP_72 (10 << 4) -#define TUSB544_EQ_TX_DFP_94_UFP_77 (11 << 4) -#define TUSB544_EQ_TX_DFP_98_UFP_81 (12 << 4) -#define TUSB544_EQ_TX_DFP_103_UFP_86 (13 << 4) -#define TUSB544_EQ_TX_DFP_106_UFP_90 (14 << 4) -#define TUSB544_EQ_TX_DFP_110_UFP_94 (15 << 4) -#define TUSB544_EQ_TX_MASK (0xF0) - -enum tusb544_ct_sel { - TUSB544_CTL_SEL_DISABLED, - TUSB544_CTL_SEL_USB_ONLY, - TUSB544_CTL_SEL_DP_ONLY, - TUSB544_CTL_SEL_DP_USB, -}; - -#define TUSB544_REG_GENERAL6 0x0C -#define TUSB544_GEN6_DIR_SEL GENMASK(1, 0) -#define TUSB544_VOD_DCGAIN_SEL GENMASK(5, 2) -#define TUSB544_VOD_DCGAIN_OVERRIDE BIT(6) - -enum tusb544_dir_sel { - TUSB544_DIR_SEL_USB_DP_SRC, - TUSB544_DIR_SEL_USB_DP_SNK, - TUSB544_DIR_SEL_CUSTOM_SRC, - TUSB544_DIS_SEL_CUSTOM_SNK, -}; - -enum tusb544_vod_dcgain_sel { - TUSB544_VOD_DCGAIN_SETTING_1, - TUSB544_VOD_DCGAIN_SETTING_2, - TUSB544_VOD_DCGAIN_SETTING_3, - TUSB544_VOD_DCGAIN_SETTING_4, - TUSB544_VOD_DCGAIN_SETTING_5, - TUSB544_VOD_DCGAIN_SETTING_6, - TUSB544_VOD_DCGAIN_SETTING_7, - TUSB544_VOD_DCGAIN_SETTING_8, -}; - -/* - * Note: TUSB544 automatically snoops DP lanes to enable, but may be manually - * directed which lanes to turn on when snoop is disabled - */ -#define TUSB544_REG_DP4 0x13 -#define TUSB544_DP4_DP0_DISABLE BIT(0) -#define TUSB544_DP4_DP1_DISABLE BIT(1) -#define TUSB544_DP4_DP2_DISABLE BIT(2) -#define TUSB544_DP4_DP3_DISABLE BIT(3) -#define TUSB544_DP4_AUX_SBU_OVR GENMASK(5, 4) -#define TUSB544_DP4_AUX_SNOOP_DISABLE BIT(7) - -extern const struct usb_mux_driver tusb544_drv; - -int tusb544_i2c_field_update8(const struct usb_mux *me, int offset, - uint8_t field_mask, uint8_t set_value); - -#endif diff --git a/driver/sb_rmi.c b/driver/sb_rmi.c deleted file mode 100644 index fbcbd990ff..0000000000 --- a/driver/sb_rmi.c +++ /dev/null @@ -1,192 +0,0 @@ -/* Copyright 2021 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. - */ - -/* AMD SB-RMI (Side-band Remote Management Interface) Driver */ - -#include "common.h" -#include "chipset.h" -#include "i2c.h" -#include "sb_rmi.h" -#include "stdbool.h" -#include "time.h" -#include "util.h" - -/* Console output macros */ -#define CPUTS(outstr) cputs(CC_SYSTEM, outstr) -#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args) - -#define SB_RMI_MAILBOX_TIMEOUT_MS 10 -#define SB_RMI_MAILBOX_RETRY_DELAY_US 200 - -/** - * Write an SB-RMI register - */ -static int sb_rmi_write(const int reg, int data) -{ - return i2c_write8(I2C_PORT_THERMAL_AP, SB_RMI_I2C_ADDR_FLAGS0, reg, - data); -} - -/** - * Read an SB-RMI register - */ -static int sb_rmi_read(const int reg, int *data) -{ - return i2c_read8(I2C_PORT_THERMAL_AP, SB_RMI_I2C_ADDR_FLAGS0, reg, - data); -} - -/** - * Set SB-RMI software interrupt - */ -static int sb_rmi_assert_interrupt(bool assert) -{ - return sb_rmi_write(SB_RMI_SW_INTR_REG, assert ? 0x1 : 0x0); -} - - -/** - * Execute a SB-RMI mailbox transaction - * - * cmd: - * See "SB-RMI Soft Mailbox Message" table in PPR for command id - * msg_in: - * Message In buffer - * msg_out: - * Message Out buffer - */ -int sb_rmi_mailbox_xfer(int cmd, uint32_t msg_in, uint32_t *msg_out_ptr) -{ - /** - * The sequence is as follows: - * 1. The initiator (BMC) indicates that command is to be serviced by - * firmware by writing 0x80 to SBRMI::InBndMsg_inst7 (SBRMI_x3F). This - * register must be set to 0x80 after reset. - * 2. The initiator (BMC) writes the command to SBRMI::InBndMsg_inst0 - * (SBRMI_x38). - * 3. For write operations or read operations which require additional - * addressing information as shown in the table above, the initiator - * (BMC) writes Command Data In[31:0] to SBRMI::InBndMsg_inst[4:1] - * {SBRMI_x3C(MSB):SBRMI_x39(LSB)}. - * 4. The initiator (BMC) writes 0x01 to SBRMI::SoftwareInterrupt to - * notify firmware to perform the requested read or write command. - * 5. Firmware reads the message and performs the defined action. - * 6. Firmware writes the original command to outbound message register - * SBRMI::OutBndMsg_inst0 (SBRMI_x30). - * 7. Firmware will write SBRMI::Status[SwAlertSts]=1 to generate an - * ALERT (if enabled) to initiator (BMC) to indicate completion of the - * requested command. Firmware must (if applicable) put the message - * data into the message registers SBRMI::OutBndMsg_inst[4:1] - * {SBRMI_x34(MSB):SBRMI_x31(LSB)}. - * 8. For a read operation, the initiator (BMC) reads the firmware - * response Command Data Out[31:0] from SBRMI::OutBndMsg_inst[4:1] - * {SBRMI_x34(MSB):SBRMI_x31(LSB)}. - * 9. Firmware clears the interrupt on SBRMI::SoftwareInterrupt. - * 10. BMC must write 1'b1 to SBRMI::Status[SwAlertSts] to clear the - * ALERT to initiator (BMC). It is recommended to clear the ALERT - * upon completion of the current mailbox command. - */ - int val; - bool alerted; - timestamp_t start; - - if (!chipset_in_state(CHIPSET_STATE_ON)) - return EC_ERROR_NOT_POWERED; - - /** - * Step 1: writing 0x80 to SBRMI::InBndMsg_inst7 (SBRMI_x3F) to - * indicate that command is to be serviced and to make sure - * SBRMIx40[Software Interrupt] is cleared - */ - RETURN_ERROR(sb_rmi_write(SB_RMI_IN_BND_MSG7_REG, 0x80)); - RETURN_ERROR(sb_rmi_assert_interrupt(0)); - - /* Step 2: writes the command to SBRMI::InBndMsg_inst0 (SBRMI_x38) */ - RETURN_ERROR(sb_rmi_write(SB_RMI_IN_BND_MSG0_REG, cmd)); - /* Step 3: msgIn to {SBRMI_x3C(MSB):SBRMI_x39(LSB)} */ - RETURN_ERROR(sb_rmi_write(SB_RMI_IN_BND_MSG1_REG, msg_in & 0xFF)); - RETURN_ERROR( - sb_rmi_write(SB_RMI_IN_BND_MSG2_REG, (msg_in >> 8) & 0xFF)); - RETURN_ERROR( - sb_rmi_write(SB_RMI_IN_BND_MSG3_REG, (msg_in >> 16) & 0xFF)); - RETURN_ERROR( - sb_rmi_write(SB_RMI_IN_BND_MSG4_REG, (msg_in >> 24) & 0xFF)); - - /** - * Step 4: writes 0x01 to SBRMIx40[Software Interrupt] to notify - * firmware to start service. - */ - RETURN_ERROR(sb_rmi_assert_interrupt(1)); - - /** - * Step 5: SoC do the service - * Step 6: The original command will be copied to SBRMI::OutBndMsg_inst0 - * (SBRMI_x30) - * Step 7: wait SBRMIx02[SwAlertSts] to 1 which indicate the completion - * of a mailbox operation - */ - alerted = false; - start = get_time(); - do { - if (sb_rmi_read(SB_RMI_STATUS_REG, &val)) - break; - if (val & 0x02) { - alerted = true; - break; - } - msleep(1); - } while (time_since32(start) < SB_RMI_MAILBOX_TIMEOUT_MS * MSEC); - - if (!alerted) { - CPRINTS("SB-SMI: Mailbox transfer timeout"); - /* Clear interrupt */ - sb_rmi_assert_interrupt(0); - return EC_ERROR_TIMEOUT; - } - - RETURN_ERROR(sb_rmi_read(SB_RMI_OUT_BND_MSG0_REG, &val)); - if (val != cmd) { - CPRINTS("RMI: Unexpected command value in out bound message"); - sb_rmi_assert_interrupt(0); - return EC_ERROR_UNKNOWN; - } - - /* Step 8: read msgOut from {SBRMI_x34(MSB):SBRMI_x31(LSB)} */ - *msg_out_ptr = 0; - RETURN_ERROR(sb_rmi_read(SB_RMI_OUT_BND_MSG1_REG, &val)); - *msg_out_ptr |= val; - RETURN_ERROR(sb_rmi_read(SB_RMI_OUT_BND_MSG2_REG, &val)); - *msg_out_ptr |= val << 8; - RETURN_ERROR(sb_rmi_read(SB_RMI_OUT_BND_MSG3_REG, &val)); - *msg_out_ptr |= val << 16; - RETURN_ERROR(sb_rmi_read(SB_RMI_OUT_BND_MSG4_REG, &val)); - *msg_out_ptr |= val << 24; - - /* Step 9: clear SBRMIx40[Software Interrupt] */ - RETURN_ERROR(sb_rmi_assert_interrupt(0)); - - /** - * Step 10: BMC must write 1'b1 to SBRMI::Status[SwAlertSts] to clear - * the ALERT to initiator (BMC). It is recommended to clear the - * ALERT upon completion of the current mailbox command. - */ - RETURN_ERROR(sb_rmi_write(SB_RMI_STATUS_REG, 0x2)); - - /* Step 11: read the return code from OutBndMsg_inst7 (SBRMI_x37) */ - RETURN_ERROR(sb_rmi_read(SB_RMI_OUT_BND_MSG7_REG, &val)); - - switch (val) { - case SB_RMI_MAILBOX_SUCCESS: - return EC_SUCCESS; - case SB_RMI_MAILBOX_ERROR_ABORTED: - return EC_ERROR_UNKNOWN; - case SB_RMI_MAILBOX_ERROR_UNKNOWN_CMD: - return EC_ERROR_INVAL; - case SB_RMI_MAILBOX_ERROR_INVALID_CORE: - return EC_ERROR_PARAM1; - default: - return EC_ERROR_UNKNOWN; - } -} diff --git a/driver/sb_rmi.h b/driver/sb_rmi.h deleted file mode 100644 index 132af0e70a..0000000000 --- a/driver/sb_rmi.h +++ /dev/null @@ -1,58 +0,0 @@ -/* Copyright 2021 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. - */ - -/* AMD SB-RMI (Side-band Remote Management Interface) Driver */ - -#ifndef __CROS_EC_SB_RMI_H -#define __CROS_EC_SB_RMI_H - -#include "common.h" - -#define SB_RMI_OUT_BND_MSG0_REG 0x30 -#define SB_RMI_OUT_BND_MSG1_REG 0x31 -#define SB_RMI_OUT_BND_MSG2_REG 0x32 -#define SB_RMI_OUT_BND_MSG3_REG 0x33 -#define SB_RMI_OUT_BND_MSG4_REG 0x34 -#define SB_RMI_OUT_BND_MSG5_REG 0x35 -#define SB_RMI_OUT_BND_MSG6_REG 0x36 -#define SB_RMI_OUT_BND_MSG7_REG 0x37 - -#define SB_RMI_IN_BND_MSG0_REG 0x38 -#define SB_RMI_IN_BND_MSG1_REG 0x39 -#define SB_RMI_IN_BND_MSG2_REG 0x3a -#define SB_RMI_IN_BND_MSG3_REG 0x3b -#define SB_RMI_IN_BND_MSG4_REG 0x3c -#define SB_RMI_IN_BND_MSG5_REG 0x3d -#define SB_RMI_IN_BND_MSG6_REG 0x3e -#define SB_RMI_IN_BND_MSG7_REG 0x3f - -#define SB_RMI_SW_INTR_REG 0x40 -#define SB_RMI_STATUS_REG 0x02 - -#define SB_RMI_WRITE_STT_SENSOR_CMD 0x3A - -#define SB_RMI_MAILBOX_SUCCESS 0x0 -#define SB_RMI_MAILBOX_ERROR_ABORTED 0x1 -#define SB_RMI_MAILBOX_ERROR_UNKNOWN_CMD 0x2 -#define SB_RMI_MAILBOX_ERROR_INVALID_CORE 0x3 - -/* Socket ID 0 */ -#define SB_RMI_I2C_ADDR_FLAGS0 0x3c -/* Socket ID 1 */ -#define SB_RMI_I2C_ADDR_FLAGS1 0x30 - -/** - * Execute a SB-RMI mailbox transaction - * - * cmd: - * See "SB-RMI Soft Mailbox Message" table in PPR for command id - * msg_in: - * Message In buffer - * msg_out: - * Message Out buffer - */ -int sb_rmi_mailbox_xfer(int cmd, uint32_t msg_in, uint32_t *msg_out_ptr); - -#endif /* __CROS_EC_SB_RMI_H */ diff --git a/driver/sensorhub_lsm6dsm.c b/driver/sensorhub_lsm6dsm.c deleted file mode 100644 index 371d8474f6..0000000000 --- a/driver/sensorhub_lsm6dsm.c +++ /dev/null @@ -1,327 +0,0 @@ -/* Copyright 2018 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. - */ - -/* - * Sensor Hub Driver for LSM6DSM acce/gyro module to enable connecting - * external sensors like magnetometer - */ - -#include "console.h" -#include "driver/accelgyro_lsm6dsm.h" -#include "driver/sensorhub_lsm6dsm.h" -#include "driver/stm_mems_common.h" - -#define CPRINTF(format, args...) cprintf(CC_ACCEL, format, ## args) - -static int set_reg_bit_field(const struct motion_sensor_t *s, - uint8_t reg, uint8_t bit_field) -{ - int tmp; - int ret; - - ret = st_raw_read8(s->port, s->i2c_spi_addr_flags, reg, &tmp); - if (ret != EC_SUCCESS) - return ret; - - tmp |= bit_field; - return st_raw_write8(s->port, s->i2c_spi_addr_flags, reg, tmp); -} - -static int clear_reg_bit_field(const struct motion_sensor_t *s, - uint8_t reg, uint8_t bit_field) -{ - int tmp; - int ret; - - ret = st_raw_read8(s->port, s->i2c_spi_addr_flags, reg, &tmp); - if (ret != EC_SUCCESS) - return ret; - - tmp &= ~(bit_field); - return st_raw_write8(s->port, s->i2c_spi_addr_flags, reg, tmp); -} - -static inline int enable_sensorhub_func(const struct motion_sensor_t *s) -{ - return set_reg_bit_field(s, LSM6DSM_CTRL10_ADDR, - LSM6DSM_EMBED_FUNC_EN); -} - -static inline int disable_sensorhub_func(const struct motion_sensor_t *s) -{ - return clear_reg_bit_field(s, LSM6DSM_CTRL10_ADDR, - LSM6DSM_EMBED_FUNC_EN); -} - -/* - * Sensor hub includes embedded register banks associated with external - * sensors. 4 external sensor slaves can be attached to the sensor hub - * and hence 4 such register banks exist. The access to them are disabled - * by default. Below 2 helper functions help enable/disable access to those - * register banks. - */ -static inline int enable_ereg_bank_acc(const struct motion_sensor_t *s) -{ - return set_reg_bit_field(s, LSM6DSM_FUNC_CFG_ACC_ADDR, - LSM6DSM_FUNC_CFG_EN); -} - -static inline int disable_ereg_bank_acc(const struct motion_sensor_t *s) -{ - return clear_reg_bit_field(s, LSM6DSM_FUNC_CFG_ACC_ADDR, - LSM6DSM_FUNC_CFG_EN); -} - -static inline int enable_aux_i2c_master(const struct motion_sensor_t *s) -{ - return set_reg_bit_field(s, LSM6DSM_MASTER_CFG_ADDR, - LSM6DSM_I2C_MASTER_ON); -} - -static inline int disable_aux_i2c_master(const struct motion_sensor_t *s) -{ - return clear_reg_bit_field(s, LSM6DSM_MASTER_CFG_ADDR, - LSM6DSM_I2C_MASTER_ON); -} - -static inline int restore_master_cfg(const struct motion_sensor_t *s, - int cache) -{ - return st_raw_write8(s->port, s->i2c_spi_addr_flags, - LSM6DSM_MASTER_CFG_ADDR, cache); -} - -static int enable_i2c_pass_through(const struct motion_sensor_t *s, - int *cache) -{ - int ret; - - ret = st_raw_read8(s->port, s->i2c_spi_addr_flags, - LSM6DSM_MASTER_CFG_ADDR, cache); - if (ret != EC_SUCCESS) { - CPRINTF("%s: %s type:0x%x MCR error ret: %d\n", - __func__, s->name, s->type, ret); - return ret; - } - - /* - * Fake set sensor hub to external trigger event and wait for 10ms. - * Wait is for any pending bus activity(probably read) to settle down - * so that there is no bus contention. - */ - ret = st_raw_write8(s->port, s->i2c_spi_addr_flags, - LSM6DSM_MASTER_CFG_ADDR, - *cache | LSM6DSM_EXT_TRIGGER_EN); - if (ret != EC_SUCCESS) { - CPRINTF("%s: %s type:0x%x MCETEN error ret: %d\n", - __func__, s->name, s->type, ret); - return ret; - } - msleep(10); - - ret = st_raw_write8(s->port, s->i2c_spi_addr_flags, - LSM6DSM_MASTER_CFG_ADDR, - *cache & ~(LSM6DSM_EXT_TRIGGER_EN - | LSM6DSM_I2C_MASTER_ON)); - if (ret != EC_SUCCESS) { - CPRINTF("%s: %s type:0x%x MCC error ret: %d\n", - __func__, s->name, s->type, ret); - restore_master_cfg(s, *cache); - return ret; - } - - return st_raw_write8(s->port, s->i2c_spi_addr_flags, - LSM6DSM_MASTER_CFG_ADDR, LSM6DSM_I2C_PASS_THRU_MODE); -} - -static inline int power_down_accel(const struct motion_sensor_t *s, - int *cache) -{ - int ret; - - ret = st_raw_read8(s->port, s->i2c_spi_addr_flags, - LSM6DSM_CTRL1_ADDR, cache); - if (ret != EC_SUCCESS) { - CPRINTF("%s: %s type:0x%x CTRL1R error ret: %d\n", - __func__, s->name, s->type, ret); - return ret; - } - - return st_raw_write8(s->port, s->i2c_spi_addr_flags, - LSM6DSM_CTRL1_ADDR, - *cache & ~LSM6DSM_XL_ODR_MASK); -} - -static inline int restore_ctrl1(const struct motion_sensor_t *s, int cache) -{ - return st_raw_write8(s->port, s->i2c_spi_addr_flags, - LSM6DSM_CTRL1_ADDR, cache); -} - -static int config_slv0_read(const struct motion_sensor_t *s, - const uint16_t slv_addr_flags, - uint16_t reg, uint8_t len) -{ - int ret; - uint16_t addr_8bit = I2C_STRIP_FLAGS(slv_addr_flags) << 1; - - ret = st_raw_write8(s->port, s->i2c_spi_addr_flags, - LSM6DSM_SLV0_ADD_ADDR, - (addr_8bit | LSM6DSM_SLV0_RD_BIT)); - if (ret != EC_SUCCESS) { - CPRINTF("%s: %s type:0x%x SA error ret: %d\n", - __func__, s->name, s->type, ret); - return ret; - } - - ret = st_raw_write8(s->port, s->i2c_spi_addr_flags, - LSM6DSM_SLV0_SUBADD_ADDR, reg); - if (ret != EC_SUCCESS) { - CPRINTF("%s: %s type:0x%x RA error ret: %d\n", - __func__, s->name, s->type, ret); - return ret; - } - - /* - * No decimation for external sensor 0, - * Number of sensors connected to external sensor hub 1 - */ - ret = st_raw_write8(s->port, s->i2c_spi_addr_flags, - LSM6DSM_SLV0_CONFIG_ADDR, - (len & LSM6DSM_SLV0_NUM_OPS_MASK)); - if (ret != EC_SUCCESS) { - CPRINTF("%s: %s type:0x%x CFG error ret: %d\n", - __func__, s->name, s->type, ret); - return ret; - } - - return EC_SUCCESS; -} - -int sensorhub_config_ext_reg(const struct motion_sensor_t *s, - const uint16_t slv_addr_flags, - uint8_t reg, uint8_t val) -{ - int ret; - int tmp; - - ret = enable_i2c_pass_through(s, &tmp); - if (ret != EC_SUCCESS) { - CPRINTF("%s: %s type:0x%x ENI2C error ret: %d\n", - __func__, s->name, s->type, ret); - return ret; - } - - ret = st_raw_write8(s->port, slv_addr_flags, reg, val); - restore_master_cfg(s, tmp); - return ret; -} - -int sensorhub_config_slv0_read(const struct motion_sensor_t *s, - uint16_t slv_addr_flags, uint8_t reg, int len) -{ - int tmp_xl_cfg; - int ret; - - if (len <= 0 || len > OUT_XYZ_SIZE) { - CPRINTF("%s: %s type:0x%x Invalid length: %d\n", - __func__, s->name, s->type, len); - return EC_ERROR_INVAL; - } - - ret = power_down_accel(s, &tmp_xl_cfg); - if (ret != EC_SUCCESS) { - CPRINTF("%s: %s type:0x%x PDXL error ret: %d\n", - __func__, s->name, s->type, ret); - return ret; - } - - ret = enable_ereg_bank_acc(s); - if (ret != EC_SUCCESS) { - CPRINTF("%s: %s type:0x%x ENERB error ret: %d\n", - __func__, s->name, s->type, ret); - goto out_restore_ctrl1; - } - - ret = config_slv0_read(s, slv_addr_flags, reg, len); - disable_ereg_bank_acc(s); - if (ret != EC_SUCCESS) { - CPRINTF("%s: %s type:0x%x CS0R error ret: %d\n", - __func__, s->name, s->type, ret); - goto out_restore_ctrl1; - } - - ret = enable_sensorhub_func(s); - if (ret != EC_SUCCESS) { - CPRINTF("%s: %s type:0x%x ENSH error ret: %d\n", - __func__, s->name, s->type, ret); - goto out_restore_ctrl1; - } - - ret = enable_aux_i2c_master(s); - if (ret != EC_SUCCESS) { - CPRINTF("%s: %s type:0x%x ENI2CM error ret: %d\n", - __func__, s->name, s->type, ret); - disable_sensorhub_func(s); - } -out_restore_ctrl1: - restore_ctrl1(s, tmp_xl_cfg); - return ret; -} - -int sensorhub_slv0_data_read(const struct motion_sensor_t *s, uint8_t *raw) -{ - int ret; - - /* - * Accel/Gyro is already reading slave 0 data into the sensorhub1 - * register as soon as the accel is in power-up mode. So return the - * contents of that register. - */ - ret = st_raw_read_n_noinc(s->port, s->i2c_spi_addr_flags, - LSM6DSM_SENSORHUB1_REG, - raw, OUT_XYZ_SIZE); - if (ret != EC_SUCCESS) { - CPRINTF("%s: %s type:0x%x SH1R error ret: %d\n", - __func__, s->name, s->type, ret); - return ret; - } - return EC_SUCCESS; -} - -int sensorhub_check_and_rst(const struct motion_sensor_t *s, - const uint16_t slv_addr_flags, - uint8_t whoami_reg, uint8_t whoami_val, - uint8_t rst_reg, uint8_t rst_val) -{ - int ret, tmp; - int tmp_master_cfg; - - ret = enable_i2c_pass_through(s, &tmp_master_cfg); - if (ret != EC_SUCCESS) { - CPRINTF("%s: %s type:0x%x ENI2C error ret: %d\n", - __func__, s->name, s->type, ret); - return ret; - } - - ret = st_raw_read8(s->port, slv_addr_flags, whoami_reg, &tmp); - if (ret != EC_SUCCESS) { - CPRINTF("%s: %s type:0x%x WAIR error ret: %d\n", - __func__, s->name, s->type, ret); - goto err_restore_master_cfg; - } - - if (tmp != whoami_val) { - CPRINTF("%s: %s type:0x%x WAIC error ret: %d\n", - __func__, s->name, s->type, ret); - ret = EC_ERROR_UNKNOWN; - goto err_restore_master_cfg; - } - - ret = st_raw_write8(s->port, slv_addr_flags, rst_reg, rst_val); -err_restore_master_cfg: - restore_master_cfg(s, tmp_master_cfg); - return ret; -} diff --git a/driver/sync.c b/driver/sync.c deleted file mode 100644 index c9a2752d63..0000000000 --- a/driver/sync.c +++ /dev/null @@ -1,137 +0,0 @@ -/* Copyright 2017 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. - * - * Sync event driver. - * Useful for recording the exact time a gpio interrupt happened in the - * context of sensors. Originally created for a camera vsync signal. - */ - -#include "accelgyro.h" -#include "config.h" -#include "console.h" -#include "driver/sync.h" -#include "hwtimer.h" -#include "motion_sense_fifo.h" -#include "queue.h" -#include "task.h" -#include "util.h" - -#define CPRINTS(format, args...) cprints(CC_MOTION_SENSE, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_MOTION_SENSE, format, ## args) - -#ifndef CONFIG_ACCEL_FIFO -#error This driver needs CONFIG_ACCEL_FIFO -#endif - -#ifndef CONFIG_ACCEL_INTERRUPTS -#error This driver needs CONFIG_ACCEL_INTERRUPTS -#endif - -struct sync_event_t { - uint32_t timestamp; - int counter; -}; - -static struct queue const sync_event_queue = - QUEUE_NULL(CONFIG_SYNC_QUEUE_SIZE, struct sync_event_t); - -struct sync_event_t next_event; -struct ec_response_motion_sensor_data vector = { - .flags = MOTIONSENSE_SENSOR_FLAG_BYPASS_FIFO, - .data = {0, 0, 0} -}; - -int sync_enabled; - -static int sync_read(const struct motion_sensor_t *s, intv3_t v) -{ - v[0] = next_event.counter; - return EC_SUCCESS; -} - -/* - * Since there's no such thing as data rate for this sensor, but the framework - * still depends on being able to set this to 0 to disable it, we'll just use - * non 0 rate values as an enable boolean. - */ -static int sync_set_data_rate(const struct motion_sensor_t *s, - int rate, int roundup) -{ - sync_enabled = !!rate; - CPRINTF("sync event driver enabling=%d\n", sync_enabled); - return EC_SUCCESS; -} - -static int sync_get_data_rate(const struct motion_sensor_t *s) -{ - return sync_enabled; -} - -/* Upper half of the irq handler */ -void sync_interrupt(enum gpio_signal signal) -{ - next_event.timestamp = __hw_clock_source_read(); - - if (!sync_enabled) - return; - - next_event.counter++; - queue_add_unit(&sync_event_queue, &next_event); - - task_set_event(TASK_ID_MOTIONSENSE, CONFIG_SYNC_INT_EVENT); -} - -/* Bottom half of the irq handler */ -static int motion_irq_handler(struct motion_sensor_t *s, uint32_t *event) -{ - struct sync_event_t sync_event; - - if (!(*event & CONFIG_SYNC_INT_EVENT)) - return EC_ERROR_NOT_HANDLED; - - while (queue_remove_unit(&sync_event_queue, &sync_event)) { - vector.data[X] = sync_event.counter; - motion_sense_fifo_stage_data( - &vector, s, 1, sync_event.timestamp); - } - motion_sense_fifo_commit_data(); - - return EC_SUCCESS; -} - -static int sync_init(struct motion_sensor_t *s) -{ - vector.sensor_num = s - motion_sensors; - sync_enabled = 0; - next_event.counter = 0; - queue_init(&sync_event_queue); - return 0; -} - -#ifdef CONFIG_SYNC_COMMAND -static int command_sync(int argc, char **argv) -{ - int count = 1, i; - - if (argc > 1) - count = strtoi(argv[1], 0, 0); - - for (i = 0; i < count; i++) - sync_interrupt(GPIO_SYNC_INT); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(sync, command_sync, - "[count]", - "Simulates sync events"); -#endif - -const struct accelgyro_drv sync_drv = { - .init = sync_init, - .read = sync_read, - .set_data_rate = sync_set_data_rate, - .get_data_rate = sync_get_data_rate, - .irq_handler = motion_irq_handler, -}; - diff --git a/driver/sync.h b/driver/sync.h deleted file mode 100644 index 1f6115a086..0000000000 --- a/driver/sync.h +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright 2017 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. - * - * Sync event driver. - * Useful for recording the exact time a gpio interrupt happened in the - * context of sensors. Originally created for a camera vsync signal. - */ - -#ifndef __CROS_EC_VSYNC_H -#define __CROS_EC_VSYNC_H - -extern const struct accelgyro_drv sync_drv; - -void sync_interrupt(enum gpio_signal signal); - -#endif /* __CROS_EC_VSYNC_H */ - diff --git a/driver/tcpm/anx7447.c b/driver/tcpm/anx7447.c deleted file mode 100644 index 9a9a3c7971..0000000000 --- a/driver/tcpm/anx7447.c +++ /dev/null @@ -1,861 +0,0 @@ -/* Copyright 2018 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. - */ - -/* ANX7447 port manager */ - -#include "common.h" -#include "anx7447.h" -#include "console.h" -#include "hooks.h" -#include "tcpm/tcpci.h" -#include "tcpm/tcpm.h" -#include "timer.h" -#include "usb_mux.h" -#include "usb_pd.h" -#include "util.h" - -#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args) - -#define vsafe5v_min (3800/25) -#define vsafe0v_max (800/25) -/* - * These interface are workable while ADC is enabled, before - * calling them should make sure ec driver finished chip initilization. - */ -#define is_equal_greater_safe5v(port) \ - (((anx7447_get_vbus_voltage(port))) > vsafe5v_min) -#define is_equal_greater_safe0v(port) \ - (((anx7447_get_vbus_voltage(port))) > vsafe0v_max) - -struct anx_state { - uint16_t i2c_addr_flags; -}; - -struct anx_usb_mux { - int state; -}; - -static int anx7447_mux_set(const struct usb_mux *me, mux_state_t mux_state, - bool *ack_required); - -static struct anx_state anx[CONFIG_USB_PD_PORT_MAX_COUNT]; -static struct anx_usb_mux mux[CONFIG_USB_PD_PORT_MAX_COUNT]; - -/* - * ANX7447 has two co-existence I2C addresses, TCPC address and - * SPI address. The registers of TCPC address are partly compliant - * with standard USB TCPC specification, and the registers in SPI - * address controls the other functions (ex, hpd_level, mux_switch, and - * so on). It can't use tcpc_read() and tcpc_write() to access SPI - * address because its address has been set as TCPC in the structure - * tcpc_config_t. - * anx7447_reg_write() and anx7447_reg_read() are implemented here to access - * ANX7447 SPI address. - */ -const struct anx7447_i2c_addr anx7447_i2c_addrs_flags[] = { - {AN7447_TCPC0_I2C_ADDR_FLAGS, AN7447_SPI0_I2C_ADDR_FLAGS}, - {AN7447_TCPC1_I2C_ADDR_FLAGS, AN7447_SPI1_I2C_ADDR_FLAGS}, - {AN7447_TCPC2_I2C_ADDR_FLAGS, AN7447_SPI2_I2C_ADDR_FLAGS}, - {AN7447_TCPC3_I2C_ADDR_FLAGS, AN7447_SPI3_I2C_ADDR_FLAGS} -}; - -static inline int anx7447_reg_write(int port, int reg, int val) -{ - int rv = i2c_write8(tcpc_config[port].i2c_info.port, - anx[port].i2c_addr_flags, - reg, val); -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER - pd_device_accessed(port); -#endif - return rv; -} - -static inline int anx7447_reg_read(int port, int reg, int *val) -{ - int rv = i2c_read8(tcpc_config[port].i2c_info.port, - anx[port].i2c_addr_flags, - reg, val); -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER - pd_device_accessed(port); -#endif - return rv; -} - -void anx7447_hpd_mode_init(int port) -{ - int reg, rv; - - rv = anx7447_reg_read(port, ANX7447_REG_HPD_CTRL_0, ®); - if (rv) - return; - - /* - * Set ANX7447_REG_HPD_MODE bit as 0, then the TCPC will generate the - * HPD pulse from internal timer (by using ANX7447_REG_HPD_IRQ0) - * instead of using the ANX7447_REG_HPD_OUT to set the HPD IRQ signal. - */ - reg &= ~(ANX7447_REG_HPD_MODE | ANX7447_REG_HPD_PLUG | - ANX7447_REG_HPD_UNPLUG); - anx7447_reg_write(port, ANX7447_REG_HPD_CTRL_0, reg); -} - -void anx7447_hpd_output_en(int port) -{ - int reg, rv; - - rv = anx7447_reg_read(port, ANX7447_REG_HPD_DEGLITCH_H, ®); - if (rv) - return; - - reg |= ANX7447_REG_HPD_OEN; - anx7447_reg_write(port, ANX7447_REG_HPD_DEGLITCH_H, reg); -} - -void anx7447_set_hpd_level(int port, int hpd_lvl) -{ - int reg, rv; - - rv = anx7447_reg_read(port, ANX7447_REG_HPD_CTRL_0, ®); - if (rv) - return; - - /* - * When ANX7447_REG_HPD_MODE is 1, use ANX7447_REG_HPD_OUT - * to generate HPD event, otherwise use ANX7447_REG_HPD_UNPLUG - * and ANX7447_REG_HPD_PLUG. - */ - if (hpd_lvl) { - reg &= ~ANX7447_REG_HPD_UNPLUG; - reg |= ANX7447_REG_HPD_PLUG; - } else { - reg &= ~ANX7447_REG_HPD_PLUG; - reg |= ANX7447_REG_HPD_UNPLUG; - } - anx7447_reg_write(port, ANX7447_REG_HPD_CTRL_0, reg); -} - -#ifdef CONFIG_USB_PD_TCPM_ANX7447_OCM_ERASE_COMMAND -static inline void anx7447_reg_write_and(int port, int reg, int v_and) -{ - int val; - - if (!anx7447_reg_read(port, reg, &val)) - anx7447_reg_write(port, reg, (val & v_and)); -} - -static inline void anx7447_reg_write_or(int port, int reg, int v_or) -{ - int val; - - if (!anx7447_reg_read(port, reg, &val)) - anx7447_reg_write(port, reg, (val | v_or)); -} - -#define ANX7447_FLASH_DONE_TIMEOUT_US (100 * MSEC) - -static int anx7447_wait_for_flash_done(int port) -{ - timestamp_t deadline; - int rv; - int r; - - deadline.val = get_time().val + ANX7447_FLASH_DONE_TIMEOUT_US; - do { - if (timestamp_expired(deadline, NULL)) - return EC_ERROR_TIMEOUT; - rv = anx7447_reg_read(port, ANX7447_REG_R_RAM_CTRL, &r); - if (rv) - return rv; - } while (!(r & ANX7447_R_RAM_CTRL_FLASH_DONE)); - - return EC_SUCCESS; -} - -static int anx7447_flash_write_en(int port) -{ - anx7447_reg_write(port, ANX7447_REG_FLASH_INST_TYPE, - ANX7447_FLASH_INST_TYPE_WRITEENABLE); - anx7447_reg_write_or(port, ANX7447_REG_R_FLASH_RW_CTRL, - ANX7447_R_FLASH_RW_CTRL_GENERAL_INST_EN); - return anx7447_wait_for_flash_done(port); -} - -static int anx7447_flash_op_init(int port) -{ - int rv; - - anx7447_reg_write_or(port, ANX7447_REG_OCM_CTRL_0, - ANX7447_OCM_CTRL_OCM_RESET); - anx7447_reg_write_or(port, ANX7447_REG_ADDR_GPIO_CTRL_0, - ANX7447_ADDR_GPIO_CTRL_0_SPI_WP); - - rv = anx7447_flash_write_en(port); - if (rv) - return rv; - - anx7447_reg_write_and(port, ANX7447_REG_R_FLASH_STATUS_0, - ANX7447_FLASH_STATUS_SPI_STATUS_0); - anx7447_reg_write_or(port, ANX7447_REG_R_FLASH_RW_CTRL, - ANX7447_R_FLASH_RW_CTRL_WRITE_STATUS_EN); - - return anx7447_wait_for_flash_done(port); -} - -static int anx7447_flash_is_empty(int port) -{ - int r; - - anx7447_reg_read(port, ANX7447_REG_OCM_VERSION, &r); - - return ((r == 0) ? 1 : 0); -} - -static int anx7447_flash_erase_internal(int port, int write_console_if_empty) -{ - int rv; - int r; - - tcpc_read(port, TCPC_REG_COMMAND, &r); - usleep(ANX7447_DELAY_IN_US); - - if (anx7447_flash_is_empty(port) == 1) { - if (write_console_if_empty) - CPRINTS("C%d: Nothing to erase!", port); - return EC_SUCCESS; - } - CPRINTS("C%d: Erasing OCM flash...", port); - - rv = anx7447_flash_op_init(port); - if (rv) - return rv; - - usleep(ANX7447_DELAY_IN_US); - - rv = anx7447_flash_write_en(port); - if (rv) - return rv; - - anx7447_reg_write(port, ANX7447_REG_FLASH_ERASE_TYPE, - ANX7447_FLASH_ERASE_TYPE_CHIPERASE); - anx7447_reg_write_or(port, ANX7447_REG_R_FLASH_RW_CTRL, - ANX7447_R_FLASH_RW_CTRL_FLASH_ERASE_EN); - - return anx7447_wait_for_flash_done(port); -} - -int anx7447_flash_erase(int port) -{ - return anx7447_flash_erase_internal(port, - 0 /* suppress console if empty */); -} - -/* Add console command to erase OCM flash if needed. */ -static int command_anx_ocm(int argc, char **argv) -{ - char *e = NULL; - int port; - - if (argc < 2) - return EC_ERROR_PARAM_COUNT; - - /* Get port number from first parameter */ - port = strtoi(argv[1], &e, 0); - if (*e) - return EC_ERROR_PARAM1; - - if (argc > 2) { - int rv; - if (strcasecmp(argv[2], "erase")) - return EC_ERROR_PARAM2; - rv = anx7447_flash_erase_internal( - port, 1 /* write to console if empty */); - if (rv) - ccprintf("C%d: Failed to erase OCM flash (%d)\n", - port, rv); - } - - ccprintf("C%d: OCM flash is %sempty.\n", - port, anx7447_flash_is_empty(port) ? "" : "not "); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(anx_ocm, command_anx_ocm, - "port [erase]", - "Print OCM status or erases OCM for a given port."); -#endif - -static int anx7447_init(int port) -{ - int rv, reg, i; - const struct usb_mux *me = &usb_muxes[port]; - bool unused; - - ASSERT(port < CONFIG_USB_PD_PORT_MAX_COUNT); - - memset(&anx[port], 0, sizeof(struct anx_state)); - - /* - * find corresponding anx7447 SPI address according to - * specified TCPC address - */ - for (i = 0; i < ARRAY_SIZE(anx7447_i2c_addrs_flags); i++) { - if (I2C_STRIP_FLAGS(tcpc_config[port].i2c_info.addr_flags) == - I2C_STRIP_FLAGS( - anx7447_i2c_addrs_flags[i].tcpc_addr_flags)) { - anx[port].i2c_addr_flags = - anx7447_i2c_addrs_flags[i].spi_addr_flags; - break; - } - } - if (!I2C_STRIP_FLAGS(anx[port].i2c_addr_flags)) { - ccprintf("TCPC I2C addr 0x%x is invalid for ANX7447\n", - I2C_STRIP_FLAGS(tcpc_config[port] - .i2c_info.addr_flags)); - return EC_ERROR_UNKNOWN; - } - - - rv = tcpci_tcpm_init(port); - if (rv) - return rv; - -#ifdef CONFIG_USB_PD_TCPM_ANX7447_OCM_ERASE_COMMAND - /* Check and print OCM status to console. */ - CPRINTS("C%d: OCM flash is %sempty", - port, anx7447_flash_is_empty(port) ? "" : "not "); -#endif - - /* - * 7447 has a physical pin to detect the presence of VBUS, VBUS_SENSE - * , and 7447 has a VBUS current protection mechanism through another - * pin input VBUS_OCP. To enable VBUS OCP, OVP protection, driver needs - * to set the threshold to the registers VBUS_VOLTAGE_ALARM_HI_CFG - * (0x76 & 0x77) and VBUS_OCP_HI_THRESHOLD (0xDD &0xDE). These values - * could be customized based on different platform design. - * Disable VBUS protection here since the default values of - * VBUS_VOLTAGE_ALARM_HI_CFG and VBUS_OCP_HI_THRESHOLD are zero. - */ - rv = tcpc_read(port, ANX7447_REG_TCPC_CTRL_2, ®); - if (rv) - return rv; - reg &= ~ANX7447_REG_ENABLE_VBUS_PROTECT; - rv = tcpc_write(port, ANX7447_REG_TCPC_CTRL_2, reg); - if (rv) - return rv; - - /* - * Specifically disable voltage alarms, as VBUS_VOLTAGE_ALARM_HI may - * trigger repeatedly despite being masked (b/153989733) - */ - rv = tcpc_update16(port, TCPC_REG_POWER_CTRL, - TCPC_REG_POWER_CTRL_VBUS_VOL_MONITOR_DIS, MASK_SET); - if (rv) - return rv; - - /* ADC enable, use to monitor VBUS voltage */ - rv = tcpc_read(port, ANX7447_REG_ADC_CTRL_1, ®); - if (rv) - return rv; - reg |= ANX7447_REG_ADCFSM_EN; - rv = tcpc_write(port, ANX7447_REG_ADC_CTRL_1, reg); - if (rv) - return rv; - - /* Set VCONN OCP(Over Current Protection) threshold */ - rv = tcpc_read(port, ANX7447_REG_ANALOG_CTRL_8, ®); - if (rv) - return rv; - reg &= ~ANX7447_REG_VCONN_OCP_MASK; - reg |= ANX7447_REG_VCONN_OCP_440mA; - rv = tcpc_write(port, ANX7447_REG_ANALOG_CTRL_8, reg); - - /* Vconn SW protection time of inrush current */ - rv = tcpc_read(port, ANX7447_REG_ANALOG_CTRL_10, ®); - if (rv) - return rv; - reg &= ~ANX7447_REG_R_VCONN_PWR_PRT_INRUSH_TIME_MASK; - reg |= ANX7447_REG_R_VCONN_PWR_PRT_INRUSH_TIME_2430US; - rv = tcpc_write(port, ANX7447_REG_ANALOG_CTRL_10, reg); - if (rv) - return rv; - -#ifdef CONFIG_USB_PD_TCPM_MUX - /* - * Run mux_set() here for considering CCD(Case-Closed Debugging) case - * If this TCPC is not also the MUX then don't initialize to NONE - */ - while ((me != NULL) && (me->driver != &anx7447_usb_mux_driver)) - me = me->next_mux; - - /* - * Note that bypassing the usb_mux API is okay for internal driver calls - * since the task calling init already holds this port's mux lock. - */ - if (me != NULL && - !(me->flags & USB_MUX_FLAG_NOT_TCPC)) - rv = anx7447_mux_set(me, USB_PD_MUX_NONE, &unused); -#endif /* CONFIG_USB_PD_TCPM_MUX */ - - return rv; -} - -static int anx7447_release(int port) -{ - return EC_SUCCESS; -} - -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC -static int anx7447_get_vbus_voltage(int port) -{ - int vbus_volt = 0; - - tcpc_read16(port, TCPC_REG_VBUS_VOLTAGE, &vbus_volt); - - return vbus_volt; -} - -int anx7447_set_power_supply_ready(int port) -{ - int count = 0; - - while (is_equal_greater_safe0v(port)) { - if (count >= 10) - break; - msleep(100); - count++; - } - - return tcpc_write(port, TCPC_REG_COMMAND, 0x77); -} -#endif /* CONFIG_USB_PD_VBUS_DETECT_TCPC */ - -int anx7447_power_supply_reset(int port) -{ - return tcpc_write(port, TCPC_REG_COMMAND, 0x66); -} - -int anx7447_board_charging_enable(int port, int enable) -{ - return tcpc_write(port, TCPC_REG_COMMAND, enable ? 0x55 : 0x44); -} - -static void anx7447_tcpc_alert(int port) -{ - /* process and clear alert status */ - tcpci_tcpc_alert(port); -} - -/* - * timestamp of the next possible toggle to ensure the 2-ms spacing - * between IRQ_HPD. - */ -static uint64_t hpd_deadline[CONFIG_USB_PD_PORT_MAX_COUNT]; - -void anx7447_tcpc_update_hpd_status(const struct usb_mux *me, - mux_state_t mux_state) -{ - int reg = 0; - int port = me->usb_port; - int hpd_lvl = (mux_state & USB_PD_MUX_HPD_LVL) ? 1 : 0; - int hpd_irq = (mux_state & USB_PD_MUX_HPD_IRQ) ? 1 : 0; - - /* - * All calls within this method need to update to a mux_read/write calls - * that use the secondary address. This is a non-trival change and no - * one is using the anx7447 as a mux only (and probably never will since - * it doesn't have a re-driver). If that changes, we need to update this - * code. - */ - ASSERT(!(me->flags & USB_MUX_FLAG_NOT_TCPC)); - - anx7447_set_hpd_level(port, hpd_lvl); - - if (hpd_irq) { - uint64_t now = get_time().val; - /* wait for the minimum spacing between IRQ_HPD if needed */ - if (now < hpd_deadline[port]) - usleep(hpd_deadline[port] - now); - - /* - * For generate hardware HPD IRQ, need clear bit - * ANX7447_REG_HPD_IRQ0 first, then set it. This bit is not - * write clear. - */ - anx7447_reg_read(port, ANX7447_REG_HPD_CTRL_0, ®); - reg &= ~ANX7447_REG_HPD_IRQ0; - anx7447_reg_write(port, ANX7447_REG_HPD_CTRL_0, reg); - reg |= ANX7447_REG_HPD_IRQ0; - anx7447_reg_write(port, ANX7447_REG_HPD_CTRL_0, reg); - } - /* enforce 2-ms delay between HPD pulses */ - hpd_deadline[port] = get_time().val + HPD_USTREAM_DEBOUNCE_LVL; -} - -void anx7447_tcpc_clear_hpd_status(int port) -{ - anx7447_hpd_output_en(port); - anx7447_set_hpd_level(port, 0); -} - -#ifdef CONFIG_USB_PD_TCPM_MUX -static int anx7447_mux_init(const struct usb_mux *me) -{ - int port = me->usb_port; - bool unused; - - ASSERT(port < CONFIG_USB_PD_PORT_MAX_COUNT); - - memset(&mux[port], 0, sizeof(struct anx_usb_mux)); - - /* init hpd status */ - anx7447_hpd_mode_init(port); - anx7447_set_hpd_level(port, 0); - anx7447_hpd_output_en(port); - - /* - * ANX initializes its muxes to (USB_PD_MUX_USB_ENABLED | - * USB_PD_MUX_DP_ENABLED) when reinitialized, we need to force - * initialize it to USB_PD_MUX_NONE - */ - return anx7447_mux_set(me, USB_PD_MUX_NONE, &unused); -} - -#ifdef CONFIG_USB_PD_TCPM_ANX7447_AUX_PU_PD -static void anx7447_mux_safemode(const struct usb_mux *me, int on_off) -{ - int reg; - - mux_read(me, ANX7447_REG_ANALOG_CTRL_9, ®); - - if (on_off) - reg |= ANX7447_REG_SAFE_MODE; - else - reg &= ~(ANX7447_REG_SAFE_MODE); - - mux_write(me, ANX7447_REG_ANALOG_CTRL_9, reg); - CPRINTS("C%d set mux to safemode %s, reg = 0x%x", - me->usb_port, (on_off) ? "on" : "off", reg); -} - -static inline void anx7447_configure_aux_src(const struct usb_mux *me, - int on_off) -{ - int reg; - - mux_read(me, ANX7447_REG_ANALOG_CTRL_9, ®); - - if (on_off) - reg |= ANX7447_REG_R_AUX_RES_PULL_SRC; - else - reg &= ~(ANX7447_REG_R_AUX_RES_PULL_SRC); - - mux_write(me, ANX7447_REG_ANALOG_CTRL_9, reg); - - CPRINTS("C%d set aux_src to %s, reg = 0x%x", - me->usb_port, (on_off) ? "on" : "off", reg); -} -#endif - -/* - * Set mux. - * - * sstx and ssrx are the USB superspeed transmit and receive pairs. ml is the - * DisplayPort Main Link. There are four lanes total. For example, DP cases - * connect them all and dock cases connect 2 DP and USB. - * - * a2, a3, a10, a11, b2, b3, b10, b11 are pins on the USB-C connector. - */ -static int anx7447_mux_set(const struct usb_mux *me, mux_state_t mux_state, - bool *ack_required) -{ - int cc_direction; - mux_state_t mux_type; - int sw_sel = 0x00, aux_sw = 0x00; - int rv; - int port = me->usb_port; - - /* This driver does not use host command ACKs */ - *ack_required = false; - - cc_direction = mux_state & USB_PD_MUX_POLARITY_INVERTED; - mux_type = mux_state & USB_PD_MUX_DOCK; - CPRINTS("C%d mux_state = 0x%x, mux_type = 0x%x", - port, mux_state, mux_type); - if (cc_direction == 0) { - /* cc1 connection */ - if (mux_type == USB_PD_MUX_DOCK) { - /* ml0-a10/11, ml1-b2/b3, sstx-a2/a3, ssrx-b10/11 */ - sw_sel = 0x21; - /* aux+ <-> sbu1, aux- <-> sbu2 */ - aux_sw = 0x03; - } else if (mux_type == USB_PD_MUX_DP_ENABLED) { - /* ml0-a10/11, ml1-b2/b3, ml2-a2/a3, ml3-b10/11 */ - sw_sel = 0x09; - /* aux+ <-> sbu1, aux- <-> sbu2 */ - aux_sw = 0x03; - } else if (mux_type == USB_PD_MUX_USB_ENABLED) { - /* ssrxp<->b11, ssrxn<->b10, sstxp<->a2, sstxn<->a3 */ - sw_sel = 0x20; - } - } else { - /* cc2 connection */ - if (mux_type == USB_PD_MUX_DOCK) { - /* ml0-b10/11, ml1-a2/b3, sstx-b2/a3, ssrx-a10/11 */ - sw_sel = 0x12; - /* aux+ <-> sbu2, aux- <-> sbu1 */ - aux_sw = 0x0C; - } else if (mux_type == USB_PD_MUX_DP_ENABLED) { - /* ml0-b10/11, ml1-a2/b3, ml2-b2/a3, ml3-a10/11 */ - sw_sel = 0x06; - /* aux+ <-> sbu2, aux- <-> sbu1 */ - aux_sw = 0x0C; - } else if (mux_type == USB_PD_MUX_USB_ENABLED) { - /* ssrxp<->a11, ssrxn<->a10, sstxp<->b2, sstxn<->b3 */ - sw_sel = 0x10; - } - } - - /* - * Once need to configure the Mux, should set the mux to safe mode - * first. After the mux configured, should set mux to normal mode. - */ -#ifdef CONFIG_USB_PD_TCPM_ANX7447_AUX_PU_PD - anx7447_mux_safemode(me, 1); -#endif - rv = mux_write(me, ANX7447_REG_TCPC_SWITCH_0, sw_sel); - rv |= mux_write(me, ANX7447_REG_TCPC_SWITCH_1, sw_sel); - rv |= mux_write(me, ANX7447_REG_TCPC_AUX_SWITCH, aux_sw); - - mux[port].state = mux_state; - -#ifdef CONFIG_USB_PD_TCPM_ANX7447_AUX_PU_PD - /* - * DP and Dock mode: after configured the Mux, change the Mux to - * normal mode, otherwise: keep safe mode. - */ - if (mux_type != USB_PD_MUX_NONE) { - anx7447_configure_aux_src(me, 1); - anx7447_mux_safemode(me, 0); - } else - anx7447_configure_aux_src(me, 0); -#endif - - return rv; -} - -/* current mux state */ -static int anx7447_mux_get(const struct usb_mux *me, mux_state_t *mux_state) -{ - int port = me->usb_port; - - *mux_state = mux[port].state; - - return EC_SUCCESS; -} -#endif /* CONFIG_USB_PD_TCPM_MUX */ - -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE -static int anx7447_tcpc_drp_toggle(int port) -{ - int rv, reg; - - rv = tcpc_read(port, ANX7447_REG_ANALOG_CTRL_10, ®); - if (rv) - return rv; - /* - * When using Look4Connection command to toggle CC under normal mode - * the CABLE_DET_DIG shall be clear first. - */ - if (reg & ANX7447_REG_CABLE_DET_DIG) { - reg &= ~ANX7447_REG_CABLE_DET_DIG; - rv = tcpc_write(port, ANX7447_REG_ANALOG_CTRL_10, reg); - if (rv) - return rv; - } - - return tcpci_tcpc_drp_toggle(port); -} -#endif - -/* Override for tcpci_tcpm_set_cc */ -static int anx7447_set_cc(int port, int pull) -{ - int rp, reg; - - rp = tcpc_read(port, ANX7447_REG_ANALOG_CTRL_10, ®); - if (rp) - return rp; - /* - * When setting CC status, should be confirm that the CC toggling - * process is stopped, the CABLE_DET_DIG shall be set to one. - */ - if ((reg & ANX7447_REG_CABLE_DET_DIG) == 0) { - reg |= ANX7447_REG_CABLE_DET_DIG; - rp = tcpc_write(port, ANX7447_REG_ANALOG_CTRL_10, reg); - if (rp) - return rp; - } - - rp = tcpci_get_cached_rp(port); - - /* Set manual control, and set both CC lines to the same pull */ - return tcpc_write(port, TCPC_REG_ROLE_CTRL, - TCPC_REG_ROLE_CTRL_SET(0, rp, pull, pull)); -} - -/* Override for tcpci_tcpm_set_polarity */ -static int anx7447_set_polarity(int port, - enum tcpc_cc_polarity polarity) -{ - return tcpc_update8(port, - TCPC_REG_TCPC_CTRL, - TCPC_REG_TCPC_CTRL_SET(1), - polarity_rm_dts(polarity) - ? MASK_SET : MASK_CLR); -} - -#ifdef CONFIG_CMD_TCPC_DUMP -static const struct tcpc_reg_dump_map anx7447_regs[] = { - { - .addr = ANX7447_REG_TCPC_SWITCH_0, - .name = "SWITCH_0", - .size = 1, - }, - { - .addr = ANX7447_REG_TCPC_SWITCH_1, - .name = "SWITCH_1", - .size = 1, - }, - { - .addr = ANX7447_REG_TCPC_AUX_SWITCH, - .name = "AUX_SWITCH", - .size = 1, - }, - { - .addr = ANX7447_REG_ADC_CTRL_1, - .name = "ADC_CTRL_1", - .size = 1, - }, - { - .addr = ANX7447_REG_ANALOG_CTRL_8, - .name = "ANALOG_CTRL_8", - .size = 1, - }, - { - .addr = ANX7447_REG_ANALOG_CTRL_10, - .name = "ANALOG_CTRL_10", - .size = 1, - }, - { - .addr = ANX7447_REG_TCPC_CTRL_2, - .name = "TCPC_CTRL_2", - .size = 1, - }, -}; - -const struct { - const char *name; - uint8_t addr; -} anx7447_alt_regs[] = { - { - .name = "HPD_CTRL_0", - .addr = ANX7447_REG_HPD_CTRL_0, - }, - { - .name = "HPD_DEGLITCH_H", - .addr = ANX7447_REG_HPD_DEGLITCH_H, - }, - { - .name = "INTP_SOURCE_0", - .addr = ANX7447_REG_INTP_SOURCE_0, - }, - { - .name = "INTP_MASK_0", - .addr = ANX7447_REG_INTP_MASK_0, - }, - { - .name = "INTP_CTRL_0", - .addr = ANX7447_REG_INTP_CTRL_0, - }, - { - .name = "PAD_INTP_CTRL", - .addr = ANX7447_REG_PAD_INTP_CTRL, - }, -}; - -/* - * Dump registers for debug command. - */ -static void anx7447_dump_registers(int port) -{ - int i, val; - - tcpc_dump_std_registers(port); - tcpc_dump_registers(port, anx7447_regs, ARRAY_SIZE(anx7447_regs)); - for (i = 0; i < ARRAY_SIZE(anx7447_alt_regs); i++) { - anx7447_reg_read(port, anx7447_alt_regs[i].addr, &val); - ccprintf(" %-26s(ALT/0x%02x) = 0x%02x\n", - anx7447_alt_regs[i].name, - anx7447_alt_regs[i].addr, (uint8_t)val); - cflush(); - } -} -#endif /* defined(CONFIG_CMD_TCPC_DUMP) */ - -/* - * ANX7447 is a TCPCI compatible port controller, with some caveats. - * It seems to require both CC lines to be set always, instead of just - * one at a time, according to TCPCI spec. Thus, now that the TCPCI - * driver more closely follows the spec, this driver requires - * overrides for set_cc and set_polarity. - */ -const struct tcpm_drv anx7447_tcpm_drv = { - .init = &anx7447_init, - .release = &anx7447_release, - .get_cc = &tcpci_tcpm_get_cc, -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - .check_vbus_level = &tcpci_tcpm_check_vbus_level, -#endif - .select_rp_value = &tcpci_tcpm_select_rp_value, - .set_cc = &anx7447_set_cc, - .set_polarity = &anx7447_set_polarity, -#ifdef CONFIG_USB_PD_DECODE_SOP - .sop_prime_enable = &tcpci_tcpm_sop_prime_enable, -#endif - .set_vconn = &tcpci_tcpm_set_vconn, - .set_msg_header = &tcpci_tcpm_set_msg_header, - .set_rx_enable = &tcpci_tcpm_set_rx_enable, - .get_message_raw = &tcpci_tcpm_get_message_raw, - .transmit = &tcpci_tcpm_transmit, - .tcpc_alert = &anx7447_tcpc_alert, -#ifdef CONFIG_USB_PD_DISCHARGE_TCPC - .tcpc_discharge_vbus = &tcpci_tcpc_discharge_vbus, -#endif -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - .drp_toggle = anx7447_tcpc_drp_toggle, -#endif - .get_chip_info = &tcpci_get_chip_info, -#ifdef CONFIG_USB_PD_PPC - .set_snk_ctrl = &tcpci_tcpm_set_snk_ctrl, - .set_src_ctrl = &tcpci_tcpm_set_src_ctrl, -#endif -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER - .enter_low_power_mode = &tcpci_enter_low_power_mode, -#endif - .set_bist_test_mode = &tcpci_set_bist_test_mode, -#ifdef CONFIG_CMD_TCPC_DUMP - .dump_registers = &anx7447_dump_registers, -#endif -}; - -#ifdef CONFIG_USB_PD_TCPM_MUX -const struct usb_mux_driver anx7447_usb_mux_driver = { - .init = anx7447_mux_init, - .set = anx7447_mux_set, - .get = anx7447_mux_get, -}; -#endif /* CONFIG_USB_PD_TCPM_MUX */ - diff --git a/driver/tcpm/anx7447.h b/driver/tcpm/anx7447.h deleted file mode 100644 index 75982e6b91..0000000000 --- a/driver/tcpm/anx7447.h +++ /dev/null @@ -1,156 +0,0 @@ -/* Copyright 2018 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 "usb_mux.h" - -/* USB Power delivery port management */ - -#ifndef __CROS_EC_USB_PD_TCPM_ANX7447_H -#define __CROS_EC_USB_PD_TCPM_ANX7447_H - -/* Registers: TCPC address used */ -#define ANX7447_REG_TCPC_SWITCH_0 0xB4 -#define ANX7447_REG_TCPC_SWITCH_1 0xB5 -#define ANX7447_REG_TCPC_AUX_SWITCH 0xB6 - -#define ANX7447_REG_INTR_ALERT_MASK_0 0xC9 - -#define ANX7447_REG_TCPC_CTRL_2 0xCD -#define ANX7447_REG_ENABLE_VBUS_PROTECT 0x20 - -#define ANX7447_REG_ADC_CTRL_1 0xBF -#define ANX7447_REG_ADCFSM_EN 0x20 - -/* Registers: SPI address used */ -#define ANX7447_REG_INTP_SOURCE_0 0x67 - -#define ANX7447_REG_HPD_CTRL_0 0x7E -#define ANX7447_REG_HPD_MODE 0x01 -#define ANX7447_REG_HPD_OUT 0x02 -#define ANX7447_REG_HPD_IRQ0 0x04 -#define ANX7447_REG_HPD_PLUG 0x08 -#define ANX7447_REG_HPD_UNPLUG 0x10 - -#define ANX7447_REG_HPD_DEGLITCH_H 0x80 -#define ANX7447_REG_HPD_DETECT 0x80 -#define ANX7447_REG_HPD_OEN 0x40 - -#define ANX7447_REG_PAD_INTP_CTRL 0x85 - -#define ANX7447_REG_INTP_MASK_0 0x86 - -#define ANX7447_REG_INTP_CTRL_0 0x9E - -#define ANX7447_REG_ANALOG_CTRL_8 0xA8 -#define ANX7447_REG_VCONN_OCP_MASK 0x0C -#define ANX7447_REG_VCONN_OCP_240mA 0x00 -#define ANX7447_REG_VCONN_OCP_310mA 0x04 -#define ANX7447_REG_VCONN_OCP_370mA 0x08 -#define ANX7447_REG_VCONN_OCP_440mA 0x0C - -#define ANX7447_REG_ANALOG_CTRL_10 0xAA -#define ANX7447_REG_CABLE_DET_DIG 0x40 - -#define ANX7447_REG_R_VCONN_PWR_PRT_INRUSH_TIME_MASK 0x38 -#define ANX7447_REG_R_VCONN_PWR_PRT_INRUSH_TIME_19US 0x00 -#define ANX7447_REG_R_VCONN_PWR_PRT_INRUSH_TIME_38US 0x08 -#define ANX7447_REG_R_VCONN_PWR_PRT_INRUSH_TIME_76US 0x10 -#define ANX7447_REG_R_VCONN_PWR_PRT_INRUSH_TIME_152US 0x18 -#define ANX7447_REG_R_VCONN_PWR_PRT_INRUSH_TIME_303US 0x20 -#define ANX7447_REG_R_VCONN_PWR_PRT_INRUSH_TIME_607US 0x28 -#define ANX7447_REG_R_VCONN_PWR_PRT_INRUSH_TIME_1210US 0x30 -#define ANX7447_REG_R_VCONN_PWR_PRT_INRUSH_TIME_2430US 0x38 - -#define ANX7447_REG_ANALOG_CTRL_9 0xA9 -#define ANX7447_REG_SAFE_MODE 0x80 -#define ANX7447_REG_R_AUX_RES_PULL_SRC 0x20 - -/* - * This section of defines are only required to support the config option - * CONFIG_USB_PD_TCPM_ANX7447_OCM_ERASE_COMMAND. - */ -/* SPI registers used for OCM flash operations */ -#define ANX7447_DELAY_IN_US (20*1000) - -#define ANX7447_REG_R_RAM_CTRL 0x05 -#define ANX7447_REG_R_FLASH_RW_CTRL 0x30 -#define ANX7447_REG_R_FLASH_STATUS_0 0x31 -#define ANX7447_REG_FLASH_INST_TYPE 0x33 -#define ANX7447_REG_FLASH_ERASE_TYPE 0x34 -#define ANX7447_REG_OCM_CTRL_0 0x6E -#define ANX7447_REG_ADDR_GPIO_CTRL_0 0x88 -#define ANX7447_REG_OCM_VERSION 0xB4 - -/* R_RAM_CTRL bit definitions */ -#define ANX7447_R_RAM_CTRL_FLASH_DONE (1<<7) - -/* R_FLASH_RW_CTRL bit definitions */ -#define ANX7447_R_FLASH_RW_CTRL_GENERAL_INST_EN (1<<6) -#define ANX7447_R_FLASH_RW_CTRL_FLASH_ERASE_EN (1<<5) -#define ANX7447_R_FLASH_RW_CTRL_WRITE_STATUS_EN (1<<2) -#define ANX7447_R_FLASH_RW_CTRL_FLASH_READ (1<<1) -#define ANX7447_R_FLASH_RW_CTRL_FLASH_WRITE (1<<0) - -/* R_FLASH_STATUS_0 definitions */ -#define ANX7447_FLASH_STATUS_SPI_STATUS_0 0x43 - -/* FLASH_ERASE_TYPE bit definitions */ -#define ANX7447_FLASH_INST_TYPE_WRITEENABLE 0x06 -#define ANX7447_FLASH_ERASE_TYPE_CHIPERASE 0x60 - -/* OCM_CTRL_0 bit definitions */ -#define ANX7447_OCM_CTRL_OCM_RESET (1<<6) - -/* ADDR_GPIO_CTRL_0 bit definitions */ -#define ANX7447_ADDR_GPIO_CTRL_0_SPI_WP (1<<7) -#define ANX7447_ADDR_GPIO_CTRL_0_SPI_CLK_ENABLE (1<<6) -/* End of defines used for CONFIG_USB_PD_TCPM_ANX7447_OCM_ERASE_COMMAND */ - -struct anx7447_i2c_addr { - uint16_t tcpc_addr_flags; - uint16_t spi_addr_flags; -}; - -#define AN7447_TCPC0_I2C_ADDR_FLAGS 0x2C -#define AN7447_TCPC1_I2C_ADDR_FLAGS 0x2B -#define AN7447_TCPC2_I2C_ADDR_FLAGS 0x2A -#define AN7447_TCPC3_I2C_ADDR_FLAGS 0x29 - -#define AN7447_SPI0_I2C_ADDR_FLAGS 0x3F -#define AN7447_SPI1_I2C_ADDR_FLAGS 0x37 -#define AN7447_SPI2_I2C_ADDR_FLAGS 0x32 -#define AN7447_SPI3_I2C_ADDR_FLAGS 0x31 - -/* - * Time TEST_R must be held high for a reset - */ -#define ANX74XX_RESET_HOLD_MS 1 -/* - * Time after TEST_R reset to wait for eFuse loading - */ -#define ANX74XX_RESET_FINISH_MS 2 - -int anx7447_set_power_supply_ready(int port); -int anx7447_power_supply_reset(int port); -int anx7447_board_charging_enable(int port, int enable); - -void anx7447_hpd_mode_en(int port); -void anx7447_hpd_output_en(int port); - -extern const struct tcpm_drv anx7447_tcpm_drv; -extern const struct usb_mux_driver anx7447_usb_mux_driver; -void anx7447_tcpc_clear_hpd_status(int port); -void anx7447_tcpc_update_hpd_status(const struct usb_mux *me, - mux_state_t mux_state); - -/** - * Erase OCM flash if it's not empty - * - * @param port: USB-C port number - * @return: EC_SUCCESS or EC_ERROR_* - */ -int anx7447_flash_erase(int port); - -#endif /* __CROS_EC_USB_PD_TCPM_ANX7688_H */ diff --git a/driver/tcpm/anx74xx.c b/driver/tcpm/anx74xx.c deleted file mode 100644 index 567005920e..0000000000 --- a/driver/tcpm/anx74xx.c +++ /dev/null @@ -1,1210 +0,0 @@ -/* Copyright 2016 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. - * - * Author : Analogix Semiconductor. - */ - -/* Type-C port manager for Analogix's anx74xx chips */ - -#include "console.h" -#include "anx74xx.h" -#include "task.h" -#include "tcpm/tcpci.h" -#include "tcpm/tcpm.h" -#include "timer.h" -#include "usb_charge.h" -#include "usb_mux.h" -#include "usb_pd.h" -#include "usb_pd_tcpc.h" -#include "usb_pd_tcpm.h" -#include "util.h" - -#if !defined(CONFIG_USB_PD_TCPM_TCPCI) -#error "ANX74xx is using part of standard TCPCI control" -#error "Please upgrade your board configuration" -#endif - -#if defined(CONFIG_USB_PD_REV30) -#error "ANX74xx chips were developed before PD 3.0 and aren't PD 3.0 compliant" -#error "Please undefine PD 3.0. See b/159253723 for details" -#endif - -#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) -#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) - -struct anx_state { - int polarity; - int vconn_en; - int mux_state; -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER - int prev_mode; -#endif -}; -#define clear_recvd_msg_int(port) do {\ - int reg, rv; \ - rv = tcpc_read(port, ANX74XX_REG_RECVD_MSG_INT, ®); \ - if (!rv) \ - tcpc_write(port, ANX74XX_REG_RECVD_MSG_INT, \ - reg | 0x01); \ - } while (0) - -static struct anx_state anx[CONFIG_USB_PD_PORT_MAX_COUNT]; - -#ifdef CONFIG_USB_PD_DECODE_SOP -/* Save the message address */ -static int msg_sop[CONFIG_USB_PD_PORT_MAX_COUNT]; -#endif - -static int anx74xx_tcpm_init(int port); - -static void anx74xx_tcpm_set_auto_good_crc(int port, int enable) -{ - int reply_sop_en = 0; - - if (enable) { - reply_sop_en = ANX74XX_REG_REPLY_SOP_EN; -#ifdef CONFIG_USB_PD_DECODE_SOP - /* - * Only the VCONN Source is allowed to communicate - * with the Cable Plugs. - */ - if (anx[port].vconn_en) { - reply_sop_en |= ANX74XX_REG_REPLY_SOP_1_EN | - ANX74XX_REG_REPLY_SOP_2_EN; - } -#endif - } - - tcpc_write(port, ANX74XX_REG_TX_AUTO_GOODCRC_2, reply_sop_en); -} - -static void anx74xx_update_cable_det(int port, int mode) -{ -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER - int reg; - - if (anx[port].prev_mode == mode) - return; - - /* Update power mode */ - anx[port].prev_mode = mode; - - /* Get ANALOG_CTRL_0 for cable det bit */ - if (tcpc_read(port, ANX74XX_REG_ANALOG_CTRL_0, ®)) - return; - - if (mode == ANX74XX_STANDBY_MODE) { - int cc_reg; - - /* - * The ANX4329 enters standby mode by setting PWR_EN signal - * low. In addition, RESET_L must be set low to keep the ANX3429 - * in standby mode. - * - * Clearing bit 7 of ANX74XX_REG_ANALOG_CTRL_0 will cause the - * ANX3429 to clear the cable_det signal that goes from the - * ANX3429 to the EC. If this bit is cleared when a cable is - * attached then cable_det will go high once standby is entered. - * - * In some cases, such as when the chipset power state is - * S3/S5/G3 and a sink only adapter is connected to the port, - * this behavior is undesirable. The constant toggling between - * standby and normal mode means that effectively the ANX3429 is - * not in standby mode only consumes ~1 mW less than just - * remaining in normal mode. However when an E mark cable is - * connected, clearing bit 7 is required so that while the E - * mark cable configuration happens, the USB PD state machine - * will continue to wake up until the USB PD attach event can be - * regtistered. - * - * Therefore, the decision to clear bit 7 is based on the - * current CC status of the port. If the CC status is open for - * both CC lines OR if either CC line is showing Ra, then clear - * bit 7. Not clearing bit 7 has no impact for normal cables and - * prevents the constant toggle of standby<->normal when an - * adapter is connected that isn't allowed to attach. Clearing - * bit 7 when CC status reads Ra for either CC line allows the - * USB PD state machine to be woken until the attach event can - * happen. Note that in the case an E mark cable is connected - * and can't attach (i.e. sink only port <- Emark cable -> sink - * only adapter), then the ANX3429 will toggle indefinitely, - * until either the cable is removed, or the port drp status - * changes so the attach event can occur. - * . - */ - - /* Read CC status to see if cable_det bit should be cleared */ - if (tcpc_read(port, ANX74XX_REG_CC_STATUS, &cc_reg)) - return; - /* If open or either CC line is Ra, then clear cable_det */ - if (!cc_reg || (cc_reg & ANX74XX_CC_RA_MASK && - !(cc_reg & ANX74XX_CC_RD_MASK))) - reg &= ~ANX74XX_REG_R_PIN_CABLE_DET; - } else { - reg |= ANX74XX_REG_R_PIN_CABLE_DET; - } - - tcpc_write(port, ANX74XX_REG_ANALOG_CTRL_0, reg); -#endif -} - -static void anx74xx_set_power_mode(int port, int mode) -{ - /* - * Update PWR_EN and RESET_N signals to the correct level. High for - * Normal mode and low for Standby mode. When transitioning from standby - * to normal mode, must set the PWR_EN and RESET_N before attempting to - * modify cable_det bit of analog_ctrl_0. If going from Normal to - * Standby, updating analog_ctrl_0 must happen before setting PWR_EN and - * RESET_N low. - */ - if (mode == ANX74XX_NORMAL_MODE) { - /* Take chip out of standby mode */ - board_set_tcpc_power_mode(port, mode); - /* Update the cable det signal */ - anx74xx_update_cable_det(port, mode); - } else { - /* Update cable cable det signal */ - anx74xx_update_cable_det(port, mode); - /* - * Delay between setting cable_det low and setting RESET_L low - * as recommended the ANX3429 datasheet. - */ - msleep(1); - /* Put chip into standby mode */ - board_set_tcpc_power_mode(port, mode); - } -} - -#if defined(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE) && \ - defined(CONFIG_USB_PD_TCPC_LOW_POWER) - -static int anx74xx_tcpc_drp_toggle(int port) -{ - /* - * The ANX3429 always auto-toggles when in low power mode. Since this is - * not configurable, there is nothing to do here. DRP auto-toggle will - * happen once low power mode is set via anx74xx_enter_low_power_mode(). - * Note: this means the ANX3429 auto-toggles in PD_DRP_FORCE_SINK mode, - * which is undesirable (b/72007056). - */ - return EC_SUCCESS; -} - -static int anx74xx_enter_low_power_mode(int port) -{ - anx74xx_set_power_mode(port, ANX74XX_STANDBY_MODE); - return EC_SUCCESS; -} - -#endif - -void anx74xx_tcpc_set_vbus(int port, int enable) -{ - int reg; - - tcpc_read(port, ANX74XX_REG_GPIO_CTRL_4_5, ®); - if (enable) - reg |= ANX74XX_REG_SET_VBUS; - else - reg &= ~ANX74XX_REG_SET_VBUS; - tcpc_write(port, ANX74XX_REG_GPIO_CTRL_4_5, reg); -} - -#ifdef CONFIG_USB_PD_DISCHARGE_TCPC -static void anx74xx_tcpc_discharge_vbus(int port, int enable) -{ - int reg; - - tcpc_read(port, ANX74XX_REG_HPD_CTRL_0, ®); - if (enable) - reg |= ANX74XX_REG_DISCHARGE_CTRL; - else - reg &= ~ANX74XX_REG_DISCHARGE_CTRL; - tcpc_write(port, ANX74XX_REG_HPD_CTRL_0, reg); -} -#endif - -/* - * timestamp of the next possible toggle to ensure the 2-ms spacing - * between IRQ_HPD. - */ -static uint64_t hpd_deadline[CONFIG_USB_PD_PORT_MAX_COUNT]; - -void anx74xx_tcpc_update_hpd_status(const struct usb_mux *me, - mux_state_t mux_state) -{ - int reg; - int port = me->usb_port; - int hpd_lvl = (mux_state & USB_PD_MUX_HPD_LVL) ? 1 : 0; - int hpd_irq = (mux_state & USB_PD_MUX_HPD_IRQ) ? 1 : 0; - - mux_read(me, ANX74XX_REG_HPD_CTRL_0, ®); - if (hpd_lvl) - reg |= ANX74XX_REG_HPD_OUT_DATA; - else - reg &= ~ANX74XX_REG_HPD_OUT_DATA; - mux_write(me, ANX74XX_REG_HPD_CTRL_0, reg); - - if (hpd_irq) { - uint64_t now = get_time().val; - /* wait for the minimum spacing between IRQ_HPD if needed */ - if (now < hpd_deadline[port]) - usleep(hpd_deadline[port] - now); - - mux_read(me, ANX74XX_REG_HPD_CTRL_0, ®); - reg &= ~ANX74XX_REG_HPD_OUT_DATA; - mux_write(me, ANX74XX_REG_HPD_CTRL_0, reg); - usleep(HPD_DSTREAM_DEBOUNCE_IRQ); - reg |= ANX74XX_REG_HPD_OUT_DATA; - mux_write(me, ANX74XX_REG_HPD_CTRL_0, reg); - } - /* enforce 2-ms delay between HPD pulses */ - hpd_deadline[port] = get_time().val + HPD_USTREAM_DEBOUNCE_LVL; -} - -void anx74xx_tcpc_clear_hpd_status(int port) -{ - int reg; - - tcpc_read(port, ANX74XX_REG_HPD_CTRL_0, ®); - reg &= 0xcf; - tcpc_write(port, ANX74XX_REG_HPD_CTRL_0, reg); -} - -#ifdef CONFIG_USB_PD_TCPM_MUX -static int anx74xx_tcpm_mux_init(const struct usb_mux *me) -{ - /* Nothing to do here, ANX initializes its muxes - * as (USB_PD_MUX_USB_ENABLED | USB_PD_MUX_DP_ENABLED) - */ - anx[me->usb_port].mux_state = USB_PD_MUX_USB_ENABLED | - USB_PD_MUX_DP_ENABLED; - - return EC_SUCCESS; -} - -static int anx74xx_tcpm_mux_enter_safe_mode(int port) -{ - int reg; - const struct usb_mux *me = &usb_muxes[port]; - - if (mux_read(me, ANX74XX_REG_ANALOG_CTRL_2, ®)) - return EC_ERROR_UNKNOWN; - if (mux_write(me, ANX74XX_REG_ANALOG_CTRL_2, reg | - ANX74XX_REG_MODE_TRANS)) - return EC_ERROR_UNKNOWN; - - - return EC_SUCCESS; -} - -static int anx74xx_tcpm_mux_exit_safe_mode(int port) -{ - int reg; - const struct usb_mux *me = &usb_muxes[port]; - - if (mux_read(me, ANX74XX_REG_ANALOG_CTRL_2, ®)) - return EC_ERROR_UNKNOWN; - if (mux_write(me, ANX74XX_REG_ANALOG_CTRL_2, reg & - ~ANX74XX_REG_MODE_TRANS)) - return EC_ERROR_UNKNOWN; - - - return EC_SUCCESS; -} - -static int anx74xx_tcpm_mux_exit(int port) -{ - int reg; - const struct usb_mux *me = &usb_muxes[port]; - - /* - * Safe mode must be entered before any changes are made to the mux - * settings used to enable ALT_DP mode. This function is called either - * from anx74xx_tcpm_mux_set when USB_PD_MUX_NONE is selected as the - * new mux state, or when both cc lines are determined to be - * TYPEC_CC_VOLT_OPEN. Therefore, safe mode must be entered and exited - * here so that both entry paths are handled. - */ - if (anx74xx_tcpm_mux_enter_safe_mode(port)) - return EC_ERROR_UNKNOWN; - - /* Disconnect aux from sbu */ - if (mux_read(me, ANX74XX_REG_ANALOG_CTRL_2, ®)) - return EC_ERROR_UNKNOWN; - if (mux_write(me, ANX74XX_REG_ANALOG_CTRL_2, reg & 0xf)) - return EC_ERROR_UNKNOWN; - - /* Clear Bit[7:0] R_SWITCH */ - if (mux_write(me, ANX74XX_REG_ANALOG_CTRL_1, 0x0)) - return EC_ERROR_UNKNOWN; - /* Clear Bit[7:4] R_SWITCH_H */ - if (mux_read(me, ANX74XX_REG_ANALOG_CTRL_5, ®)) - return EC_ERROR_UNKNOWN; - if (mux_write(me, ANX74XX_REG_ANALOG_CTRL_5, reg & 0x0f)) - return EC_ERROR_UNKNOWN; - - /* Exit safe mode */ - if (anx74xx_tcpm_mux_exit_safe_mode(port)) - return EC_ERROR_UNKNOWN; - - return EC_SUCCESS; -} - - -static int anx74xx_mux_aux_to_sbu(int port, int polarity, int enabled) -{ - int reg; - const int aux_mask = ANX74XX_REG_AUX_SWAP_SET_CC2 | - ANX74XX_REG_AUX_SWAP_SET_CC1; - const struct usb_mux *me = &usb_muxes[port]; - - /* - * Get the current value of analog_ctrl_2 register. Note, that safe mode - * is enabled and exited by the calling function, so only have to worry - * about setting the correct value for the upper 4 bits of analog_ctrl_2 - * here. - */ - if (mux_read(me, ANX74XX_REG_ANALOG_CTRL_2, ®)) - return EC_ERROR_UNKNOWN; - - /* Assume aux_p/n lines are not connected */ - reg &= ~aux_mask; - - if (enabled) { - /* If enabled, connect aux to sbu based on desired polarity */ - if (polarity) - reg |= ANX74XX_REG_AUX_SWAP_SET_CC2; - else - reg |= ANX74XX_REG_AUX_SWAP_SET_CC1; - } - /* Write new aux <-> sbu settings */ - if (mux_write(me, ANX74XX_REG_ANALOG_CTRL_2, reg)) - return EC_ERROR_UNKNOWN; - - return EC_SUCCESS; -} - -static int anx74xx_tcpm_mux_set(const struct usb_mux *me, - mux_state_t mux_state, - bool *ack_required) -{ - int ctrl5; - int ctrl1 = 0; - int rv; - int port = me->usb_port; - - /* This driver does not use host command ACKs */ - *ack_required = false; - - if (!(mux_state & ~USB_PD_MUX_POLARITY_INVERTED)) { - anx[port].mux_state = mux_state; - return anx74xx_tcpm_mux_exit(port); - } - - rv = mux_read(me, ANX74XX_REG_ANALOG_CTRL_5, &ctrl5); - if (rv) - return EC_ERROR_UNKNOWN; - ctrl5 &= 0x0f; - - if (mux_state & USB_PD_MUX_USB_ENABLED) { - /* Connect USB SS switches */ - if (mux_state & USB_PD_MUX_POLARITY_INVERTED) { - ctrl1 = ANX74XX_REG_MUX_SSRX_RX2; - ctrl5 |= ANX74XX_REG_MUX_SSTX_TX2; - } else { - ctrl1 = ANX74XX_REG_MUX_SSRX_RX1; - ctrl5 |= ANX74XX_REG_MUX_SSTX_TX1; - } - if (mux_state & USB_PD_MUX_DP_ENABLED) { - /* Set pin assignment D */ - if (mux_state & USB_PD_MUX_POLARITY_INVERTED) - ctrl1 |= (ANX74XX_REG_MUX_ML0_RX1 | - ANX74XX_REG_MUX_ML1_TX1); - else - ctrl1 |= (ANX74XX_REG_MUX_ML0_RX2 | - ANX74XX_REG_MUX_ML1_TX2); - } - /* Keep ML0/ML1 unconnected if DP is not enabled */ - } else if (mux_state & USB_PD_MUX_DP_ENABLED) { - /* Set pin assignment C */ - if (mux_state & USB_PD_MUX_POLARITY_INVERTED) { - ctrl1 = (ANX74XX_REG_MUX_ML0_RX1 | - ANX74XX_REG_MUX_ML1_TX1 | - ANX74XX_REG_MUX_ML3_RX2); - ctrl5 |= ANX74XX_REG_MUX_ML2_TX2; - } else { - ctrl1 = (ANX74XX_REG_MUX_ML0_RX2 | - ANX74XX_REG_MUX_ML1_TX2 | - ANX74XX_REG_MUX_ML3_RX1); - ctrl5 |= ANX74XX_REG_MUX_ML2_TX1; - } - } else if (!mux_state) { - return anx74xx_tcpm_mux_exit(port); - } else { - return EC_ERROR_UNIMPLEMENTED; - } - - /* - * Safe mode must be entererd prior to any changes to the mux related to - * ALT_DP mode. Therefore, first enable safe mode prior to updating the - * values for analog_ctrl_1, analog_ctrl_5, and analog_ctrl_2. - */ - if (anx74xx_tcpm_mux_enter_safe_mode(port)) - return EC_ERROR_UNKNOWN; - - /* Write updated pin assignment */ - rv = mux_write(me, ANX74XX_REG_ANALOG_CTRL_1, ctrl1); - /* Write Rswitch config bits */ - rv |= mux_write(me, ANX74XX_REG_ANALOG_CTRL_5, ctrl5); - if (rv) - return EC_ERROR_UNKNOWN; - - /* Configure DP aux to sbu settings */ - if (anx74xx_mux_aux_to_sbu(port, - mux_state & USB_PD_MUX_POLARITY_INVERTED, - mux_state & USB_PD_MUX_DP_ENABLED)) - return EC_ERROR_UNKNOWN; - - /* Exit safe mode */ - if (anx74xx_tcpm_mux_exit_safe_mode(port)) - return EC_ERROR_UNKNOWN; - - anx[port].mux_state = mux_state; - - return EC_SUCCESS; -} - -/* current mux state */ -static int anx74xx_tcpm_mux_get(const struct usb_mux *me, - mux_state_t *mux_state) -{ - *mux_state = anx[me->usb_port].mux_state; - - return EC_SUCCESS; -} - -const struct usb_mux_driver anx74xx_tcpm_usb_mux_driver = { - .init = &anx74xx_tcpm_mux_init, - .set = &anx74xx_tcpm_mux_set, - .get = &anx74xx_tcpm_mux_get, -}; -#endif /* CONFIG_USB_PD_TCPM_MUX */ - -static int anx74xx_init_analog(int port) -{ - int reg, rv = EC_SUCCESS; - - /* Analog settings for chip */ - rv |= tcpc_write(port, ANX74XX_REG_HPD_CONTROL, - ANX74XX_REG_HPD_OP_MODE); - rv |= tcpc_write(port, ANX74XX_REG_HPD_CTRL_0, - ANX74XX_REG_HPD_DEFAULT); - if (rv) - return rv; - rv = tcpc_read(port, ANX74XX_REG_GPIO_CTRL_4_5, ®); - if (rv) - return rv; - reg &= ANX74XX_REG_VBUS_GPIO_MODE; - reg |= ANX74XX_REG_VBUS_OP_ENABLE; - rv = tcpc_write(port, ANX74XX_REG_GPIO_CTRL_4_5, reg); - if (rv) - return rv; - rv = tcpc_read(port, ANX74XX_REG_CC_SOFTWARE_CTRL, ®); - if (rv) - return rv; - reg |= ANX74XX_REG_TX_MODE_ENABLE; - rv = tcpc_write(port, ANX74XX_REG_CC_SOFTWARE_CTRL, reg); - - return rv; -} - -static int anx74xx_send_message(int port, uint16_t header, - const uint32_t *payload, - int type, - uint8_t len) -{ - int reg, rv = EC_SUCCESS; - uint8_t *buf = NULL; - int num_retry = 0, i = 0; - /* If sending Soft_reset, clear received message */ - /* Soft Reset Message type = 1101 and Number of Data Object = 0 */ - if ((header & 0x700f) == 0x000d) { - /* - * When sending soft reset, - * the Rx buffer of ANX3429 shall be clear - */ - rv = tcpc_read(port, ANX74XX_REG_CTRL_FW, ®); - rv |= tcpc_write( - port, ANX74XX_REG_CTRL_FW, reg | CLEAR_RX_BUFFER); - if (rv) - return EC_ERROR_UNKNOWN; - tcpc_write(port, ANX74XX_REG_RECVD_MSG_INT, 0xFF); - } - /* Inform chip about message length and TX type - * type->bit-0..2, len->bit-3..7 - */ - reg = (len << 3) & 0xf8; - reg |= type & 0x07; - rv |= tcpc_write(port, ANX74XX_REG_TX_CTRL_2, reg); - if (rv) - return EC_ERROR_UNKNOWN; - - /* Enqueue Header */ - rv = tcpc_write(port, ANX74XX_REG_TX_HEADER_L, (header & 0xff)); - if (rv) - return EC_ERROR_UNKNOWN; - rv = tcpc_write(port, ANX74XX_REG_TX_HEADER_H, (header >> 8)); - if (rv) - return EC_ERROR_UNKNOWN; - /* Enqueue payload */ - if (len > 2) { - len -= 2; - buf = (uint8_t *)payload; - while (1) { - if (i < 18) - rv = tcpc_write(port, - ANX74XX_REG_TX_START_ADDR_0 + i, - *buf); - else - rv = tcpc_write(port, - ANX74XX_REG_TX_START_ADDR_1 + i - 18, - *buf); - if (rv) { - num_retry++; - } else { - buf++; - len--; - num_retry = 0; - i++; - } - if (len == 0 || num_retry >= 3) - break; - } - /* If enqueue failed, do not request anx to transmit - * messages, FIFO will get cleared in next call - * before enqueue. - * num_retry = 0, refer to success - */ - if (num_retry) - return EC_ERROR_UNKNOWN; - } - /* Request a data transmission - * This bit will be cleared by ANX after TX success - */ - rv = tcpc_read(port, ANX74XX_REG_CTRL_COMMAND, ®); - if (rv) - return EC_ERROR_UNKNOWN; - reg |= ANX74XX_REG_TX_SEND_DATA_REQ; - rv |= tcpc_write(port, ANX74XX_REG_CTRL_COMMAND, reg); - - return rv; -} - -static int anx74xx_read_pd_obj(int port, - uint8_t *buf, - int plen) -{ - int rv = EC_SUCCESS, i; - int reg, addr = ANX74XX_REG_PD_RX_DATA_OBJ; - - /* Read PD data objects from ANX */ - for (i = 0; i < plen ; i++) { - /* Register sequence changes for last two bytes, if - * plen is greater than 26 - */ - if (i == 26) - addr = ANX74XX_REG_PD_RX_DATA_OBJ_M; - rv = tcpc_read(port, addr + i, ®); - if (rv) - break; - buf[i] = reg; - } - clear_recvd_msg_int(port); - return rv; -} - -static int anx74xx_check_cc_type(int cc_reg) -{ - int cc; - - switch (cc_reg & ANX74XX_REG_CC_STATUS_MASK) { - case BIT_VALUE_OF_SRC_CC_RD: - cc = TYPEC_CC_VOLT_RD; - break; - - case BIT_VALUE_OF_SRC_CC_RA: - cc = TYPEC_CC_VOLT_RA; - break; - - case BIT_VALUE_OF_SNK_CC_DEFAULT: - cc = TYPEC_CC_VOLT_RP_DEF; - break; - - case BIT_VALUE_OF_SNK_CC_1_P_5: - cc = TYPEC_CC_VOLT_RP_1_5; - break; - - case BIT_VALUE_OF_SNK_CC_3_P_0: - cc = TYPEC_CC_VOLT_RP_3_0; - break; - - default: - /* If no bits are set, then nothing is attached */ - cc = TYPEC_CC_VOLT_OPEN; - } - - return cc; -} - -static int anx74xx_tcpm_get_cc(int port, enum tcpc_cc_voltage_status *cc1, - enum tcpc_cc_voltage_status *cc2) -{ - int rv = EC_SUCCESS; - int reg = 0; - - /* Read tcpc cc status register */ - rv |= tcpc_read(port, ANX74XX_REG_CC_STATUS, ®); - /* Check for cc1 type */ - *cc1 = anx74xx_check_cc_type(reg); - /* - * Check for cc2 type (note cc2 bits are upper 4 of cc status - * register. - */ - *cc2 = anx74xx_check_cc_type(reg >> 4); - - /* clear HPD status*/ - if (!(*cc1) && !(*cc2)) { - anx74xx_tcpc_clear_hpd_status(port); -#ifdef CONFIG_USB_PD_TCPM_MUX - anx74xx_tcpm_mux_exit(port); -#endif - } - - return EC_SUCCESS; -} - -static int anx74xx_rp_control(int port, int rp) -{ - int reg; - int rv; - - rv = tcpc_read(port, ANX74XX_REG_ANALOG_CTRL_6, ®); - if (rv) - return EC_ERROR_UNKNOWN; - - /* clear Bit[0,1] R_RP to default Rp's value */ - reg &= ~0x03; - - switch (rp) { - case TYPEC_RP_1A5: - /* Set Rp strength to 12K for presenting 1.5A */ - reg |= ANX74XX_REG_CC_PULL_RP_12K; - break; - case TYPEC_RP_3A0: - /* Set Rp strength to 4K for presenting 3A */ - reg |= ANX74XX_REG_CC_PULL_RP_4K; - break; - case TYPEC_RP_USB: - default: - /* default: Set Rp strength to 36K */ - break; - } - - return tcpc_write(port, ANX74XX_REG_ANALOG_CTRL_6, reg); -} - -static int anx74xx_tcpm_select_rp_value(int port, int rp) -{ - /* Keep track of current RP value */ - tcpci_set_cached_rp(port, rp); - - /* For ANX3429 cannot get cc correctly when Rp != USB_Default */ - return EC_SUCCESS; -} - - -static int anx74xx_cc_software_ctrl(int port, int enable) -{ - int rv; - int reg; - - rv = tcpc_read(port, ANX74XX_REG_CC_SOFTWARE_CTRL, ®); - if (rv) - return EC_ERROR_UNKNOWN; - - if (enable) - reg |= ANX74XX_REG_CC_SW_CTRL_ENABLE; - else - reg &= ~ANX74XX_REG_CC_SW_CTRL_ENABLE; - - rv |= tcpc_write(port, ANX74XX_REG_CC_SOFTWARE_CTRL, reg); - return rv; -} - -static int anx74xx_tcpm_set_cc(int port, int pull) -{ - int rv = EC_SUCCESS; - int reg; - - /* Enable CC software Control */ - rv = anx74xx_cc_software_ctrl(port, 1); - if (rv) - return EC_ERROR_UNKNOWN; - - switch (pull) { - case TYPEC_CC_RP: - /* Enable Rp */ - rv |= tcpc_read(port, ANX74XX_REG_ANALOG_STATUS, ®); - if (rv) - return EC_ERROR_UNKNOWN; - reg |= ANX74XX_REG_CC_PULL_RP; - rv |= tcpc_write(port, ANX74XX_REG_ANALOG_STATUS, reg); - break; - case TYPEC_CC_RD: - /* Enable Rd */ - rv |= tcpc_read(port, ANX74XX_REG_ANALOG_STATUS, ®); - if (rv) - return EC_ERROR_UNKNOWN; - reg &= ANX74XX_REG_CC_PULL_RD; - rv |= tcpc_write(port, ANX74XX_REG_ANALOG_STATUS, reg); - break; - default: - rv = EC_ERROR_UNKNOWN; - break; - } - - return rv; -} - -static int anx74xx_tcpm_set_polarity(int port, enum tcpc_cc_polarity polarity) -{ - int reg, mux_state, rv = EC_SUCCESS; - const struct usb_mux *me = &usb_muxes[port]; - bool unused; - - rv |= tcpc_read(port, ANX74XX_REG_CC_SOFTWARE_CTRL, ®); - if (polarity_rm_dts(polarity)) /* Inform ANX to use CC2 */ - reg &= ~ANX74XX_REG_SELECT_CC1; - else /* Inform ANX to use CC1 */ - reg |= ANX74XX_REG_SELECT_CC1; - rv |= tcpc_write(port, ANX74XX_REG_CC_SOFTWARE_CTRL, reg); - - anx[port].polarity = polarity; - - /* Update mux polarity */ -#ifdef CONFIG_USB_PD_TCPM_MUX - mux_state = anx[port].mux_state & ~USB_PD_MUX_POLARITY_INVERTED; - if (polarity_rm_dts(polarity)) - mux_state |= USB_PD_MUX_POLARITY_INVERTED; - anx74xx_tcpm_mux_set(me, mux_state, &unused); -#endif - return rv; -} - -static int anx74xx_tcpm_set_vconn(int port, int enable) -{ - int reg, rv = EC_SUCCESS; - - /* switch VCONN to Non CC line */ - rv |= tcpc_read(port, ANX74XX_REG_INTP_VCONN_CTRL, ®); - if (rv) - return EC_ERROR_UNKNOWN; - if (enable) { - if (anx[port].polarity) - reg |= ANX74XX_REG_VCONN_1_ENABLE; - else - reg |= ANX74XX_REG_VCONN_2_ENABLE; - } else { - reg &= ANX74XX_REG_VCONN_DISABLE; - } - rv |= tcpc_write(port, ANX74XX_REG_INTP_VCONN_CTRL, reg); - anx[port].vconn_en = enable; - -#ifdef CONFIG_USB_PD_DECODE_SOP - rv |= tcpc_read(port, ANX74XX_REG_TX_AUTO_GOODCRC_2, ®); - if (rv) - return EC_ERROR_UNKNOWN; - - if (reg & ANX74XX_REG_REPLY_SOP_EN) { - if (enable) { - reg |= ANX74XX_REG_REPLY_SOP_1_EN | - ANX74XX_REG_REPLY_SOP_2_EN; - } else { - reg &= ~(ANX74XX_REG_REPLY_SOP_1_EN | - ANX74XX_REG_REPLY_SOP_2_EN); - } - - tcpc_write(port, ANX74XX_REG_TX_AUTO_GOODCRC_2, reg); - } -#endif - return rv; -} - -static int anx74xx_tcpm_set_msg_header(int port, int power_role, int data_role) -{ - return tcpc_write(port, ANX74XX_REG_TX_AUTO_GOODCRC_1, - ANX74XX_REG_AUTO_GOODCRC_SET(!!data_role, !!power_role)); -} - -static int anx74xx_tcpm_set_rx_enable(int port, int enable) -{ - int reg, rv; - - rv = tcpc_read(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG_MASK, ®); - if (rv) - return rv; - if (enable) { - reg &= ~(ANX74XX_REG_IRQ_CC_MSG_INT); - anx74xx_tcpm_set_auto_good_crc(port, 1); - anx74xx_rp_control(port, tcpci_get_cached_rp(port)); - } else { - /* Disable RX message by masking interrupt */ - reg |= (ANX74XX_REG_IRQ_CC_MSG_INT); - anx74xx_tcpm_set_auto_good_crc(port, 0); - anx74xx_rp_control(port, TYPEC_RP_USB); - } - /*When this function was call, the interrupt status shall be cleared*/ - tcpc_write(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG, 0); - - return tcpc_write(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG_MASK, reg); -} - -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC -static bool anx74xx_tcpm_check_vbus_level(int port, enum vbus_level level) -{ - int reg = 0; - - tcpc_read(port, ANX74XX_REG_ANALOG_STATUS, ®); - if (level == VBUS_PRESENT) - return ((reg & ANX74XX_REG_VBUS_STATUS) ? 1 : 0); - else - return ((reg & ANX74XX_REG_VBUS_STATUS) ? 0 : 1); -} -#endif - -static int anx74xx_tcpm_get_message_raw(int port, uint32_t *payload, int *head) -{ - int reg; - int len; - - /* Fetch the header */ - if (tcpc_read16(port, ANX74XX_REG_PD_HEADER, ®)) { - clear_recvd_msg_int(port); - return EC_ERROR_UNKNOWN; - } - *head = reg; -#ifdef CONFIG_USB_PD_DECODE_SOP - *head |= PD_HEADER_SOP(msg_sop[port]); -#endif - - len = PD_HEADER_CNT(*head) * 4; - if (!len) { - clear_recvd_msg_int(port); - return EC_SUCCESS; - } - - /* Receive message : assuming payload have enough - * memory allocated - */ - return anx74xx_read_pd_obj(port, (uint8_t *)payload, len); -} - -static int anx74xx_tcpm_transmit(int port, enum tcpci_msg_type type, - uint16_t header, - const uint32_t *data) -{ - uint8_t len = 0; - int ret = 0, reg = 0; - - switch (type) { - /* ANX is aware of type */ - case TCPCI_MSG_SOP: - case TCPCI_MSG_SOP_PRIME: - case TCPCI_MSG_SOP_PRIME_PRIME: - len = PD_HEADER_CNT(header) * 4 + 2; - ret = anx74xx_send_message(port, header, - data, type, len); - break; - case TCPCI_MSG_TX_HARD_RESET: - /* Request HARD RESET */ - tcpc_read(port, ANX74XX_REG_TX_CTRL_1, ®); - reg |= ANX74XX_REG_TX_HARD_RESET_REQ; - ret = tcpc_write(port, ANX74XX_REG_TX_CTRL_1, reg); - /*After Hard Reset, TCPM shall disable goodCRC*/ - anx74xx_tcpm_set_auto_good_crc(port, 0); - break; - case TCPCI_MSG_CABLE_RESET: - /* Request CABLE RESET */ - tcpc_read(port, ANX74XX_REG_TX_CTRL_1, ®); - reg |= ANX74XX_REG_TX_CABLE_RESET_REQ; - ret = tcpc_write(port, ANX74XX_REG_TX_CTRL_1, reg); - break; - case TCPCI_MSG_TX_BIST_MODE_2: - /* Request BIST MODE 2 */ - reg = ANX74XX_REG_TX_BIST_START - | ANX74XX_REG_TX_BIXT_FOREVER | (0x02 << 4); - ret = tcpc_write(port, ANX74XX_REG_TX_BIST_CTRL, reg); - msleep(1); - ret = tcpc_write(port, ANX74XX_REG_TX_BIST_CTRL, - reg | ANX74XX_REG_TX_BIST_ENABLE); - msleep(30); - tcpc_read(port, ANX74XX_REG_TX_BIST_CTRL, ®); - ret = tcpc_write(port, ANX74XX_REG_TX_BIST_CTRL, - reg | ANX74XX_REG_TX_BIST_STOP); - ret = tcpc_write(port, ANX74XX_REG_TX_BIST_CTRL, - reg & (~ANX74XX_REG_TX_BIST_STOP)); - ret = tcpc_write(port, ANX74XX_REG_TX_BIST_CTRL, 0); - break; - default: - return EC_ERROR_UNIMPLEMENTED; - } - - return ret; -} - -/* - * Don't let the TCPC try to pull from the RX buffer forever. We typical only - * have 1 or 2 messages waiting. - */ -#define MAX_ALLOW_FAILED_RX_READS 10 - -void anx74xx_tcpc_alert(int port) -{ - int reg; - int failed_attempts; - - /* Clear soft irq bit */ - tcpc_write(port, ANX74XX_REG_IRQ_EXT_SOURCE_3, - ANX74XX_REG_CLEAR_SOFT_IRQ); - - /* Read main alert register for pending alerts */ - reg = 0; - tcpc_read(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG, ®); - - /* Prioritize TX completion because PD state machine is waiting */ - if (reg & ANX74XX_REG_IRQ_GOOD_CRC_INT) - pd_transmit_complete(port, TCPC_TX_COMPLETE_SUCCESS); - - if (reg & ANX74XX_REG_IRQ_TX_FAIL_INT) - pd_transmit_complete(port, TCPC_TX_COMPLETE_FAILED); - - /* Pull all RX messages from TCPC into EC memory */ - failed_attempts = 0; - while (reg & ANX74XX_REG_IRQ_CC_MSG_INT) { - if (tcpm_enqueue_message(port)) - ++failed_attempts; - if (tcpc_read(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG, ®)) - ++failed_attempts; - - /* Ensure we don't loop endlessly */ - if (failed_attempts >= MAX_ALLOW_FAILED_RX_READS) { - CPRINTF("C%d Cannot consume RX buffer after %d failed " - "attempts!", port, failed_attempts); - /* - * The port is in a bad state, we don't want to consume - * all EC resources so suspend the port for a little - * while. - */ - pd_set_suspend(port, 1); - pd_deferred_resume(port); - return; - } - } - - /* Clear all pending alerts */ - tcpc_write(port, ANX74XX_REG_RECVD_MSG_INT, reg); - - if (reg & ANX74XX_REG_IRQ_CC_STATUS_INT) - /* CC status changed, wake task */ - task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_CC); - - /* Read and clear extended alert register 1 */ - reg = 0; - tcpc_read(port, ANX74XX_REG_IRQ_EXT_SOURCE_1, ®); - tcpc_write(port, ANX74XX_REG_IRQ_EXT_SOURCE_1, reg); - -#ifdef CONFIG_USB_PD_DECODE_SOP - if (reg & ANX74XX_REG_EXT_SOP) - msg_sop[port] = TCPCI_MSG_SOP; - else if (reg & ANX74XX_REG_EXT_SOP_PRIME) - msg_sop[port] = TCPCI_MSG_SOP_PRIME; -#endif - - /* Check for Hard Reset done bit */ - if (reg & ANX74XX_REG_ALERT_TX_HARD_RESETOK) - /* ANX hardware clears the request bit */ - pd_transmit_complete(port, TCPC_TX_COMPLETE_SUCCESS); - - /* Read and clear TCPC extended alert register 2 */ - reg = 0; - tcpc_read(port, ANX74XX_REG_IRQ_EXT_SOURCE_2, ®); - tcpc_write(port, ANX74XX_REG_IRQ_EXT_SOURCE_2, reg); - -#ifdef CONFIG_USB_PD_DECODE_SOP - if (reg & ANX74XX_REG_EXT_SOP_PRIME_PRIME) - msg_sop[port] = TCPCI_MSG_SOP_PRIME_PRIME; -#endif - - if (reg & ANX74XX_REG_EXT_HARD_RST) { - /* hard reset received */ - task_set_event(PD_PORT_TO_TASK_ID(port), - PD_EVENT_RX_HARD_RESET); - } -} - -static int anx74xx_tcpm_init(int port) -{ - int rv = 0, reg; - - memset(&anx[port], 0, sizeof(struct anx_state)); - /* Bring chip in normal mode to work */ - anx74xx_set_power_mode(port, ANX74XX_NORMAL_MODE); - - /* Initialize analog section of ANX */ - rv |= anx74xx_init_analog(port); - - /* disable all interrupts */ - rv |= tcpc_write(port, ANX74XX_REG_IRQ_EXT_MASK_1, - ANX74XX_REG_CLEAR_SET_BITS); - - /* Initialize interrupt open-drain */ - rv |= tcpc_read(port, ANX74XX_REG_INTP_VCONN_CTRL, ®); - if (tcpc_config[port].flags & TCPC_FLAGS_ALERT_OD) - reg |= ANX74XX_REG_R_INTERRUPT_OPEN_DRAIN; - else - reg &= ~ANX74XX_REG_R_INTERRUPT_OPEN_DRAIN; - rv |= tcpc_write(port, ANX74XX_REG_INTP_VCONN_CTRL, reg); - - /* Initialize interrupt polarity */ - reg = tcpc_config[port].flags & TCPC_FLAGS_ALERT_ACTIVE_HIGH ? - ANX74XX_REG_IRQ_POL_HIGH : ANX74XX_REG_IRQ_POL_LOW; - rv |= tcpc_write(port, ANX74XX_REG_IRQ_STATUS, reg); - - /* unmask interrupts */ - rv |= tcpc_read(port, ANX74XX_REG_IRQ_EXT_MASK_1, ®); - reg &= (~ANX74XX_REG_ALERT_TX_MSG_ERROR); - reg &= (~ANX74XX_REG_ALERT_TX_CABLE_RESETOK); - reg &= (~ANX74XX_REG_ALERT_TX_HARD_RESETOK); - rv |= tcpc_write(port, ANX74XX_REG_IRQ_EXT_MASK_1, reg); - - rv |= tcpc_read(port, ANX74XX_REG_IRQ_EXT_MASK_2, ®); - reg &= (~ANX74XX_REG_EXT_HARD_RST); - rv |= tcpc_write(port, ANX74XX_REG_IRQ_EXT_MASK_2, reg); - - /* HPD pin output enable*/ - rv |= tcpc_write(port, ANX74XX_REG_HPD_CTRL_0, ANX74XX_REG_HPD_DEFAULT); - - if (rv) - return EC_ERROR_UNKNOWN; - - /* Set AVDD10_BMC to 1.08 */ - rv |= tcpc_read(port, ANX74XX_REG_ANALOG_CTRL_5, ®); - if (rv) - return EC_ERROR_UNKNOWN; - rv = tcpc_write(port, ANX74XX_REG_ANALOG_CTRL_5, (reg & 0xf3)); - if (rv) - return EC_ERROR_UNKNOWN; - - /* Decrease BMC TX lowest swing voltage */ - rv |= tcpc_read(port, ANX74XX_REG_ANALOG_CTRL_11, ®); - if (rv) - return EC_ERROR_UNKNOWN; - rv = tcpc_write(port, ANX74XX_REG_ANALOG_CTRL_11, (reg & 0x3f) | 0x40); - if (rv) - return EC_ERROR_UNKNOWN; - - /* Set BMC TX cap slew rate to 400ns */ - rv = tcpc_write(port, ANX74XX_REG_ANALOG_CTRL_12, 0x4); - if (rv) - return EC_ERROR_UNKNOWN; - - tcpm_get_chip_info(port, 1, NULL); - - return EC_SUCCESS; -} - -static int anx74xx_get_chip_info(int port, int live, - struct ec_response_pd_chip_info_v1 *chip_info) -{ - int rv = tcpci_get_chip_info(port, live, chip_info); - int val; - - if (rv) - return rv; - - if (chip_info->fw_version_number == 0 || - chip_info->fw_version_number == -1 || live) { - rv = tcpc_read(port, ANX74XX_REG_FW_VERSION, &val); - - if (rv) - return rv; - - chip_info->fw_version_number = val; - } - -#ifdef CONFIG_USB_PD_TCPM_ANX3429 - /* - * Min firmware version of ANX3429 to ensure that false SOP' detection - * doesn't occur for e-marked cables. See b/116255749#comment8 and - * b/64752060#comment11 - */ - chip_info->min_req_fw_version_number = 0x16; -#endif - - return rv; -} - -/* - * Dissociate from the TCPC. - */ - -static int anx74xx_tcpm_release(int port) -{ - return EC_SUCCESS; -} - -const struct tcpm_drv anx74xx_tcpm_drv = { - .init = &anx74xx_tcpm_init, - .release = &anx74xx_tcpm_release, - .get_cc = &anx74xx_tcpm_get_cc, -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - .check_vbus_level = &anx74xx_tcpm_check_vbus_level, -#endif - .select_rp_value = &anx74xx_tcpm_select_rp_value, - .set_cc = &anx74xx_tcpm_set_cc, - .set_polarity = &anx74xx_tcpm_set_polarity, -#ifdef CONFIG_USB_PD_DECODE_SOP - .sop_prime_enable = &tcpci_tcpm_sop_prime_enable, -#endif - .set_vconn = &anx74xx_tcpm_set_vconn, - .set_msg_header = &anx74xx_tcpm_set_msg_header, - .set_rx_enable = &anx74xx_tcpm_set_rx_enable, - .get_message_raw = &anx74xx_tcpm_get_message_raw, - .transmit = &anx74xx_tcpm_transmit, - .tcpc_alert = &anx74xx_tcpc_alert, -#ifdef CONFIG_USB_PD_DISCHARGE_TCPC - .tcpc_discharge_vbus = &anx74xx_tcpc_discharge_vbus, -#endif - .get_chip_info = &anx74xx_get_chip_info, -#if defined(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE) && \ - defined(CONFIG_USB_PD_TCPC_LOW_POWER) - .drp_toggle = &anx74xx_tcpc_drp_toggle, - .enter_low_power_mode = &anx74xx_enter_low_power_mode, -#endif - .set_bist_test_mode = &tcpci_set_bist_test_mode, -}; - -#ifdef CONFIG_CMD_I2C_STRESS_TEST_TCPC -struct i2c_stress_test_dev anx74xx_i2c_stress_test_dev = { - .reg_info = { - .read_reg = ANX74XX_REG_VENDOR_ID_L, - .read_val = ANX74XX_VENDOR_ID & 0xFF, - .write_reg = ANX74XX_REG_CC_SOFTWARE_CTRL, - }, - .i2c_read = &tcpc_i2c_read, - .i2c_write = &tcpc_i2c_write, -}; -#endif /* CONFIG_CMD_I2C_STRESS_TEST_TCPC */ diff --git a/driver/tcpm/anx74xx.h b/driver/tcpm/anx74xx.h deleted file mode 100644 index 8d700d4d86..0000000000 --- a/driver/tcpm/anx74xx.h +++ /dev/null @@ -1,229 +0,0 @@ -/* Copyright 2016 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. - * - * Author : Analogix Semiconductor. - */ - -#include "usb_mux.h" - -/* USB Power delivery port management */ - -#ifndef __CROS_EC_USB_PD_TCPM_ANX74XX_H -#define __CROS_EC_USB_PD_TCPM_ANX74XX_H - -/* I2C interface */ -#define ANX74XX_I2C_ADDR1_FLAGS 0x28 -#define ANX74XX_I2C_ADDR2_FLAGS 0x39 -#define ANX74XX_I2C_ADDR3_FLAGS 0x3E -#define ANX74XX_I2C_ADDR4_FLAGS 0x40 - -#define ANX74XX_REG_IRQ_POL_LOW 0x00 -#define ANX74XX_REG_IRQ_POL_HIGH 0x02 - -#define ANX74XX_REG_VENDOR_ID_L 0x00 -#define ANX74XX_REG_VENDOR_ID_H 0x01 -#define ANX74XX_VENDOR_ID 0xAAAA - -/* ANX F/W version:0x50:0x44 which contains otp firmware version */ -#define ANX74XX_REG_FW_VERSION 0x44 - -#define ANX74XX_REG_IRQ_STATUS 0x53 - -#define ANX74XX_REG_INTP_VCONN_CTRL 0x33 -#define ANX74XX_REG_VCONN_DISABLE 0x0f -#define ANX74XX_REG_VCONN_1_ENABLE BIT(4) -#define ANX74XX_REG_VCONN_2_ENABLE BIT(5) -#define ANX74XX_REG_R_INTERRUPT_OPEN_DRAIN BIT(2) - -#define ANX74XX_STANDBY_MODE (0) -#define ANX74XX_NORMAL_MODE (1) - -#define ANX74XX_REG_TX_CTRL_1 0x81 -#define ANX74XX_REG_TX_HARD_RESET_REQ BIT(1) -#define ANX74XX_REG_TX_CABLE_RESET_REQ BIT(2) - -#define ANX74XX_REG_TX_CTRL_2 0x82 -#define ANX74XX_REG_TX_WR_FIFO 0x83 -#define ANX74XX_REG_TX_FIFO_CTRL 0x9a -#define ANX74XX_REG_TX_HEADER_L 0x2c -#define ANX74XX_REG_TX_HEADER_H 0x2d -#define ANX74XX_REG_TX_START_ADDR_0 0x6d -#define ANX74XX_REG_TX_START_ADDR_1 0xd0 - -#define ANX74XX_REG_CTRL_COMMAND 0xdb -#define ANX74XX_REG_TX_SEND_DATA_REQ BIT(0) -#define ANX74XX_REG_TX_HARD_RST_REQ BIT(1) - -#define ANX74XX_REG_TX_BIST_CTRL 0x9D -#define ANX74XX_REG_TX_BIST_MODE BIT(4) -#define ANX74XX_REG_TX_BIST_STOP BIT(3) -#define ANX74XX_REG_TX_BIXT_FOREVER BIT(2) -#define ANX74XX_REG_TX_BIST_ENABLE BIT(1) -#define ANX74XX_REG_TX_BIST_START BIT(0) - -#define ANX74XX_REG_PD_HEADER 0x69 -#define ANX74XX_REG_PD_RX_DATA_OBJ 0x11 -#define ANX74XX_REG_PD_RX_DATA_OBJ_M 0x4d - -#define ANX74XX_REG_ANALOG_STATUS 0x40 -#define ANX74XX_REG_VBUS_STATUS BIT(4) -#define ANX74XX_REG_CC_PULL_RD 0xfd -#define ANX74XX_REG_CC_PULL_RP 0x02 - - -#define ANX74XX_REG_TX_AUTO_GOODCRC_2 0x94 -#define ANX74XX_REG_REPLY_SOP_EN BIT(3) -#define ANX74XX_REG_REPLY_SOP_1_EN BIT(4) -#define ANX74XX_REG_REPLY_SOP_2_EN BIT(5) - -#define ANX74XX_REG_TX_AUTO_GOODCRC_1 0x9c -#define ANX74XX_REG_SPEC_REV_BIT_POS (3) -#define ANX74XX_REG_DATA_ROLE_BIT_POS (2) -#define ANX74XX_REG_PWR_ROLE_BIT_POS (1) -#define ANX74XX_REG_AUTO_GOODCRC_EN BIT(0) -#define ANX74XX_REG_AUTO_GOODCRC_SET(drole, prole) \ - ((PD_REV20 << ANX74XX_REG_SPEC_REV_BIT_POS) | \ - ((drole) << ANX74XX_REG_DATA_ROLE_BIT_POS) | \ - ((prole) << ANX74XX_REG_PWR_ROLE_BIT_POS) | \ - ANX74XX_REG_AUTO_GOODCRC_EN) - - -#define ANX74XX_REG_ANALOG_CTRL_0 0x41 -#define ANX74XX_REG_R_PIN_CABLE_DET BIT(7) - -#define ANX74XX_REG_ANALOG_CTRL_1 0x42 -#define ANX74XX_REG_ANALOG_CTRL_5 0x46 -#define ANX74XX_REG_ANALOG_CTRL_6 0x47 -#define ANX74XX_REG_CC_PULL_RP_36K 0x00 -#define ANX74XX_REG_CC_PULL_RP_12K 0x01 -#define ANX74XX_REG_CC_PULL_RP_4K 0x02 - -#define ANX74XX_REG_R_SWITCH_CC_CLR 0x0f -#define ANX74XX_REG_R_SWITCH_CC2_SET 0x10 -#define ANX74XX_REG_R_SWITCH_CC1_SET 0x20 -#define ANX74XX_REG_AUX_SWAP_SET_CC1 0x30 -#define ANX74XX_REG_AUX_SWAP_SET_CC2 0xc0 - -#define ANX74XX_REG_ANALOG_CTRL_11 0x4c -#define ANX74XX_REG_ANALOG_CTRL_12 0x4d - -#define ANX74XX_REG_MUX_ML0_RX2 BIT(0) -#define ANX74XX_REG_MUX_ML0_RX1 BIT(1) -#define ANX74XX_REG_MUX_ML3_RX2 BIT(2) -#define ANX74XX_REG_MUX_ML3_RX1 BIT(3) -#define ANX74XX_REG_MUX_SSRX_RX2 BIT(4) -#define ANX74XX_REG_MUX_SSRX_RX1 BIT(5) -#define ANX74XX_REG_MUX_ML1_TX2 BIT(6) -#define ANX74XX_REG_MUX_ML1_TX1 BIT(7) - -#define ANX74XX_REG_MUX_ML2_TX2 BIT(4) -#define ANX74XX_REG_MUX_ML2_TX1 BIT(5) -#define ANX74XX_REG_MUX_SSTX_TX2 BIT(6) -#define ANX74XX_REG_MUX_SSTX_TX1 BIT(7) - -#define ANX74XX_REG_CC_SOFTWARE_CTRL 0x4a -#define ANX74XX_REG_CC_SW_CTRL_ENABLE 0x01 -#define ANX74XX_REG_TX_MODE_ENABLE 0x04 - -#define ANX74XX_REG_SELECT_CC1 0x02 - -#define ANX74XX_REG_GPIO_CTRL_4_5 0x3f -#define ANX74XX_REG_VBUS_OP_ENABLE 0x04 -#define ANX74XX_REG_VBUS_GPIO_MODE 0xfe - -#define ANX74XX_REG_IRQ_EXT_MASK_1 0x3b -#define ANX74XX_REG_IRQ_EXT_MASK_2 0x3c -#define ANX74XX_REG_IRQ_EXT_SOURCE_1 0x3e -#define ANX74XX_REG_EXT_SOP BIT(6) -#define ANX74XX_REG_EXT_SOP_PRIME BIT(7) -#define ANX74XX_REG_IRQ_EXT_SOURCE_2 0x4e -#define ANX74XX_REG_EXT_SOP_PRIME_PRIME BIT(0) -#define ANX74XX_REG_EXT_HARD_RST BIT(2) -#define ANX74XX_REG_IRQ_EXT_SOURCE_3 0x4f -#define ANX74XX_REG_CLEAR_SOFT_IRQ BIT(2) - -#define ANX74XX_REG_IRQ_SOURCE_RECV_MSG 0x6b -#define ANX74XX_REG_IRQ_CC_MSG_INT BIT(0) -#define ANX74XX_REG_IRQ_CC_STATUS_INT BIT(1) -#define ANX74XX_REG_IRQ_GOOD_CRC_INT BIT(2) -#define ANX74XX_REG_IRQ_TX_FAIL_INT BIT(3) -#define ANX74XX_REG_IRQ_SOURCE_RECV_MSG_MASK 0x6c - -#define ANX74XX_REG_CLEAR_SET_BITS 0xff -#define ANX74XX_REG_ALERT_HARD_RST_RECV BIT(6) -#define ANX74XX_REG_ALERT_MSG_RECV BIT(5) -#define ANX74XX_REG_ALERT_TX_MSG_ERROR BIT(4) -#define ANX74XX_REG_ALERT_TX_ACK_RECV BIT(3) -#define ANX74XX_REG_ALERT_TX_CABLE_RESETOK BIT(2) -#define ANX74XX_REG_ALERT_TX_HARD_RESETOK BIT(1) -#define ANX74XX_REG_ALERT_CC_CHANGE BIT(0) - -#define ANX74XX_REG_ANALOG_CTRL_2 0x43 -#define ANX74XX_REG_MODE_TRANS 0x01 - -#define ANX74XX_REG_SET_VBUS 0x20 - -#define ANX74XX_REG_ANALOG_CTRL_7 0x48 -#define ANX74XX_REG_STATUS_CC_RD 0x01 -#define ANX74XX_REG_STATUS_CC_RA 0x03 -#define ANX74XX_REG_STATUS_CC1(reg) ((reg & 0x0C) >> 2) -#define ANX74XX_REG_STATUS_CC2(reg) ((reg & 0x03) >> 0) - -#define ANX74XX_REG_HPD_CONTROL 0xfd - -#define ANX74XX_REG_HPD_CTRL_0 0x36 -#define ANX74XX_REG_DISCHARGE_CTRL 0x80 -#define ANX74XX_REG_HPD_OP_MODE 0x08 -#define ANX74XX_REG_HPD_DEFAULT 0x00 -#define ANX74XX_REG_HPD_OUT_DATA 0x10 - -#define ANX74XX_REG_RECVD_MSG_INT 0x98 -#define ANX74XX_REG_CC_STATUS 0x99 -#define ANX74XX_REG_CTRL_FW 0x2E -#define CLEAR_RX_BUFFER (1) -#define ANX74XX_REG_POWER_DOWN_CTRL 0x0d -#define ANX74XX_REG_STATUS_CC1_VRD_USB BIT(7) -#define ANX74XX_REG_STATUS_CC1_VRD_1P5 BIT(6) -#define ANX74XX_REG_STATUS_CC1_VRD_3P0 BIT(5) -#define ANX74XX_REG_STATUS_CC2_VRD_USB BIT(4) -#define ANX74XX_REG_STATUS_CC2_VRD_1P5 BIT(3) -#define ANX74XX_REG_STATUS_CC2_VRD_3P0 BIT(2) - -/* defined in the inter-bock Spec: 4.2.10 CC Detect Status */ -#define ANX74XX_REG_CC_STATUS_MASK 0xf -#define BIT_VALUE_OF_SRC_CC_RD 0x01 -#define BIT_VALUE_OF_SRC_CC_RA 0x02 -#define BIT_VALUE_OF_SNK_CC_DEFAULT 0x04 -#define BIT_VALUE_OF_SNK_CC_1_P_5 0x08 -#define BIT_VALUE_OF_SNK_CC_3_P_0 0x0C -#define ANX74XX_CC_RA_MASK (BIT_VALUE_OF_SRC_CC_RA | \ - (BIT_VALUE_OF_SRC_CC_RA << 4)) -#define ANX74XX_CC_RD_MASK (BIT_VALUE_OF_SRC_CC_RD | \ - (BIT_VALUE_OF_SRC_CC_RD << 4)) - -/* - * RESETN low to PWR_EN low delay - */ -#define ANX74XX_RST_L_PWR_L_DELAY_MS 1 -/* - * minimum power off-to-on delay to reset chip - */ -#define ANX74XX_PWR_L_PWR_H_DELAY_MS 10 -/* - * parameter T4: PWR_EN high to RESETN high delay - */ -#define ANX74XX_PWR_H_RST_H_DELAY_MS 10 - -extern const struct tcpm_drv anx74xx_tcpm_drv; -extern const struct usb_mux_driver anx74xx_tcpm_usb_mux_driver; -void anx74xx_tcpc_set_vbus(int port, int enable); -void anx74xx_tcpc_clear_hpd_status(int port); -void anx74xx_tcpc_update_hpd_status(const struct usb_mux *me, - mux_state_t mux_state); - -#ifdef CONFIG_CMD_I2C_STRESS_TEST_TCPC -extern struct i2c_stress_test_dev anx74xx_i2c_stress_test_dev; -#endif - -#endif /* __CROS_EC_USB_PD_TCPM_ANX74XX_H */ diff --git a/driver/tcpm/anx7688.c b/driver/tcpm/anx7688.c deleted file mode 100644 index 5e37352bc5..0000000000 --- a/driver/tcpm/anx7688.c +++ /dev/null @@ -1,225 +0,0 @@ -/* Copyright 2016 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. - */ - -/* ANX7688 port manager */ - -#include "hooks.h" -#include "tcpm/tcpci.h" -#include "tcpm/tcpm.h" -#include "timer.h" -#include "usb_mux.h" - -#if defined(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE) || \ - defined(CONFIG_USB_PD_TCPC_LOW_POWER) || \ - defined(CONFIG_USB_PD_DISCHARGE_TCPC) -#error "Unsupported config options of anx7688 PD driver" -#endif - -#define ANX7688_VENDOR_ALERT BIT(15) - -#define ANX7688_REG_STATUS 0x82 -#define ANX7688_REG_STATUS_LINK BIT(0) - -#define ANX7688_REG_HPD 0x83 -#define ANX7688_REG_HPD_HIGH BIT(0) -#define ANX7688_REG_HPD_IRQ BIT(1) -#define ANX7688_REG_HPD_ENABLE BIT(2) - -#define ANX7688_USBC_ADDR_FLAGS 0x28 -#define ANX7688_REG_RAMCTRL 0xe7 -#define ANX7688_REG_RAMCTRL_BOOT_DONE BIT(6) - -static int anx7688_init(int port) -{ - int rv = 0; - int mask = 0; - - /* - * 7688 POWER_STATUS[6] is not reliable for tcpci_tcpm_init() to poll - * due to it is default 0 in HW, and we cannot write TCPC until it is - * ready, or something goes wrong. (Issue 52772) - * Instead we poll TCPC 0x50:0xe7 bit6 here to make sure bootdone is - * ready(50ms). Then PD main flow can process cc debounce in 50ms ~ - * 100ms to follow cts. - */ - while (1) { - rv = i2c_read8(I2C_PORT_TCPC, ANX7688_USBC_ADDR_FLAGS, - ANX7688_REG_RAMCTRL, &mask); - - if (rv == EC_SUCCESS && (mask & ANX7688_REG_RAMCTRL_BOOT_DONE)) - break; - msleep(10); - } - - rv = tcpci_tcpm_drv.init(port); - if (rv) - return rv; - - rv = tcpc_read16(port, TCPC_REG_ALERT_MASK, &mask); - if (rv) - return rv; - - /* enable vendor specific alert */ - mask |= ANX7688_VENDOR_ALERT; - rv = tcpc_write16(port, TCPC_REG_ALERT_MASK, mask); - return rv; -} - -static int anx7688_release(int port) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -static void anx7688_update_hpd_enable(int port) -{ - int status, reg, rv; - - rv = tcpc_read(port, ANX7688_REG_STATUS, &status); - rv |= tcpc_read(port, ANX7688_REG_HPD, ®); - if (rv) - return; - - if (!(reg & ANX7688_REG_HPD_ENABLE) || - !(status & ANX7688_REG_STATUS_LINK)) { - reg &= ~ANX7688_REG_HPD_IRQ; - tcpc_write(port, ANX7688_REG_HPD, - (status & ANX7688_REG_STATUS_LINK) - ? reg | ANX7688_REG_HPD_ENABLE - : reg & ~ANX7688_REG_HPD_ENABLE); - } -} - -int anx7688_hpd_disable(int port) -{ - return tcpc_write(port, ANX7688_REG_HPD, 0); -} - -int anx7688_update_hpd(int port, int level, int irq) -{ - int reg, rv; - - rv = tcpc_read(port, ANX7688_REG_HPD, ®); - if (rv) - return rv; - - if (level) - reg |= ANX7688_REG_HPD_HIGH; - else - reg &= ~ANX7688_REG_HPD_HIGH; - - if (irq) - reg |= ANX7688_REG_HPD_IRQ; - else - reg &= ~ANX7688_REG_HPD_IRQ; - - return tcpc_write(port, ANX7688_REG_HPD, reg); -} - -int anx7688_enable_cable_detection(int port) -{ - return tcpc_write(port, TCPC_REG_COMMAND, 0xff); -} - -int anx7688_set_power_supply_ready(int port) -{ - return tcpc_write(port, TCPC_REG_COMMAND, 0x77); -} - -int anx7688_power_supply_reset(int port) -{ - return tcpc_write(port, TCPC_REG_COMMAND, 0x66); -} - -static void anx7688_tcpc_alert(int port) -{ - int alert, rv; - - rv = tcpc_read16(port, TCPC_REG_ALERT, &alert); - /* process and clear alert status */ - tcpci_tcpc_alert(port); - - if (!rv && (alert & ANX7688_VENDOR_ALERT)) - anx7688_update_hpd_enable(port); -} - -static int anx7688_mux_set(const struct usb_mux *me, mux_state_t mux_state, - bool *ack_required) -{ - int reg = 0; - int rv, polarity; - - /* This driver does not use host command ACKs */ - *ack_required = false; - - rv = mux_read(me, TCPC_REG_CONFIG_STD_OUTPUT, ®); - if (rv != EC_SUCCESS) - return rv; - - reg &= ~TCPC_REG_CONFIG_STD_OUTPUT_MUX_MASK; - if (mux_state & USB_PD_MUX_USB_ENABLED) - reg |= TCPC_REG_CONFIG_STD_OUTPUT_MUX_USB; - if (mux_state & USB_PD_MUX_DP_ENABLED) - reg |= TCPC_REG_CONFIG_STD_OUTPUT_MUX_DP; - - /* ANX7688 needs to set bit0 */ - rv = mux_read(me, TCPC_REG_TCPC_CTRL, &polarity); - if (rv != EC_SUCCESS) - return rv; - - /* copy the polarity from TCPC_CTRL[0], take care clear then set */ - reg &= ~TCPC_REG_TCPC_CTRL_POLARITY(1); - reg |= TCPC_REG_TCPC_CTRL_POLARITY(polarity); - return mux_write(me, TCPC_REG_CONFIG_STD_OUTPUT, reg); -} - -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC -static bool anx7688_tcpm_check_vbus_level(int port, enum vbus_level level) -{ - int reg = 0; - - /* On ANX7688, POWER_STATUS.VBusPresent (bit 2) is averaged 16 times, so - * its value may not be set to 1 quickly enough during power role swap. - * Therefore, we use a proprietary register to read the unfiltered VBus - * value. See crosbug.com/p/55221 . - */ - i2c_read8(I2C_PORT_TCPC, 0x28, 0x40, ®); - - if (level == VBUS_PRESENT) - return ((reg & 0x10) ? 1 : 0); - else - return ((reg & 0x10) ? 0 : 1); -} -#endif - -/* ANX7688 is a TCPCI compatible port controller */ -const struct tcpm_drv anx7688_tcpm_drv = { - .init = &anx7688_init, - .release = &anx7688_release, - .get_cc = &tcpci_tcpm_get_cc, -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - .check_vbus_level = &anx7688_tcpm_check_vbus_level, -#endif - .select_rp_value = &tcpci_tcpm_select_rp_value, - .set_cc = &tcpci_tcpm_set_cc, - .set_polarity = &tcpci_tcpm_set_polarity, -#ifdef CONFIG_USB_PD_DECODE_SOP - .sop_prime_enable = &tcpci_tcpm_sop_prime_enable, -#endif - .set_vconn = &tcpci_tcpm_set_vconn, - .set_msg_header = &tcpci_tcpm_set_msg_header, - .set_rx_enable = &tcpci_tcpm_set_rx_enable, - .get_message_raw = &tcpci_tcpm_get_message_raw, - .transmit = &tcpci_tcpm_transmit, - .tcpc_alert = &anx7688_tcpc_alert, - .set_bist_test_mode = &tcpci_set_bist_test_mode, -}; - -#ifdef CONFIG_USB_PD_TCPM_MUX -const struct usb_mux_driver anx7688_usb_mux_driver = { - .init = tcpci_tcpm_mux_init, - .set = anx7688_mux_set, - .get = tcpci_tcpm_mux_get, -}; -#endif /* CONFIG_USB_PD_TCPM_MUX */ diff --git a/driver/tcpm/anx7688.h b/driver/tcpm/anx7688.h deleted file mode 100644 index 534e4155b1..0000000000 --- a/driver/tcpm/anx7688.h +++ /dev/null @@ -1,21 +0,0 @@ -/* Copyright 2016 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. - */ - -/* USB Power delivery port management */ - -#ifndef __CROS_EC_USB_PD_TCPM_ANX7688_H -#define __CROS_EC_USB_PD_TCPM_ANX7688_H - -int anx7688_update_hpd(int port, int level, int irq); -int anx7688_set_dp_pin_mode(int port, int pin_mode); -int anx7688_enable_cable_detection(int port); -int anx7688_set_power_supply_ready(int port); -int anx7688_power_supply_reset(int port); -int anx7688_hpd_disable(int port); - -extern struct tcpm_drv anx7688_tcpm_drv; -extern struct usb_mux_driver anx7688_usb_mux_driver; - -#endif /* __CROS_EC_USB_PD_TCPM_ANX7688_H */ diff --git a/driver/tcpm/ccgxxf.h b/driver/tcpm/ccgxxf.h deleted file mode 100644 index f4b3deb355..0000000000 --- a/driver/tcpm/ccgxxf.h +++ /dev/null @@ -1,62 +0,0 @@ -/* Copyright 2021 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. - */ - -/* - * USB Power delivery port management For Cypress EZ-PD CCG6DF, CCG6SF - * CCGXXF FW is designed to adapt standard TCPM driver procedures. - */ -#ifndef __CROS_EC_DRIVER_TCPM_CCGXXF_H -#define __CROS_EC_DRIVER_TCPM_CCGXXF_H - -#define CCGXXF_I2C_ADDR1_FLAGS 0x0B -#define CCGXXF_I2C_ADDR2_FLAGS 0x1B - -/* CCGXXF built in I/O expander definitions */ -#ifdef CONFIG_IO_EXPANDER_CCGXXF - -/* CCGXXF I/O ports that can be referenced in gpio.inc */ -enum ccgxxf_io_ports { - CCGXXF_PORT_0, - CCGXXF_PORT_1, - CCGXXF_PORT_2, - CCGXXF_PORT_3 -}; - -/* CCGXXF I/O pins that can be referenced in gpio.inc */ -enum ccgxxf_io_pins { - CCGXXF_IO_0, - CCGXXF_IO_1, - CCGXXF_IO_2, - CCGXXF_IO_3, - CCGXXF_IO_4, - CCGXXF_IO_5, - CCGXXF_IO_6, - CCGXXF_IO_7 -}; - -#define CCGXXF_REG_GPIO_CONTROL(port) ((port) + 0x80) -#define CCGXXF_REG_GPIO_STATUS(port) ((port) + 0x84) - -#define CCGXXF_REG_GPIO_MODE 0x88 -#define CCGXXF_GPIO_PIN_MASK_SHIFT 8 -#define CCGXXF_GPIO_PIN_MODE_SHIFT 2 -#define CCGXXF_GPIO_1P8V_SEL BIT(7) - -enum ccgxxf_gpio_mode { - CCGXXF_GPIO_MODE_HIZ_ANALOG, - CCGXXF_GPIO_MODE_HIZ_DIGITAL, - CCGXXF_GPIO_MODE_RES_UP, - CCGXXF_GPIO_MODE_RES_DWN, - CCGXXF_GPIO_MODE_OD_LOW, - CCGXXF_GPIO_MODE_OD_HIGH, - CCGXXF_GPIO_MODE_STRONG, - CCGXXF_GPIO_MODE_RES_UPDOWN -}; - -extern const struct ioexpander_drv ccgxxf_ioexpander_drv; - -#endif /* CONFIG_IO_EXPANDER_CCGXXF */ - -#endif /* __CROS_EC_DRIVER_TCPM_CCGXXF_H */ diff --git a/driver/tcpm/fusb302.c b/driver/tcpm/fusb302.c deleted file mode 100644 index 0098906d32..0000000000 --- a/driver/tcpm/fusb302.c +++ /dev/null @@ -1,1205 +0,0 @@ -/* 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. - * - * Author: Gabe Noblesmith - */ - -/* Type-C port manager for Fairchild's FUSB302 */ - -#include "console.h" -#include "fusb302.h" -#include "task.h" -#include "hooks.h" -#include "tcpm/tcpci.h" -#include "tcpm/tcpm.h" -#include "timer.h" -#include "usb_charge.h" -#include "usb_pd.h" -#include "usb_pd_tcpc.h" -#include "usb_pd_tcpm.h" -#include "util.h" - -#if defined(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE) || \ - defined(CONFIG_USB_PD_DISCHARGE_TCPC) -#error "Unsupported config options of fusb302 PD driver" -#endif - -#define PACKET_IS_GOOD_CRC(head) (PD_HEADER_TYPE(head) == PD_CTRL_GOOD_CRC && \ - PD_HEADER_CNT(head) == 0) - -static struct fusb302_chip_state { - int cc_polarity; - int vconn_enabled; - /* 1 = pulling up (DFP) 0 = pulling down (UFP) */ - int pulling_up; - int rx_enable; - uint8_t mdac_vnc; - uint8_t mdac_rd; -} state[CONFIG_USB_PD_PORT_MAX_COUNT]; - -static struct mutex measure_lock; - -/* - * Bring the FUSB302 out of reset after Hard Reset signaling. This will - * automatically flush both the Rx and Tx FIFOs. - */ -static void fusb302_pd_reset(int port) -{ - tcpc_write(port, TCPC_REG_RESET, TCPC_REG_RESET_PD_RESET); -} - -/* - * Flush our Rx FIFO. To prevent packet framing issues, this function should - * only be called when Rx is disabled. - */ -static void fusb302_flush_rx_fifo(int port) -{ - /* - * other bits in the register _should_ be 0 - * until the day we support other SOP* types... - * then we'll have to keep a shadow of what this register - * value should be so we don't clobber it here! - */ - tcpc_write(port, TCPC_REG_CONTROL1, TCPC_REG_CONTROL1_RX_FLUSH); -} - -static void fusb302_flush_tx_fifo(int port) -{ - int reg; - - tcpc_read(port, TCPC_REG_CONTROL0, ®); - reg |= TCPC_REG_CONTROL0_TX_FLUSH; - tcpc_write(port, TCPC_REG_CONTROL0, reg); -} - -static void fusb302_auto_goodcrc_enable(int port, int enable) -{ - int reg; - - tcpc_read(port, TCPC_REG_SWITCHES1, ®); - - if (enable) - reg |= TCPC_REG_SWITCHES1_AUTO_GCRC; - else - reg &= ~TCPC_REG_SWITCHES1_AUTO_GCRC; - - tcpc_write(port, TCPC_REG_SWITCHES1, reg); -} - -/* Convert BC LVL values (in FUSB302) to Type-C CC Voltage Status */ -static int convert_bc_lvl(int port, int bc_lvl) -{ - /* assume OPEN unless one of the following conditions is true... */ - int ret = TYPEC_CC_VOLT_OPEN; - - if (state[port].pulling_up) { - if (bc_lvl == 0x00) - ret = TYPEC_CC_VOLT_RA; - else if (bc_lvl < 0x3) - ret = TYPEC_CC_VOLT_RD; - } else { - if (bc_lvl == 0x1) - ret = TYPEC_CC_VOLT_RP_DEF; - else if (bc_lvl == 0x2) - ret = TYPEC_CC_VOLT_RP_1_5; - else if (bc_lvl == 0x3) - ret = TYPEC_CC_VOLT_RP_3_0; - } - - return ret; -} - -static int measure_cc_pin_source(int port, int cc_measure) -{ - int switches0_reg; - int reg; - int cc_lvl; - - mutex_lock(&measure_lock); - - /* Read status register */ - tcpc_read(port, TCPC_REG_SWITCHES0, ®); - /* Save current value */ - switches0_reg = reg; - /* Clear pull-up register settings and measure bits */ - reg &= ~(TCPC_REG_SWITCHES0_MEAS_CC1 | TCPC_REG_SWITCHES0_MEAS_CC2); - /* Set desired pullup register bit */ - if (cc_measure == TCPC_REG_SWITCHES0_MEAS_CC1) - reg |= TCPC_REG_SWITCHES0_CC1_PU_EN; - else - reg |= TCPC_REG_SWITCHES0_CC2_PU_EN; - /* Set CC measure bit */ - reg |= cc_measure; - - /* Set measurement switch */ - tcpc_write(port, TCPC_REG_SWITCHES0, reg); - - /* Set MDAC for Open vs Rd/Ra comparison */ - tcpc_write(port, TCPC_REG_MEASURE, state[port].mdac_vnc); - - /* Wait on measurement */ - usleep(250); - - /* Read status register */ - tcpc_read(port, TCPC_REG_STATUS0, ®); - - /* Assume open */ - cc_lvl = TYPEC_CC_VOLT_OPEN; - - /* CC level is below the 'no connect' threshold (vOpen) */ - if ((reg & TCPC_REG_STATUS0_COMP) == 0) { - /* Set MDAC for Rd vs Ra comparison */ - tcpc_write(port, TCPC_REG_MEASURE, state[port].mdac_rd); - - /* Wait on measurement */ - usleep(250); - - /* Read status register */ - tcpc_read(port, TCPC_REG_STATUS0, ®); - - cc_lvl = (reg & TCPC_REG_STATUS0_COMP) ? TYPEC_CC_VOLT_RD - : TYPEC_CC_VOLT_RA; - } - - /* Restore SWITCHES0 register to its value prior */ - tcpc_write(port, TCPC_REG_SWITCHES0, switches0_reg); - - mutex_unlock(&measure_lock); - - return cc_lvl; -} - -/* Determine cc pin state for source when in manual detect mode */ -static void detect_cc_pin_source_manual(int port, - enum tcpc_cc_voltage_status *cc1_lvl, - enum tcpc_cc_voltage_status *cc2_lvl) -{ - int cc1_measure = TCPC_REG_SWITCHES0_MEAS_CC1; - int cc2_measure = TCPC_REG_SWITCHES0_MEAS_CC2; - - if (state[port].vconn_enabled) { - /* If VCONN enabled, measure cc_pin that matches polarity */ - if (state[port].cc_polarity) - *cc2_lvl = measure_cc_pin_source(port, cc2_measure); - else - *cc1_lvl = measure_cc_pin_source(port, cc1_measure); - } else { - /* If VCONN not enabled, measure both cc1 and cc2 */ - *cc1_lvl = measure_cc_pin_source(port, cc1_measure); - *cc2_lvl = measure_cc_pin_source(port, cc2_measure); - } - -} - -/* Determine cc pin state for sink */ -static void detect_cc_pin_sink(int port, enum tcpc_cc_voltage_status *cc1, - enum tcpc_cc_voltage_status *cc2) -{ - int reg; - int orig_meas_cc1; - int orig_meas_cc2; - int bc_lvl_cc1; - int bc_lvl_cc2; - - mutex_lock(&measure_lock); - - /* - * Measure CC1 first. - */ - tcpc_read(port, TCPC_REG_SWITCHES0, ®); - - /* save original state to be returned to later... */ - if (reg & TCPC_REG_SWITCHES0_MEAS_CC1) - orig_meas_cc1 = 1; - else - orig_meas_cc1 = 0; - - if (reg & TCPC_REG_SWITCHES0_MEAS_CC2) - orig_meas_cc2 = 1; - else - orig_meas_cc2 = 0; - - - /* Disable CC2 measurement switch, enable CC1 measurement switch */ - reg &= ~TCPC_REG_SWITCHES0_MEAS_CC2; - reg |= TCPC_REG_SWITCHES0_MEAS_CC1; - - tcpc_write(port, TCPC_REG_SWITCHES0, reg); - - /* CC1 is now being measured by FUSB302. */ - - /* Wait on measurement */ - usleep(250); - - tcpc_read(port, TCPC_REG_STATUS0, &bc_lvl_cc1); - - /* mask away unwanted bits */ - bc_lvl_cc1 &= (TCPC_REG_STATUS0_BC_LVL0 | TCPC_REG_STATUS0_BC_LVL1); - - /* - * Measure CC2 next. - */ - - tcpc_read(port, TCPC_REG_SWITCHES0, ®); - - /* Disable CC1 measurement switch, enable CC2 measurement switch */ - reg &= ~TCPC_REG_SWITCHES0_MEAS_CC1; - reg |= TCPC_REG_SWITCHES0_MEAS_CC2; - - tcpc_write(port, TCPC_REG_SWITCHES0, reg); - - /* CC2 is now being measured by FUSB302. */ - - /* Wait on measurement */ - usleep(250); - - tcpc_read(port, TCPC_REG_STATUS0, &bc_lvl_cc2); - - /* mask away unwanted bits */ - bc_lvl_cc2 &= (TCPC_REG_STATUS0_BC_LVL0 | TCPC_REG_STATUS0_BC_LVL1); - - *cc1 = convert_bc_lvl(port, bc_lvl_cc1); - *cc2 = convert_bc_lvl(port, bc_lvl_cc2); - - /* return MEAS_CC1/2 switches to original state */ - tcpc_read(port, TCPC_REG_SWITCHES0, ®); - if (orig_meas_cc1) - reg |= TCPC_REG_SWITCHES0_MEAS_CC1; - else - reg &= ~TCPC_REG_SWITCHES0_MEAS_CC1; - if (orig_meas_cc2) - reg |= TCPC_REG_SWITCHES0_MEAS_CC2; - else - reg &= ~TCPC_REG_SWITCHES0_MEAS_CC2; - - tcpc_write(port, TCPC_REG_SWITCHES0, reg); - - mutex_unlock(&measure_lock); -} - -/* Parse header bytes for the size of packet */ -static int get_num_bytes(uint16_t header) -{ - int rv; - - /* Grab the Number of Data Objects field.*/ - rv = PD_HEADER_CNT(header); - - /* Multiply by four to go from 32-bit words -> bytes */ - rv *= 4; - - /* Plus 2 for header */ - rv += 2; - - return rv; -} - -static int fusb302_send_message(int port, uint16_t header, const uint32_t *data, - uint8_t *buf, int buf_pos) -{ - int rv; - int reg; - int len; - - len = get_num_bytes(header); - - /* - * packsym tells the TXFIFO that the next X bytes are payload, - * and should not be interpreted as special tokens. - * The 5 LSBs represent X, the number of bytes. - */ - reg = FUSB302_TKN_PACKSYM; - reg |= (len & 0x1F); - - buf[buf_pos++] = reg; - - /* write in the header */ - reg = header; - buf[buf_pos++] = reg & 0xFF; - - reg >>= 8; - buf[buf_pos++] = reg & 0xFF; - - /* header is done, subtract from length to make this for-loop simpler */ - len -= 2; - - /* write data objects, if present */ - memcpy(&buf[buf_pos], data, len); - buf_pos += len; - - /* put in the CRC */ - buf[buf_pos++] = FUSB302_TKN_JAMCRC; - - /* put in EOP */ - buf[buf_pos++] = FUSB302_TKN_EOP; - - /* Turn transmitter off after sending message */ - buf[buf_pos++] = FUSB302_TKN_TXOFF; - - /* Start transmission */ - reg = FUSB302_TKN_TXON; - buf[buf_pos++] = FUSB302_TKN_TXON; - - /* burst write for speed! */ - rv = tcpc_xfer(port, buf, buf_pos, 0, 0); - - return rv; -} - -static int fusb302_tcpm_select_rp_value(int port, int rp) -{ - int reg; - int rv; - uint8_t vnc, rd; - - /* Keep track of current RP value */ - tcpci_set_cached_rp(port, rp); - - rv = tcpc_read(port, TCPC_REG_CONTROL0, ®); - if (rv) - return rv; - - /* Set the current source for Rp value */ - reg &= ~TCPC_REG_CONTROL0_HOST_CUR_MASK; - switch (rp) { - case TYPEC_RP_1A5: - reg |= TCPC_REG_CONTROL0_HOST_CUR_1A5; - vnc = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_1_5_VNC_MV); - rd = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_1_5_RD_THRESH_MV); - break; - case TYPEC_RP_3A0: - reg |= TCPC_REG_CONTROL0_HOST_CUR_3A0; - vnc = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_3_0_VNC_MV); - rd = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_3_0_RD_THRESH_MV); - break; - case TYPEC_RP_USB: - default: - reg |= TCPC_REG_CONTROL0_HOST_CUR_USB; - vnc = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_DEF_VNC_MV); - rd = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_DEF_RD_THRESH_MV); - } - state[port].mdac_vnc = vnc; - state[port].mdac_rd = rd; - return tcpc_write(port, TCPC_REG_CONTROL0, reg); -} - -static int fusb302_tcpm_init(int port) -{ - int reg; - - /* set default */ - state[port].cc_polarity = -1; - - /* set the voltage threshold for no connect detection (vOpen) */ - state[port].mdac_vnc = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_DEF_VNC_MV); - /* set the voltage threshold for Rd vs Ra detection */ - state[port].mdac_rd = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_DEF_RD_THRESH_MV); - - /* all other variables assumed to default to 0 */ - - /* Restore default settings */ - tcpc_write(port, TCPC_REG_RESET, TCPC_REG_RESET_SW_RESET); - - /* Turn on retries and set number of retries */ - tcpc_read(port, TCPC_REG_CONTROL3, ®); - reg |= TCPC_REG_CONTROL3_AUTO_RETRY; - reg |= (CONFIG_PD_RETRY_COUNT & 0x3) << TCPC_REG_CONTROL3_N_RETRIES_POS; - tcpc_write(port, TCPC_REG_CONTROL3, reg); - - /* Create interrupt masks */ - reg = 0xFF; - /* CC level changes */ - reg &= ~TCPC_REG_MASK_BC_LVL; - /* collisions */ - reg &= ~TCPC_REG_MASK_COLLISION; - /* misc alert */ - reg &= ~TCPC_REG_MASK_ALERT; -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - /* TODO(crbug.com/791109): Clean up VBUS notification. */ - - /* VBUS threshold crossed (~4.0V) */ - reg &= ~TCPC_REG_MASK_VBUSOK; -#endif - tcpc_write(port, TCPC_REG_MASK, reg); - - reg = 0xFF; - /* when all pd message retries fail... */ - reg &= ~TCPC_REG_MASKA_RETRYFAIL; - /* when fusb302 send a hard reset. */ - reg &= ~TCPC_REG_MASKA_HARDSENT; - /* when fusb302 receives GoodCRC ack for a pd message */ - reg &= ~TCPC_REG_MASKA_TX_SUCCESS; - /* when fusb302 receives a hard reset */ - reg &= ~TCPC_REG_MASKA_HARDRESET; - tcpc_write(port, TCPC_REG_MASKA, reg); - - reg = 0xFF; - /* when fusb302 sends GoodCRC to ack a pd message */ - reg &= ~TCPC_REG_MASKB_GCRCSENT; - tcpc_write(port, TCPC_REG_MASKB, reg); - - /* Interrupt Enable */ - tcpc_read(port, TCPC_REG_CONTROL0, ®); - reg &= ~TCPC_REG_CONTROL0_INT_MASK; - tcpc_write(port, TCPC_REG_CONTROL0, reg); - - /* Set VCONN switch defaults */ - tcpm_set_polarity(port, 0); - tcpm_set_vconn(port, 0); - - /* TODO: Reduce power consumption */ - tcpc_write(port, TCPC_REG_POWER, TCPC_REG_POWER_PWR_ALL); - -#if defined(CONFIG_USB_PD_VBUS_DETECT_TCPC) && defined(CONFIG_USB_CHARGER) - /* Wait for the reference voltage to stablize */ - usleep(250); - /* - * Initialize VBUS supplier when VBUS is already present before - * init (e.g. Cold reboot with charger plugged). - */ - tcpc_read(port, TCPC_REG_STATUS0, ®); - if (reg & TCPC_REG_STATUS0_VBUSOK) - usb_charger_vbus_change(port, 1); -#endif - - return 0; -} - -static int fusb302_tcpm_release(int port) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -static int fusb302_tcpm_get_cc(int port, enum tcpc_cc_voltage_status *cc1, - enum tcpc_cc_voltage_status *cc2) -{ - if (state[port].pulling_up) { - /* Source mode? */ - detect_cc_pin_source_manual(port, cc1, cc2); - } else { - /* Sink mode? */ - detect_cc_pin_sink(port, cc1, cc2); - } - - return 0; -} - -static int fusb302_tcpm_set_cc(int port, int pull) -{ - int reg; - - /* NOTE: FUSB302 toggles a single pull-up between CC1 and CC2 */ - /* NOTE: FUSB302 Does not support Ra. */ - switch (pull) { - case TYPEC_CC_RP: - /* enable the pull-up we know to be necessary */ - tcpc_read(port, TCPC_REG_SWITCHES0, ®); - - reg &= ~(TCPC_REG_SWITCHES0_CC2_PU_EN | - TCPC_REG_SWITCHES0_CC1_PU_EN | - TCPC_REG_SWITCHES0_CC1_PD_EN | - TCPC_REG_SWITCHES0_CC2_PD_EN | - TCPC_REG_SWITCHES0_VCONN_CC1 | - TCPC_REG_SWITCHES0_VCONN_CC2); - - reg |= TCPC_REG_SWITCHES0_CC1_PU_EN | - TCPC_REG_SWITCHES0_CC2_PU_EN; - - if (state[port].vconn_enabled) - reg |= state[port].cc_polarity ? - TCPC_REG_SWITCHES0_VCONN_CC1 : - TCPC_REG_SWITCHES0_VCONN_CC2; - - tcpc_write(port, TCPC_REG_SWITCHES0, reg); - - state[port].pulling_up = 1; - break; - case TYPEC_CC_RD: - /* Enable UFP Mode */ - - /* turn off toggle */ - tcpc_read(port, TCPC_REG_CONTROL2, ®); - reg &= ~TCPC_REG_CONTROL2_TOGGLE; - tcpc_write(port, TCPC_REG_CONTROL2, reg); - - /* enable pull-downs, disable pullups */ - tcpc_read(port, TCPC_REG_SWITCHES0, ®); - - reg &= ~(TCPC_REG_SWITCHES0_CC2_PU_EN); - reg &= ~(TCPC_REG_SWITCHES0_CC1_PU_EN); - reg |= (TCPC_REG_SWITCHES0_CC1_PD_EN); - reg |= (TCPC_REG_SWITCHES0_CC2_PD_EN); - tcpc_write(port, TCPC_REG_SWITCHES0, reg); - - state[port].pulling_up = 0; - break; - case TYPEC_CC_OPEN: - /* Disable toggling */ - tcpc_read(port, TCPC_REG_CONTROL2, ®); - reg &= ~TCPC_REG_CONTROL2_TOGGLE; - tcpc_write(port, TCPC_REG_CONTROL2, reg); - - /* Ensure manual switches are opened */ - tcpc_read(port, TCPC_REG_SWITCHES0, ®); - reg &= ~TCPC_REG_SWITCHES0_CC1_PU_EN; - reg &= ~TCPC_REG_SWITCHES0_CC2_PU_EN; - reg &= ~TCPC_REG_SWITCHES0_CC1_PD_EN; - reg &= ~TCPC_REG_SWITCHES0_CC2_PD_EN; - tcpc_write(port, TCPC_REG_SWITCHES0, reg); - - state[port].pulling_up = 0; - break; - default: - /* Unsupported... */ - return EC_ERROR_UNIMPLEMENTED; - } - return 0; -} - -static int fusb302_tcpm_set_polarity(int port, enum tcpc_cc_polarity polarity) -{ - /* Port polarity : 0 => CC1 is CC line, 1 => CC2 is CC line */ - int reg; - - tcpc_read(port, TCPC_REG_SWITCHES0, ®); - - /* clear VCONN switch bits */ - reg &= ~TCPC_REG_SWITCHES0_VCONN_CC1; - reg &= ~TCPC_REG_SWITCHES0_VCONN_CC2; - - if (state[port].vconn_enabled) { - /* set VCONN switch to be non-CC line */ - if (polarity_rm_dts(polarity)) - reg |= TCPC_REG_SWITCHES0_VCONN_CC1; - else - reg |= TCPC_REG_SWITCHES0_VCONN_CC2; - } - - /* clear meas_cc bits (RX line select) */ - reg &= ~TCPC_REG_SWITCHES0_MEAS_CC1; - reg &= ~TCPC_REG_SWITCHES0_MEAS_CC2; - - /* set rx polarity */ - if (polarity_rm_dts(polarity)) - reg |= TCPC_REG_SWITCHES0_MEAS_CC2; - else - reg |= TCPC_REG_SWITCHES0_MEAS_CC1; - - tcpc_write(port, TCPC_REG_SWITCHES0, reg); - - tcpc_read(port, TCPC_REG_SWITCHES1, ®); - - /* clear tx_cc bits */ - reg &= ~TCPC_REG_SWITCHES1_TXCC1_EN; - reg &= ~TCPC_REG_SWITCHES1_TXCC2_EN; - - /* set tx polarity */ - if (polarity_rm_dts(polarity)) - reg |= TCPC_REG_SWITCHES1_TXCC2_EN; - else - reg |= TCPC_REG_SWITCHES1_TXCC1_EN; - - tcpc_write(port, TCPC_REG_SWITCHES1, reg); - - /* Save the polarity for later */ - state[port].cc_polarity = polarity; - - return 0; -} - -__maybe_unused static int fusb302_tcpm_decode_sop_prime_enable(int port, - bool enable) -{ - int reg; - - if (tcpc_read(port, TCPC_REG_CONTROL1, ®)) - return EC_ERROR_UNKNOWN; - - if (enable) - reg |= (TCPC_REG_CONTROL1_ENSOP1 | - TCPC_REG_CONTROL1_ENSOP2); - else - reg &= ~(TCPC_REG_CONTROL1_ENSOP1 | - TCPC_REG_CONTROL1_ENSOP2); - - return tcpc_write(port, TCPC_REG_CONTROL1, reg); -} - -static int fusb302_tcpm_set_vconn(int port, int enable) -{ - /* - * FUSB302 does not have dedicated VCONN Enable switch. - * We'll get through this by disabling both of the - * VCONN - CC* switches to disable, and enabling the - * saved polarity when enabling. - * Therefore at startup, tcpm_set_polarity should be called first, - * or else live with the default put into tcpm_init. - */ - int reg; - - /* save enable state for later use */ - state[port].vconn_enabled = enable; - - if (enable) { - /* set to saved polarity */ - tcpm_set_polarity(port, state[port].cc_polarity); - - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) { - if (state[port].rx_enable) { - if (fusb302_tcpm_decode_sop_prime_enable(port, - true)) - return EC_ERROR_UNKNOWN; - } - } - } else { - - tcpc_read(port, TCPC_REG_SWITCHES0, ®); - - /* clear VCONN switch bits */ - reg &= ~TCPC_REG_SWITCHES0_VCONN_CC1; - reg &= ~TCPC_REG_SWITCHES0_VCONN_CC2; - - tcpc_write(port, TCPC_REG_SWITCHES0, reg); - - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) { - if (state[port].rx_enable) { - if (fusb302_tcpm_decode_sop_prime_enable(port, - false)) - return EC_ERROR_UNKNOWN; - } - } - } - - return 0; -} - -static int fusb302_tcpm_set_msg_header(int port, int power_role, int data_role) -{ - int reg; - - tcpc_read(port, TCPC_REG_SWITCHES1, ®); - - reg &= ~TCPC_REG_SWITCHES1_POWERROLE; - reg &= ~TCPC_REG_SWITCHES1_DATAROLE; - - if (power_role) - reg |= TCPC_REG_SWITCHES1_POWERROLE; - if (data_role) - reg |= TCPC_REG_SWITCHES1_DATAROLE; - - tcpc_write(port, TCPC_REG_SWITCHES1, reg); - - return 0; -} - -static int fusb302_tcpm_set_rx_enable(int port, int enable) -{ - int reg; - - state[port].rx_enable = enable; - - /* Get current switch state */ - tcpc_read(port, TCPC_REG_SWITCHES0, ®); - - /* Clear CC1/CC2 measure bits */ - reg &= ~TCPC_REG_SWITCHES0_MEAS_CC1; - reg &= ~TCPC_REG_SWITCHES0_MEAS_CC2; - - if (enable) { - switch (state[port].cc_polarity) { - /* if CC polarity hasnt been determined, can't enable */ - case -1: - return EC_ERROR_UNKNOWN; - case 0: - reg |= TCPC_REG_SWITCHES0_MEAS_CC1; - break; - case 1: - reg |= TCPC_REG_SWITCHES0_MEAS_CC2; - break; - default: - /* "shouldn't get here" */ - return EC_ERROR_UNKNOWN; - } - tcpc_write(port, TCPC_REG_SWITCHES0, reg); - - /* Disable BC_LVL interrupt when enabling PD comm */ - if (!tcpc_read(port, TCPC_REG_MASK, ®)) - tcpc_write(port, TCPC_REG_MASK, - reg | TCPC_REG_MASK_BC_LVL); - - /* flush rx fifo in case messages have been coming our way */ - fusb302_flush_rx_fifo(port); - - - } else { - tcpc_write(port, TCPC_REG_SWITCHES0, reg); - - /* Enable BC_LVL interrupt when disabling PD comm */ - if (!tcpc_read(port, TCPC_REG_MASK, ®)) - tcpc_write(port, TCPC_REG_MASK, - reg & ~TCPC_REG_MASK_BC_LVL); - } - -#ifdef CONFIG_USB_PD_DECODE_SOP - /* - * Only the VCONN Source is allowed to communicate - * with the Cable Plugs. - */ - if (state[port].vconn_enabled) { - if (tcpc_read(port, TCPC_REG_CONTROL1, ®)) - return EC_ERROR_UNKNOWN; - - reg |= (TCPC_REG_CONTROL1_ENSOP1 | TCPC_REG_CONTROL1_ENSOP2); - tcpc_write(port, TCPC_REG_CONTROL1, reg); - } -#endif - - fusb302_auto_goodcrc_enable(port, enable); - - return 0; -} - -/* Return true if our Rx FIFO is empty */ -static int fusb302_rx_fifo_is_empty(int port) -{ - int reg; - - return (!tcpc_read(port, TCPC_REG_STATUS1, ®)) && - (reg & TCPC_REG_STATUS1_RX_EMPTY); -} - -static int fusb302_tcpm_get_message_raw(int port, uint32_t *payload, int *head) -{ - /* - * This is the buffer that will get the burst-read data - * from the fusb302. - * - * It's re-used in a couple different spots, the worst of which - * is the PD packet (not header) and CRC. - * maximum size necessary = 28 + 4 = 32 - */ - uint8_t buf[32]; - int rv, len; - - /* Read until we have a non-GoodCRC packet or an empty FIFO */ - do { - buf[0] = TCPC_REG_FIFOS; - tcpc_lock(port, 1); - - /* - * PART 1 OF BURST READ: Write in register address. - * Issue a START, no STOP. - */ - rv = tcpc_xfer_unlocked(port, buf, 1, 0, 0, I2C_XFER_START); - - /* - * PART 2 OF BURST READ: Read up to the header. - * Issue a repeated START, no STOP. - * only grab three bytes so we can get the header - * and determine how many more bytes we need to read. - * TODO: Check token to ensure valid packet. - */ - rv |= tcpc_xfer_unlocked(port, 0, 0, buf, 3, I2C_XFER_START); - - /* Grab the header */ - *head = (buf[1] & 0xFF); - *head |= ((buf[2] << 8) & 0xFF00); - - /* figure out packet length, subtract header bytes */ - len = get_num_bytes(*head) - 2; - - /* - * PART 3 OF BURST READ: Read everything else. - * No START, but do issue a STOP at the end. - * add 4 to len to read CRC out - */ - rv |= tcpc_xfer_unlocked(port, 0, 0, buf, len+4, I2C_XFER_STOP); - - tcpc_lock(port, 0); - } while (!rv && PACKET_IS_GOOD_CRC(*head) && - !fusb302_rx_fifo_is_empty(port)); - - if (!rv) { - /* Discard GoodCRC packets */ - if (PACKET_IS_GOOD_CRC(*head)) - rv = EC_ERROR_UNKNOWN; - else - memcpy(payload, buf, len); - } - -#ifdef CONFIG_USB_PD_DECODE_SOP - { - int reg; - - if (tcpc_read(port, TCPC_REG_STATUS1, ®)) - return EC_ERROR_UNKNOWN; - - if (reg & TCPC_REG_STATUS1_RXSOP1) - *head |= PD_HEADER_SOP(TCPCI_MSG_SOP_PRIME); - else if (reg & TCPC_REG_STATUS1_RXSOP2) - *head |= PD_HEADER_SOP(TCPCI_MSG_SOP_PRIME_PRIME); - } -#endif - - return rv; -} - -static int fusb302_tcpm_transmit(int port, enum tcpci_msg_type type, - uint16_t header, const uint32_t *data) -{ - /* - * this is the buffer that will be burst-written into the fusb302 - * maximum size necessary = - * 1: FIFO register address - * 4: SOP* tokens - * 1: Token that signifies "next X bytes are not tokens" - * 30: 2 for header and up to 7*4 = 28 for rest of message - * 1: "Insert CRC" Token - * 1: EOP Token - * 1: "Turn transmitter off" token - * 1: "Star Transmission" Command - * - - * 40: 40 bytes worst-case - */ - uint8_t buf[40]; - int buf_pos = 0; - - int reg; - - /* Flush the TXFIFO */ - fusb302_flush_tx_fifo(port); - - switch (type) { - case TCPCI_MSG_SOP: - - /* put register address first for of burst tcpc write */ - buf[buf_pos++] = TCPC_REG_FIFOS; - - /* Write the SOP Ordered Set into TX FIFO */ - buf[buf_pos++] = FUSB302_TKN_SYNC1; - buf[buf_pos++] = FUSB302_TKN_SYNC1; - buf[buf_pos++] = FUSB302_TKN_SYNC1; - buf[buf_pos++] = FUSB302_TKN_SYNC2; - - return fusb302_send_message(port, header, data, buf, buf_pos); - case TCPCI_MSG_SOP_PRIME: - - /* put register address first for of burst tcpc write */ - buf[buf_pos++] = TCPC_REG_FIFOS; - - /* Write the SOP' Ordered Set into TX FIFO */ - buf[buf_pos++] = FUSB302_TKN_SYNC1; - buf[buf_pos++] = FUSB302_TKN_SYNC1; - buf[buf_pos++] = FUSB302_TKN_SYNC3; - buf[buf_pos++] = FUSB302_TKN_SYNC3; - - return fusb302_send_message(port, header, data, buf, buf_pos); - case TCPCI_MSG_SOP_PRIME_PRIME: - - /* put register address first for of burst tcpc write */ - buf[buf_pos++] = TCPC_REG_FIFOS; - - /* Write the SOP'' Ordered Set into TX FIFO */ - buf[buf_pos++] = FUSB302_TKN_SYNC1; - buf[buf_pos++] = FUSB302_TKN_SYNC3; - buf[buf_pos++] = FUSB302_TKN_SYNC1; - buf[buf_pos++] = FUSB302_TKN_SYNC3; - - return fusb302_send_message(port, header, data, buf, buf_pos); - case TCPCI_MSG_TX_HARD_RESET: - /* Simply hit the SEND_HARD_RESET bit */ - tcpc_read(port, TCPC_REG_CONTROL3, ®); - reg |= TCPC_REG_CONTROL3_SEND_HARDRESET; - tcpc_write(port, TCPC_REG_CONTROL3, reg); - - break; - case TCPCI_MSG_TX_BIST_MODE_2: - /* Hit the BIST_MODE2 bit and start TX */ - tcpc_read(port, TCPC_REG_CONTROL1, ®); - reg |= TCPC_REG_CONTROL1_BIST_MODE2; - tcpc_write(port, TCPC_REG_CONTROL1, reg); - - tcpc_read(port, TCPC_REG_CONTROL0, ®); - reg |= TCPC_REG_CONTROL0_TX_START; - tcpc_write(port, TCPC_REG_CONTROL0, reg); - - task_wait_event(PD_T_BIST_TRANSMIT); - - /* Clear BIST mode bit, TX_START is self-clearing */ - tcpc_read(port, TCPC_REG_CONTROL1, ®); - reg &= ~TCPC_REG_CONTROL1_BIST_MODE2; - tcpc_write(port, TCPC_REG_CONTROL1, reg); - - break; - default: - return EC_ERROR_UNIMPLEMENTED; - } - - return 0; -} - -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC -static bool fusb302_tcpm_check_vbus_level(int port, enum vbus_level level) -{ - int reg; - - /* Read status register */ - tcpc_read(port, TCPC_REG_STATUS0, ®); - - if (level == VBUS_PRESENT) - return (reg & TCPC_REG_STATUS0_VBUSOK) ? 1 : 0; - else - return (reg & TCPC_REG_STATUS0_VBUSOK) ? 0 : 1; -} -#endif - -void fusb302_tcpc_alert(int port) -{ - /* interrupt has been received */ - int interrupt; - int interrupta; - int interruptb; - - /* reading interrupt registers clears them */ - - tcpc_read(port, TCPC_REG_INTERRUPT, &interrupt); - tcpc_read(port, TCPC_REG_INTERRUPTA, &interrupta); - tcpc_read(port, TCPC_REG_INTERRUPTB, &interruptb); - - /* - * Ignore BC_LVL changes when transmitting / receiving PD, - * since CC level will constantly change. - */ - if (state[port].rx_enable) - interrupt &= ~TCPC_REG_INTERRUPT_BC_LVL; - - if (interrupt & TCPC_REG_INTERRUPT_BC_LVL) { - /* CC Status change */ - task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_CC); - } - - if (interrupt & TCPC_REG_INTERRUPT_COLLISION) { - /* packet sending collided */ - pd_transmit_complete(port, TCPC_TX_COMPLETE_FAILED); - } - -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - if (interrupt & TCPC_REG_INTERRUPT_VBUSOK) { - /* VBUS crossed threshold */ -#ifdef CONFIG_USB_CHARGER - usb_charger_vbus_change(port, - fusb302_tcpm_check_vbus_level(port, - VBUS_PRESENT)); -#else - if (!fusb302_tcpm_check_vbus_level(port, VBUS_PRESENT)) - pd_vbus_low(port); -#endif - task_wake(PD_PORT_TO_TASK_ID(port)); - hook_notify(HOOK_AC_CHANGE); - } -#endif - - /* GoodCRC was received, our FIFO is now non-empty */ - if (interrupta & TCPC_REG_INTERRUPTA_TX_SUCCESS) { - pd_transmit_complete(port, TCPC_TX_COMPLETE_SUCCESS); - } - - if (interrupta & TCPC_REG_INTERRUPTA_RETRYFAIL) { - /* all retries have failed to get a GoodCRC */ - pd_transmit_complete(port, TCPC_TX_COMPLETE_FAILED); - } - - if (interrupta & TCPC_REG_INTERRUPTA_HARDSENT) { - /* hard reset has been sent */ - - /* bring FUSB302 out of reset */ - fusb302_pd_reset(port); - - pd_transmit_complete(port, TCPC_TX_COMPLETE_SUCCESS); - } - - if (interrupta & TCPC_REG_INTERRUPTA_HARDRESET) { - /* hard reset has been received */ - - /* bring FUSB302 out of reset */ - fusb302_pd_reset(port); - task_set_event(PD_PORT_TO_TASK_ID(port), - PD_EVENT_RX_HARD_RESET); - } - - if (interruptb & TCPC_REG_INTERRUPTB_GCRCSENT) { - /* Packet received and GoodCRC sent */ - /* (this interrupt fires after the GoodCRC finishes) */ - if (state[port].rx_enable) { - /* Pull all RX messages from TCPC into EC memory */ - while (!fusb302_rx_fifo_is_empty(port)) - tcpm_enqueue_message(port); - } else { - /* flush rx fifo if rx isn't enabled */ - fusb302_flush_rx_fifo(port); - } - } - -} - -/* For BIST receiving */ -void tcpm_set_bist_test_data(int port) -{ - int reg; - - /* Read control3 register */ - tcpc_read(port, TCPC_REG_CONTROL3, ®); - - /* Set the BIST_TMODE bit (Clears on Hard Reset) */ - reg |= TCPC_REG_CONTROL3_BIST_TMODE; - - /* Write the updated value */ - tcpc_write(port, TCPC_REG_CONTROL3, reg); -} - -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER -static int fusb302_set_toggle_mode(int port, int mode) -{ - int reg, rv; - - rv = i2c_read8(tcpc_config[port].i2c_info.port, - tcpc_config[port].i2c_info.addr_flags, - TCPC_REG_CONTROL2, ®); - if (rv) - return rv; - - reg &= ~TCPC_REG_CONTROL2_MODE_MASK; - reg |= mode << TCPC_REG_CONTROL2_MODE_POS; - return i2c_write8(tcpc_config[port].i2c_info.port, - tcpc_config[port].i2c_info.addr_flags, - TCPC_REG_CONTROL2, reg); -} - -static int fusb302_tcpm_enter_low_power_mode(int port) -{ - int reg, rv, mode = TCPC_REG_CONTROL2_MODE_DRP; - - /** - * vendor's suggested LPM flow: - * - enable low power mode and set up other things - * - sleep 250 us - * - start toggling - */ - rv = i2c_write8(tcpc_config[port].i2c_info.port, - tcpc_config[port].i2c_info.addr_flags, - TCPC_REG_POWER, TCPC_REG_POWER_PWR_LOW); - if (rv) - return rv; - - switch (pd_get_dual_role(port)) { - case PD_DRP_TOGGLE_ON: - mode = TCPC_REG_CONTROL2_MODE_DRP; - break; - case PD_DRP_TOGGLE_OFF: - mode = TCPC_REG_CONTROL2_MODE_UFP; - break; - case PD_DRP_FREEZE: - mode = pd_get_power_role(port) == PD_ROLE_SINK ? - TCPC_REG_CONTROL2_MODE_UFP : - TCPC_REG_CONTROL2_MODE_DFP; - break; - case PD_DRP_FORCE_SINK: - mode = TCPC_REG_CONTROL2_MODE_UFP; - break; - case PD_DRP_FORCE_SOURCE: - mode = TCPC_REG_CONTROL2_MODE_DFP; - break; - } - rv = fusb302_set_toggle_mode(port, mode); - if (rv) - return rv; - - usleep(250); - - rv = i2c_read8(tcpc_config[port].i2c_info.port, - tcpc_config[port].i2c_info.addr_flags, - TCPC_REG_CONTROL2, ®); - if (rv) - return rv; - reg |= TCPC_REG_CONTROL2_TOGGLE; - return i2c_write8(tcpc_config[port].i2c_info.port, - tcpc_config[port].i2c_info.addr_flags, - TCPC_REG_CONTROL2, reg); -} -#endif - -/* - * Compare VBUS voltage with given mdac reference voltage. - * returns non-zero if VBUS voltage >= (mdac + 1) * 420 mV - */ -static int fusb302_compare_mdac(int port, int mdac) -{ - int orig_reg, status0; - - mutex_lock(&measure_lock); - - /* backup REG_MEASURE */ - tcpc_read(port, TCPC_REG_MEASURE, &orig_reg); - /* set reg_measure bit 0~5 to mdac, and bit6 to 1(measure vbus) */ - tcpc_write(port, TCPC_REG_MEASURE, - (mdac & TCPC_REG_MEASURE_MDAC_MASK) | TCPC_REG_MEASURE_VBUS); - - /* Wait on measurement */ - usleep(350); - - /* - * Read status register, if STATUS0_COMP=1 then vbus is higher than - * (mdac + 1) * 0.42V - */ - tcpc_read(port, TCPC_REG_STATUS0, &status0); - /* write back original value */ - tcpc_write(port, TCPC_REG_MEASURE, orig_reg); - - mutex_unlock(&measure_lock); - - return status0 & TCPC_REG_STATUS0_COMP; -} - -int tcpc_get_vbus_voltage(int port) -{ - int mdac = 0, i; - - /* - * Implement by comparing VBUS with MDAC reference voltage, and binary - * search the value of MDAC. - * - * MDAC register has 6 bits, so we can simply search 1 bit per - * iteration, from MSB to LSB. - */ - for (i = 5; i >= 0; i--) { - if (fusb302_compare_mdac(port, mdac | BIT(i))) - mdac |= BIT(i); - } - - return (mdac + 1) * 420; -} - -const struct tcpm_drv fusb302_tcpm_drv = { - .init = &fusb302_tcpm_init, - .release = &fusb302_tcpm_release, - .get_cc = &fusb302_tcpm_get_cc, -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - .check_vbus_level = &fusb302_tcpm_check_vbus_level, -#endif - .select_rp_value = &fusb302_tcpm_select_rp_value, - .set_cc = &fusb302_tcpm_set_cc, - .set_polarity = &fusb302_tcpm_set_polarity, -#ifdef CONFIG_USB_PD_DECODE_SOP - .sop_prime_enable = &fusb302_tcpm_decode_sop_prime_enable, -#endif - .set_vconn = &fusb302_tcpm_set_vconn, - .set_msg_header = &fusb302_tcpm_set_msg_header, - .set_rx_enable = &fusb302_tcpm_set_rx_enable, - .get_message_raw = &fusb302_tcpm_get_message_raw, - .transmit = &fusb302_tcpm_transmit, - .tcpc_alert = &fusb302_tcpc_alert, -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER - .enter_low_power_mode = &fusb302_tcpm_enter_low_power_mode, -#endif -}; diff --git a/driver/tcpm/fusb302.h b/driver/tcpm/fusb302.h deleted file mode 100644 index 717b28df18..0000000000 --- a/driver/tcpm/fusb302.h +++ /dev/null @@ -1,211 +0,0 @@ -/* 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. - * - * Author: Gabe Noblesmith - */ - -/* USB Power delivery port management */ -/* For Fairchild FUSB302 */ -#ifndef __CROS_EC_DRIVER_TCPM_FUSB302_H -#define __CROS_EC_DRIVER_TCPM_FUSB302_H - -/* Chip Device ID - 302A or 302B */ -#define FUSB302_DEVID_302A 0x08 -#define FUSB302_DEVID_302B 0x09 - -/* I2C address varies by part number */ -/* FUSB302BUCX / FUSB302BMPX */ -#define FUSB302_I2C_ADDR_FLAGS 0x22 -/* FUSB302B01MPX */ -#define FUSB302_I2C_ADDR_B01_FLAGS 0x23 -/* FUSB302B10MPX */ -#define FUSB302_I2C_ADDR_B10_FLAGS 0x24 -/* FUSB302B11MPX */ -#define FUSB302_I2C_ADDR_B11_FLAGS 0x25 - -#define TCPC_REG_DEVICE_ID 0x01 - -#define TCPC_REG_SWITCHES0 0x02 -#define TCPC_REG_SWITCHES0_CC2_PU_EN (1<<7) -#define TCPC_REG_SWITCHES0_CC1_PU_EN (1<<6) -#define TCPC_REG_SWITCHES0_VCONN_CC2 (1<<5) -#define TCPC_REG_SWITCHES0_VCONN_CC1 (1<<4) -#define TCPC_REG_SWITCHES0_MEAS_CC2 (1<<3) -#define TCPC_REG_SWITCHES0_MEAS_CC1 (1<<2) -#define TCPC_REG_SWITCHES0_CC2_PD_EN (1<<1) -#define TCPC_REG_SWITCHES0_CC1_PD_EN (1<<0) - -#define TCPC_REG_SWITCHES1 0x03 -#define TCPC_REG_SWITCHES1_POWERROLE (1<<7) -#define TCPC_REG_SWITCHES1_SPECREV1 (1<<6) -#define TCPC_REG_SWITCHES1_SPECREV0 (1<<5) -#define TCPC_REG_SWITCHES1_DATAROLE (1<<4) -#define TCPC_REG_SWITCHES1_AUTO_GCRC (1<<2) -#define TCPC_REG_SWITCHES1_TXCC2_EN (1<<1) -#define TCPC_REG_SWITCHES1_TXCC1_EN (1<<0) - -#define TCPC_REG_MEASURE 0x04 -#define TCPC_REG_MEASURE_MDAC_MASK 0x3F -#define TCPC_REG_MEASURE_VBUS (1<<6) -/* - * MDAC reference voltage step size is 42 mV. Round our thresholds to reduce - * maximum error, which also matches suggested thresholds in datasheet - * (Table 3. Host Interrupt Summary). - */ -#define TCPC_REG_MEASURE_MDAC_MV(mv) (DIV_ROUND_NEAREST((mv), 42) & 0x3f) - -#define TCPC_REG_CONTROL0 0x06 -#define TCPC_REG_CONTROL0_TX_FLUSH (1<<6) -#define TCPC_REG_CONTROL0_INT_MASK (1<<5) -#define TCPC_REG_CONTROL0_HOST_CUR_MASK (3<<2) -#define TCPC_REG_CONTROL0_HOST_CUR_3A0 (3<<2) -#define TCPC_REG_CONTROL0_HOST_CUR_1A5 (2<<2) -#define TCPC_REG_CONTROL0_HOST_CUR_USB (1<<2) -#define TCPC_REG_CONTROL0_TX_START (1<<0) - -#define TCPC_REG_CONTROL1 0x07 -#define TCPC_REG_CONTROL1_ENSOP2DB (1<<6) -#define TCPC_REG_CONTROL1_ENSOP1DB (1<<5) -#define TCPC_REG_CONTROL1_BIST_MODE2 (1<<4) -#define TCPC_REG_CONTROL1_RX_FLUSH (1<<2) -#define TCPC_REG_CONTROL1_ENSOP2 (1<<1) -#define TCPC_REG_CONTROL1_ENSOP1 (1<<0) - -#define TCPC_REG_CONTROL2 0x08 -/* two-bit field, valid values below */ -#define TCPC_REG_CONTROL2_MODE_MASK (0x3<<TCPC_REG_CONTROL2_MODE_POS) -#define TCPC_REG_CONTROL2_MODE_DFP (0x3) -#define TCPC_REG_CONTROL2_MODE_UFP (0x2) -#define TCPC_REG_CONTROL2_MODE_DRP (0x1) -#define TCPC_REG_CONTROL2_MODE_POS (1) -#define TCPC_REG_CONTROL2_TOGGLE (1<<0) - -#define TCPC_REG_CONTROL3 0x09 -#define TCPC_REG_CONTROL3_SEND_HARDRESET (1<<6) -#define TCPC_REG_CONTROL3_BIST_TMODE (1<<5) /* 302B Only */ -#define TCPC_REG_CONTROL3_AUTO_HARDRESET (1<<4) -#define TCPC_REG_CONTROL3_AUTO_SOFTRESET (1<<3) -/* two-bit field */ -#define TCPC_REG_CONTROL3_N_RETRIES (1<<1) -#define TCPC_REG_CONTROL3_N_RETRIES_POS (1) -#define TCPC_REG_CONTROL3_N_RETRIES_SIZE (2) -#define TCPC_REG_CONTROL3_AUTO_RETRY (1<<0) - -#define TCPC_REG_MASK 0x0A -#define TCPC_REG_MASK_VBUSOK (1<<7) -#define TCPC_REG_MASK_ACTIVITY (1<<6) -#define TCPC_REG_MASK_COMP_CHNG (1<<5) -#define TCPC_REG_MASK_CRC_CHK (1<<4) -#define TCPC_REG_MASK_ALERT (1<<3) -#define TCPC_REG_MASK_WAKE (1<<2) -#define TCPC_REG_MASK_COLLISION (1<<1) -#define TCPC_REG_MASK_BC_LVL (1<<0) - -#define TCPC_REG_POWER 0x0B -#define TCPC_REG_POWER_PWR (1<<0) /* four-bit field */ -#define TCPC_REG_POWER_PWR_LOW 0x1 /* Bandgap + Wake circuitry */ -#define TCPC_REG_POWER_PWR_MEDIUM 0x3 /* LOW + Receiver + Current refs */ -#define TCPC_REG_POWER_PWR_HIGH 0x7 /* MEDIUM + Measure block */ -#define TCPC_REG_POWER_PWR_ALL 0xF /* HIGH + Internal Oscillator */ - -#define TCPC_REG_RESET 0x0C -#define TCPC_REG_RESET_PD_RESET (1<<1) -#define TCPC_REG_RESET_SW_RESET (1<<0) - -#define TCPC_REG_MASKA 0x0E -#define TCPC_REG_MASKA_OCP_TEMP (1<<7) -#define TCPC_REG_MASKA_TOGDONE (1<<6) -#define TCPC_REG_MASKA_SOFTFAIL (1<<5) -#define TCPC_REG_MASKA_RETRYFAIL (1<<4) -#define TCPC_REG_MASKA_HARDSENT (1<<3) -#define TCPC_REG_MASKA_TX_SUCCESS (1<<2) -#define TCPC_REG_MASKA_SOFTRESET (1<<1) -#define TCPC_REG_MASKA_HARDRESET (1<<0) - -#define TCPC_REG_MASKB 0x0F -#define TCPC_REG_MASKB_GCRCSENT (1<<0) - -#define TCPC_REG_STATUS0A 0x3C -#define TCPC_REG_STATUS0A_SOFTFAIL (1<<5) -#define TCPC_REG_STATUS0A_RETRYFAIL (1<<4) -#define TCPC_REG_STATUS0A_POWER (1<<2) /* two-bit field */ -#define TCPC_REG_STATUS0A_RX_SOFT_RESET (1<<1) -#define TCPC_REG_STATUS0A_RX_HARD_RESEt (1<<0) - -#define TCPC_REG_STATUS1A 0x3D -/* three-bit field, valid values below */ -#define TCPC_REG_STATUS1A_TOGSS (1<<3) -#define TCPC_REG_STATUS1A_TOGSS_RUNNING 0x0 -#define TCPC_REG_STATUS1A_TOGSS_SRC1 0x1 -#define TCPC_REG_STATUS1A_TOGSS_SRC2 0x2 -#define TCPC_REG_STATUS1A_TOGSS_SNK1 0x5 -#define TCPC_REG_STATUS1A_TOGSS_SNK2 0x6 -#define TCPC_REG_STATUS1A_TOGSS_AA 0x7 -#define TCPC_REG_STATUS1A_TOGSS_POS (3) -#define TCPC_REG_STATUS1A_TOGSS_MASK (0x7) - -#define TCPC_REG_STATUS1A_RXSOP2DB (1<<2) -#define TCPC_REG_STATUS1A_RXSOP1DB (1<<1) -#define TCPC_REG_STATUS1A_RXSOP (1<<0) - -#define TCPC_REG_INTERRUPTA 0x3E -#define TCPC_REG_INTERRUPTA_OCP_TEMP (1<<7) -#define TCPC_REG_INTERRUPTA_TOGDONE (1<<6) -#define TCPC_REG_INTERRUPTA_SOFTFAIL (1<<5) -#define TCPC_REG_INTERRUPTA_RETRYFAIL (1<<4) -#define TCPC_REG_INTERRUPTA_HARDSENT (1<<3) -#define TCPC_REG_INTERRUPTA_TX_SUCCESS (1<<2) -#define TCPC_REG_INTERRUPTA_SOFTRESET (1<<1) -#define TCPC_REG_INTERRUPTA_HARDRESET (1<<0) - -#define TCPC_REG_INTERRUPTB 0x3F -#define TCPC_REG_INTERRUPTB_GCRCSENT (1<<0) - -#define TCPC_REG_STATUS0 0x40 -#define TCPC_REG_STATUS0_VBUSOK (1<<7) -#define TCPC_REG_STATUS0_ACTIVITY (1<<6) -#define TCPC_REG_STATUS0_COMP (1<<5) -#define TCPC_REG_STATUS0_CRC_CHK (1<<4) -#define TCPC_REG_STATUS0_ALERT (1<<3) -#define TCPC_REG_STATUS0_WAKE (1<<2) -#define TCPC_REG_STATUS0_BC_LVL1 (1<<1) /* two-bit field */ -#define TCPC_REG_STATUS0_BC_LVL0 (1<<0) /* two-bit field */ - -#define TCPC_REG_STATUS1 0x41 -#define TCPC_REG_STATUS1_RXSOP2 (1<<7) -#define TCPC_REG_STATUS1_RXSOP1 (1<<6) -#define TCPC_REG_STATUS1_RX_EMPTY (1<<5) -#define TCPC_REG_STATUS1_RX_FULL (1<<4) -#define TCPC_REG_STATUS1_TX_EMPTY (1<<3) -#define TCPC_REG_STATUS1_TX_FULL (1<<2) - -#define TCPC_REG_INTERRUPT 0x42 -#define TCPC_REG_INTERRUPT_VBUSOK (1<<7) -#define TCPC_REG_INTERRUPT_ACTIVITY (1<<6) -#define TCPC_REG_INTERRUPT_COMP_CHNG (1<<5) -#define TCPC_REG_INTERRUPT_CRC_CHK (1<<4) -#define TCPC_REG_INTERRUPT_ALERT (1<<3) -#define TCPC_REG_INTERRUPT_WAKE (1<<2) -#define TCPC_REG_INTERRUPT_COLLISION (1<<1) -#define TCPC_REG_INTERRUPT_BC_LVL (1<<0) - -#define TCPC_REG_FIFOS 0x43 - -/* Tokens defined for the FUSB302 TX FIFO */ -enum fusb302_txfifo_tokens { - FUSB302_TKN_TXON = 0xA1, - FUSB302_TKN_SYNC1 = 0x12, - FUSB302_TKN_SYNC2 = 0x13, - FUSB302_TKN_SYNC3 = 0x1B, - FUSB302_TKN_RST1 = 0x15, - FUSB302_TKN_RST2 = 0x16, - FUSB302_TKN_PACKSYM = 0x80, - FUSB302_TKN_JAMCRC = 0xFF, - FUSB302_TKN_EOP = 0x14, - FUSB302_TKN_TXOFF = 0xFE, -}; - -extern const struct tcpm_drv fusb302_tcpm_drv; - -#endif /* __CROS_EC_DRIVER_TCPM_FUSB302_H */ diff --git a/driver/tcpm/fusb307.c b/driver/tcpm/fusb307.c deleted file mode 100644 index e8804a2661..0000000000 --- a/driver/tcpm/fusb307.c +++ /dev/null @@ -1,103 +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. - */ - -/* Type-C port manager for Fairchild's FUSB307 */ - -#include "console.h" -#include "fusb307.h" -#include "hooks.h" -#include "task.h" -#include "tcpm/tcpci.h" -#include "tcpm/tcpm.h" -#include "timer.h" -#include "util.h" - -#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) -#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) - -int fusb307_power_supply_reset(int port) -{ - return tcpc_write(port, TCPC_REG_COMMAND, 0x66); -} - -static int fusb307_tcpm_init(int port) -{ - int rv; - - rv = tcpci_tcpm_init(port); - - rv = tcpci_set_role_ctrl(port, TYPEC_DRP, TYPEC_RP_USB, TYPEC_CC_RD); - pd_set_dual_role(port, PD_DRP_TOGGLE_ON); - - return rv; -} - -int fusb307_tcpm_set_polarity(int port, enum tcpc_cc_polarity polarity) -{ - int rv; - enum tcpc_cc_voltage_status cc1, cc2; - - rv = tcpci_tcpm_set_polarity(port, polarity); - - tcpm_get_cc(port, &cc1, &cc2); - if (cc1) { - if (pd_get_power_role(port) == PD_ROLE_SINK) { - int role = TCPC_REG_ROLE_CTRL_SET(0, - tcpci_get_cached_rp(port), TYPEC_CC_RD, TYPEC_CC_OPEN); - - tcpc_write(port, TCPC_REG_ROLE_CTRL, role); - } else { - int role = TCPC_REG_ROLE_CTRL_SET(0, - tcpci_get_cached_rp(port), TYPEC_CC_RP, TYPEC_CC_OPEN); - - tcpc_write(port, TCPC_REG_ROLE_CTRL, role); - } - } else if (cc2) { - if (pd_get_power_role(port) == PD_ROLE_SINK) { - int role = TCPC_REG_ROLE_CTRL_SET(0, - tcpci_get_cached_rp(port), TYPEC_CC_OPEN, TYPEC_CC_RD); - - tcpc_write(port, TCPC_REG_ROLE_CTRL, role); - } else { - int role = TCPC_REG_ROLE_CTRL_SET(0, - tcpci_get_cached_rp(port), TYPEC_CC_OPEN, TYPEC_CC_RP); - - tcpc_write(port, TCPC_REG_ROLE_CTRL, role); - } - } else { - if (pd_get_power_role(port) == PD_ROLE_SINK) - tcpci_tcpm_set_cc(port, TYPEC_CC_RD); - else - tcpci_tcpm_set_cc(port, TYPEC_CC_RP); - } - - return rv; -} - -const struct tcpm_drv fusb307_tcpm_drv = { - .init = &fusb307_tcpm_init, - .release = &tcpci_tcpm_release, - .get_cc = &tcpci_tcpm_get_cc, -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - .check_vbus_level = &tcpci_tcpm_check_vbus_level, -#endif - .select_rp_value = &tcpci_tcpm_select_rp_value, - .set_cc = &tcpci_tcpm_set_cc, - .set_polarity = &fusb307_tcpm_set_polarity, - .set_vconn = &tcpci_tcpm_set_vconn, - .set_msg_header = &tcpci_tcpm_set_msg_header, - .set_rx_enable = &tcpci_tcpm_set_rx_enable, - .get_message_raw = &tcpci_tcpm_get_message_raw, - .transmit = &tcpci_tcpm_transmit, - .tcpc_alert = &tcpci_tcpc_alert, - .tcpc_enable_auto_discharge_disconnect = - &tcpci_tcpc_enable_auto_discharge_disconnect, - .get_chip_info = &tcpci_get_chip_info, -#if defined(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE) - .drp_toggle = &tcpci_tcpc_drp_toggle, -#endif - .set_bist_test_mode = &tcpci_set_bist_test_mode, -}; - diff --git a/driver/tcpm/fusb307.h b/driver/tcpm/fusb307.h deleted file mode 100644 index 3f1f12901d..0000000000 --- a/driver/tcpm/fusb307.h +++ /dev/null @@ -1,28 +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. - */ - -/* USB Power delivery port management */ -/* For Fairchild FUSB307 */ -#ifndef __CROS_EC_FUSB307_H -#define __CROS_EC_FUSB307_H - -#include "usb_pd.h" - -#define FUSB307_I2C_ADDR_FLAGS 0x50 - -#define TCPC_REG_RESET 0xA2 -#define TCPC_REG_RESET_PD_RESET BIT(1) -#define TCPC_REG_RESET_SW_RESET BIT(0) - -#define TCPC_REG_GPIO1_CFG 0xA4 -#define TCPC_REG_GPIO1_CFG_GPO1_VAL BIT(2) -#define TCPC_REG_GPIO1_CFG_GPI1_EN BIT(1) -#define TCPC_REG_GPIO1_CFG_GPO1_EN BIT(0) - -int fusb307_power_supply_reset(int port); - -extern const struct tcpm_drv fusb307_tcpm_drv; - -#endif /* __CROS_EC_FUSB307_H */ diff --git a/driver/tcpm/it83xx.c b/driver/tcpm/it83xx.c deleted file mode 100644 index 7bd2913bd7..0000000000 --- a/driver/tcpm/it83xx.c +++ /dev/null @@ -1,910 +0,0 @@ -/* Copyright 2016 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. - */ - -/* TCPM for MCU also running TCPC */ - -#include "common.h" -#include "config.h" -#include "console.h" -#include "it83xx_pd.h" -#include "registers.h" -#include "system.h" -#include "task.h" -#include "tcpm/tcpci.h" -#include "timer.h" -#include "util.h" -#include "usb_common.h" -#include "usb_pd.h" -#include "usb_pd_tcpm.h" -#include "hooks.h" - -#ifdef CONFIG_USB_PD_TCPMV1 -#if defined(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE) || \ - defined(CONFIG_USB_PD_VBUS_DETECT_TCPC) || \ - defined(CONFIG_USB_PD_TCPC_LOW_POWER) || \ - defined(CONFIG_USB_PD_DISCHARGE_TCPC) -#error "Unsupported config options of IT83xx PD driver" -#endif -#endif - -#ifdef CONFIG_USB_PD_TCPMV2 -#if defined(CONFIG_USB_PD_VBUS_DETECT_TCPC) || \ - defined(CONFIG_USB_PD_DISCHARGE_TCPC) -#error "Unsupported config options of IT83xx PD driver" -#endif -#endif - -int rx_en[IT83XX_USBPD_PHY_PORT_COUNT]; -STATIC_IF(CONFIG_USB_PD_DECODE_SOP) - bool sop_prime_en[IT83XX_USBPD_PHY_PORT_COUNT]; - -const struct usbpd_ctrl_t usbpd_ctrl_regs[] = { - {&IT83XX_GPIO_GPCRF4, &IT83XX_GPIO_GPCRF5, IT83XX_IRQ_USBPD0}, - {&IT83XX_GPIO_GPCRH1, &IT83XX_GPIO_GPCRH2, IT83XX_IRQ_USBPD1}, -}; -BUILD_ASSERT(ARRAY_SIZE(usbpd_ctrl_regs) == IT83XX_USBPD_PHY_PORT_COUNT); - -static int it83xx_tcpm_set_rx_enable(int port, int enable); -static int it83xx_tcpm_set_vconn(int port, int enable); - -/* - * Disable cc analog and pd digital module, but only left Rd_5.1K (Not - * Dead Battery) analog module alive to assert Rd on CCs. EC reset or - * calling _init() are able to re-active cc and pd. - */ -void it83xx_Rd_5_1K_only_for_hibernate(int port) -{ - /* This only apply to active PD port */ - if (*usbpd_ctrl_regs[port].cc1 == IT83XX_USBPD_CC_PIN_CONFIG && - *usbpd_ctrl_regs[port].cc2 == IT83XX_USBPD_CC_PIN_CONFIG) { - /* Disable PD PHY */ - IT83XX_USBPD_GCR(port) &= ~(BIT(0) | BIT(4)); - /* - * Disable CCs voltage detector, and - * connect CCs analog module (ex.UP/RD/DET/TX/RX), and - * connect CCs 5.1K to GND - */ - IT83XX_USBPD_CCCSR(port) = 0x22; - /* Disconnect CCs 5V tolerant */ - IT83XX_USBPD_CCPSR(port) |= - (USBPD_REG_MASK_DISCONNECT_POWER_CC2 | - USBPD_REG_MASK_DISCONNECT_POWER_CC1); - /* - * Select Rp reserved value for not current leakage, and - * CCs assert Rd, and - * enable CCs analog module - */ - IT83XX_USBPD_BMCSR(port) &= ~0x08; - IT83XX_USBPD_CCGCR(port) &= ~0x1f; - } -} - -static enum tcpc_cc_voltage_status it83xx_get_cc( - enum usbpd_port port, - enum usbpd_cc_pin cc_pin) -{ - enum usbpd_ufp_volt_status ufp_volt; - enum usbpd_dfp_volt_status dfp_volt; - enum tcpc_cc_voltage_status cc_state = TYPEC_CC_VOLT_OPEN; - int pull; - - pull = (cc_pin == USBPD_CC_PIN_1) ? - USBPD_GET_CC1_PULL_REGISTER_SELECTION(port) : - USBPD_GET_CC2_PULL_REGISTER_SELECTION(port); - - /* select Rp */ - if (pull) - CLEAR_MASK(cc_state, BIT(2)); - /* select Rd */ - else - SET_MASK(cc_state, BIT(2)); - - /* sink */ - if (USBPD_GET_POWER_ROLE(port) == USBPD_POWER_ROLE_CONSUMER) { - if (cc_pin == USBPD_CC_PIN_1) - ufp_volt = IT83XX_USBPD_UFPVDR(port) & 0x7; - else - ufp_volt = (IT83XX_USBPD_UFPVDR(port) >> 4) & 0x7; - - switch (ufp_volt) { - case USBPD_UFP_STATE_SNK_DEF: - cc_state |= (TYPEC_CC_VOLT_RP_DEF & 3); - break; - case USBPD_UFP_STATE_SNK_1_5: - cc_state |= (TYPEC_CC_VOLT_RP_1_5 & 3); - break; - case USBPD_UFP_STATE_SNK_3_0: - cc_state |= (TYPEC_CC_VOLT_RP_3_0 & 3); - break; - case USBPD_UFP_STATE_SNK_OPEN: - cc_state = TYPEC_CC_VOLT_OPEN; - break; - default: - cc_state = TYPEC_CC_VOLT_OPEN; - break; - } - /* source */ - } else { - if (cc_pin == USBPD_CC_PIN_1) - dfp_volt = IT83XX_USBPD_DFPVDR(port) & 0xf; - else - dfp_volt = (IT83XX_USBPD_DFPVDR(port) >> 4) & 0xf; - - switch (dfp_volt) { - case USBPD_DFP_STATE_SRC_RA: - cc_state |= TYPEC_CC_VOLT_RA; - break; - case USBPD_DFP_STATE_SRC_RD: - cc_state |= TYPEC_CC_VOLT_RD; - break; - case USBPD_DFP_STATE_SRC_OPEN: - cc_state = TYPEC_CC_VOLT_OPEN; - break; - default: - cc_state = TYPEC_CC_VOLT_OPEN; - break; - } - } - - return cc_state; -} - -static int it83xx_tcpm_get_message_raw(int port, uint32_t *buf, int *head) -{ - int cnt = PD_HEADER_CNT(IT83XX_USBPD_RMH(port)); - - if (!USBPD_IS_RX_DONE(port)) - return EC_ERROR_UNKNOWN; - - /* store header */ - *head = IT83XX_USBPD_RMH(port); - /* check data message */ - if (cnt) - memcpy(buf, (uint32_t *)&IT83XX_USBPD_RDO0(port), cnt * 4); - - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) { - int type = USBPD_REG_GET_SOP_TYPE_RX(IT83XX_USBPD_MRSR(port)); - *head |= PD_HEADER_SOP(type); - } - /* - * Note: clear RX done interrupt after get the data. - * If clear this bit, USBPD receives next packet - */ - IT83XX_USBPD_MRSR(port) = USBPD_REG_MASK_RX_MSG_VALID; - - return EC_SUCCESS; -} - -static enum tcpc_transmit_complete it83xx_tx_data( - enum usbpd_port port, - enum tcpci_msg_type type, - uint16_t header, - const uint32_t *buf) -{ - int r; - uint32_t evt; - uint8_t length = PD_HEADER_CNT(header); - - /* set message header */ - IT83XX_USBPD_TMHLR(port) = (uint8_t)header; - IT83XX_USBPD_TMHHR(port) = (header >> 8); - - /* - * SOP type bit[6~4]: - * on bx version and before: - * x00b=SOP, x01b=SOP', x10b=SOP", bit[6] is reserved. - * on dx version: - * 000b=SOP, 001b=SOP', 010b=SOP", 011b=Debug SOP', 100b=Debug SOP''. - */ - IT83XX_USBPD_MTSR1(port) = - (IT83XX_USBPD_MTSR1(port) & ~0x70) | ((type & 0x7) << 4); - /* bit7: transmit message is send to cable or not */ - if (type == TCPCI_MSG_SOP) - IT83XX_USBPD_MTSR0(port) &= ~USBPD_REG_MASK_CABLE_ENABLE; - else - IT83XX_USBPD_MTSR0(port) |= USBPD_REG_MASK_CABLE_ENABLE; - /* clear msg length */ - IT83XX_USBPD_MTSR1(port) &= (~0x7); - /* Limited by PD_HEADER_CNT() */ - ASSERT(length <= 0x7); - - if (length) { - /* set data bit */ - IT83XX_USBPD_MTSR0(port) |= BIT(4); - /* set data length setting */ - IT83XX_USBPD_MTSR1(port) |= length; - /* set data */ - memcpy((uint32_t *)&IT83XX_USBPD_TDO(port), buf, length * 4); - } - - for (r = 0; r <= CONFIG_PD_RETRY_COUNT; r++) { - /* Start TX */ - USBPD_KICK_TX_START(port); - evt = task_wait_event_mask(TASK_EVENT_PHY_TX_DONE, - PD_T_TCPC_TX_TIMEOUT); - /* check TX status */ - if (USBPD_IS_TX_ERR(port) || (evt & TASK_EVENT_TIMER)) { - /* - * If discard, means HW doesn't send the msg and resend. - */ - if (USBPD_IS_TX_DISCARD(port)) - continue; - /* - * Or port partner doesn't respond GoodCRC - */ - else - return TCPC_TX_COMPLETE_FAILED; - } else { - break; - } - } - - if (r > CONFIG_PD_RETRY_COUNT) - return TCPC_TX_COMPLETE_DISCARDED; - - return TCPC_TX_COMPLETE_SUCCESS; -} - -static enum tcpc_transmit_complete it83xx_send_hw_reset(enum usbpd_port port, - enum tcpci_msg_type reset_type) -{ - if (reset_type == TCPCI_MSG_CABLE_RESET) - IT83XX_USBPD_MTSR0(port) |= USBPD_REG_MASK_CABLE_ENABLE; - else - IT83XX_USBPD_MTSR0(port) &= ~USBPD_REG_MASK_CABLE_ENABLE; - - /* send hard reset */ - USBPD_SEND_HARD_RESET(port); - usleep(MSEC); - - if (USBPD_IS_HARD_CABLE_RESET_TX_DONE(port)) { - IT83XX_USBPD_ISR(port) = - USBPD_REG_MASK_HARD_CABLE_RESET_TX_DONE; - return TCPC_TX_COMPLETE_SUCCESS; - } - - return TCPC_TX_COMPLETE_FAILED; -} - -static void it83xx_send_bist_mode2_pattern(enum usbpd_port port) -{ - USBPD_ENABLE_SEND_BIST_MODE_2(port); - usleep(PD_T_BIST_TRANSMIT); - USBPD_DISABLE_SEND_BIST_MODE_2(port); -} - -static void it83xx_enable_vconn(enum usbpd_port port, int enabled) -{ - enum usbpd_cc_pin cc_pin; - - if (USBPD_GET_PULL_CC_SELECTION(port)) - cc_pin = USBPD_CC_PIN_1; - else - cc_pin = USBPD_CC_PIN_2; - - if (enabled) { - /* Disable unused CC to become VCONN */ - if (cc_pin == USBPD_CC_PIN_1) { - IT83XX_USBPD_CCCSR(port) = USBPD_CC2_DISCONNECTED(port); - IT83XX_USBPD_CCPSR(port) = (IT83XX_USBPD_CCPSR(port) - & ~USBPD_REG_MASK_DISCONNECT_POWER_CC2) - | USBPD_REG_MASK_DISCONNECT_POWER_CC1; - } else { - IT83XX_USBPD_CCCSR(port) = USBPD_CC1_DISCONNECTED(port); - IT83XX_USBPD_CCPSR(port) = (IT83XX_USBPD_CCPSR(port) - & ~USBPD_REG_MASK_DISCONNECT_POWER_CC1) - | USBPD_REG_MASK_DISCONNECT_POWER_CC2; - } - } else { - /* Enable cc1 and cc2 */ - IT83XX_USBPD_CCCSR(port) &= ~0xaa; - IT83XX_USBPD_CCPSR(port) |= - (USBPD_REG_MASK_DISCONNECT_POWER_CC1 | - USBPD_REG_MASK_DISCONNECT_POWER_CC2); - } -} - -static void it83xx_enable_cc(enum usbpd_port port, int enable) -{ - if (enable) - CLEAR_MASK(IT83XX_USBPD_CCGCR(port), BIT(4)); - else - SET_MASK(IT83XX_USBPD_CCGCR(port), BIT(4)); -} - -static void it83xx_set_power_role(enum usbpd_port port, int power_role) -{ - /* PD_ROLE_SINK 0, PD_ROLE_SOURCE 1 */ - if (power_role == PD_ROLE_SOURCE) { - /* - * bit[2,3] BMC Rx threshold setting - * 00b: power neutral - * 01b: sinking power => - * High to low Y3Rx threshold = 0.38, - * Low to high Y3Rx threshold = 0.54. - * 10b: sourcing power => - * High to low Y3Rx threshold = 0.64, - * Low to high Y3Rx threshold = 0.79. - */ - IT83XX_USBPD_CCADCR(port) = 0x08; - /* bit0: source */ - SET_MASK(IT83XX_USBPD_PDMSR(port), BIT(0)); - /* bit1: CC1 select Rp */ - SET_MASK(IT83XX_USBPD_CCGCR(port), BIT(1)); - /* bit3: CC2 select Rp */ - SET_MASK(IT83XX_USBPD_BMCSR(port), BIT(3)); - } else { - /* - * bit[2,3] BMC Rx threshold setting - * 00b: power neutral - * 01b: sinking power => - * High to low Y3Rx threshold = 0.38, - * Low to high Y3Rx threshold = 0.54 - * 10b: sourcing power => - * High to low Y3Rx threshold = 0.64, - * Low to high Y3Rx threshold = 0.79 - */ - IT83XX_USBPD_CCADCR(port) = 0x04; - /* bit0: sink */ - CLEAR_MASK(IT83XX_USBPD_PDMSR(port), BIT(0)); - /* bit1: CC1 select Rd */ - CLEAR_MASK(IT83XX_USBPD_CCGCR(port), BIT(1)); - /* bit3: CC2 select Rd */ - CLEAR_MASK(IT83XX_USBPD_BMCSR(port), BIT(3)); - } -} - -static void it83xx_set_data_role(enum usbpd_port port, int pd_role) -{ - /* 0: PD_ROLE_UFP 1: PD_ROLE_DFP */ - IT83XX_USBPD_PDMSR(port) = - (IT83XX_USBPD_PDMSR(port) & ~0xc) | ((pd_role & 0x1) << 2); -} - -#ifdef CONFIG_USB_PD_FRS_TCPC -static int it83xx_tcpm_set_frs_enable(int port, int enable) -{ - uint8_t mask = (USBPD_REG_FAST_SWAP_REQUEST_ENABLE | - USBPD_REG_FAST_SWAP_DETECT_ENABLE); - - if (enable) { - /* - * Disable HW auto turn off FRS requestion and detection - * when we receive soft or hard reset. - */ - IT83XX_USBPD_PDPSR(port) &= ~USBPD_REG_MASK_AUTO_FRS_DISABLE; - /* W/C status */ - IT83XX_USBPD_PD30IR(port) = 0x3f; - /* Enable FRS detection (cc to GND) interrupt */ - IT83XX_USBPD_MPD30IR(port) &= ~(USBPD_REG_MASK_PD30_ISR | - USBPD_REG_MASK_FAST_SWAP_DETECT_ISR); - /* Enable FRS detection (cc to GND) */ - IT83XX_USBPD_PDQSCR(port) = (IT83XX_USBPD_PDQSCR(port) & ~mask) - | USBPD_REG_FAST_SWAP_DETECT_ENABLE; - } else { - /* Disable FRS detection (cc to GND) interrupt */ - IT83XX_USBPD_MPD30IR(port) |= (USBPD_REG_MASK_PD30_ISR | - USBPD_REG_MASK_FAST_SWAP_DETECT_ISR); - /* Disable FRS detection and requestion */ - IT83XX_USBPD_PDQSCR(port) &= ~mask; - } - - return EC_SUCCESS; -} -#endif - -static void it83xx_init(enum usbpd_port port, int role) -{ -#ifdef IT83XX_USBPD_CC_PARAMETER_RELOAD - /* bit7: Reload CC parameter setting. */ - IT83XX_USBPD_CCPSR0(port) |= BIT(7); -#endif - /* reset and disable HW auto generate message header */ - IT83XX_USBPD_GCR(port) = BIT(5); - USBPD_SW_RESET(port); - /* - * According PD version set the total number of HW attempts - * (= retry count + 1) - */ - IT83XX_USBPD_BMCSR(port) = (IT83XX_USBPD_BMCSR(port) & ~0x70) | - ((CONFIG_PD_RETRY_COUNT + 1) << 4); - /* Disable Rx decode */ - it83xx_tcpm_set_rx_enable(port, 0); - if (IS_ENABLED(CONFIG_USB_PD_TCPMV1)) { - uint8_t flags = 0; - /* - * If explicit contract is set in bbram when EC boot up, then - * TCPMv1 set soft reset as first state instead of - * unattached.SNK, so we need to enable BMC PHY for tx module. - * - * NOTE: If the platform is without battery and connects to - * adapter, then cold reset EC, our Rd is always asserted on cc, - * so adapter keeps providing 5v and data in BBRAM are still - * alive. - */ - if ((pd_get_saved_port_flags(port, &flags) == EC_SUCCESS) && - (flags & PD_BBRMFLG_EXPLICIT_CONTRACT)) - USBPD_ENABLE_BMC_PHY(port); - } - /* W/C status */ - IT83XX_USBPD_ISR(port) = 0xff; - /* enable cc, select cc1 and Rd. */ - IT83XX_USBPD_CCGCR(port) = 0xd; - /* change data role as the same power role */ - it83xx_set_data_role(port, role); - /* set power role */ - it83xx_set_power_role(port, role); - /* disable all interrupts */ - IT83XX_USBPD_IMR(port) = 0xff; - /* enable tx done and reset detect interrupt */ - IT83XX_USBPD_IMR(port) &= ~(USBPD_REG_MASK_MSG_TX_DONE | - USBPD_REG_MASK_HARD_RESET_DETECT); -#ifdef IT83XX_INTC_PLUG_IN_OUT_SUPPORT - /* - * when tcpc detect type-c plug in (cc lines voltage change), it will - * interrupt fw to wake pd task, so task can react immediately. - * - * w/c status and unmask TCDCR (detect type-c plug in interrupt default - * is enable). - */ - IT83XX_USBPD_TCDCR(port) = USBPD_REG_PLUG_IN_OUT_DETECT_STAT; -#endif - /* cc connect */ - IT83XX_USBPD_CCCSR(port) = 0; - /* disable vconn */ - it83xx_tcpm_set_vconn(port, 0); - /* TX start from high */ - IT83XX_USBPD_CCADCR(port) |= BIT(6); - /* enable cc1/cc2 */ - *usbpd_ctrl_regs[port].cc1 = IT83XX_USBPD_CC_PIN_CONFIG; - *usbpd_ctrl_regs[port].cc2 = IT83XX_USBPD_CC_PIN_CONFIG; - task_clear_pending_irq(usbpd_ctrl_regs[port].irq); - task_enable_irq(usbpd_ctrl_regs[port].irq); - USBPD_START(port); - /* - * Disconnect CCs Rd_DB from GND - * NOTE: CCs assert both Rd_5.1k and Rd_DB from USBPD_START() to - * disconnect Rd_DB about 1.5us. - */ - IT83XX_USBPD_CCPSR(port) |= (USBPD_REG_MASK_DISCONNECT_5_1K_CC2_DB | - USBPD_REG_MASK_DISCONNECT_5_1K_CC1_DB); -} - -static void it83xx_select_polarity(enum usbpd_port port, - enum usbpd_cc_pin cc_pin) -{ - /* cc1/cc2 selection */ - if (cc_pin == USBPD_CC_PIN_1) - SET_MASK(IT83XX_USBPD_CCGCR(port), BIT(0)); - else - CLEAR_MASK(IT83XX_USBPD_CCGCR(port), BIT(0)); -} - -static int it83xx_set_cc(enum usbpd_port port, int pull) -{ - int enable_cc = 1; - - switch (pull) { - case TYPEC_CC_RD: - it83xx_set_power_role(port, PD_ROLE_SINK); - break; - case TYPEC_CC_RP: - it83xx_set_power_role(port, PD_ROLE_SOURCE); - break; - case TYPEC_CC_OPEN: - /* Power-down CC1 & CC2 to remove Rp/Rd */ - enable_cc = 0; - break; - default: - return EC_ERROR_UNIMPLEMENTED; - } - - it83xx_enable_cc(port, enable_cc); - return EC_SUCCESS; -} - -static int it83xx_tcpm_init(int port) -{ - /* Initialize physical layer */ - it83xx_init(port, PD_ROLE_DEFAULT(port)); - - return EC_SUCCESS; -} - -static int it83xx_tcpm_release(int port) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -static int it83xx_tcpm_get_cc(int port, enum tcpc_cc_voltage_status *cc1, - enum tcpc_cc_voltage_status *cc2) -{ - *cc2 = it83xx_get_cc(port, USBPD_CC_PIN_2); - *cc1 = it83xx_get_cc(port, USBPD_CC_PIN_1); - - return EC_SUCCESS; -} - -static int it83xx_tcpm_select_rp_value(int port, int rp_sel) -{ - uint8_t rp; - - /* Keep track of current RP value */ - tcpci_set_cached_rp(port, rp_sel); - - /* - * bit[3-2]: CC output current (when Rp selected) - * 00: reserved - * 01: 330uA outpt (3.0A) - * 10: 180uA outpt (1.5A) - * 11: 80uA outpt (USB default) - */ - switch (rp_sel) { - case TYPEC_RP_1A5: - rp = 2 << 2; - break; - case TYPEC_RP_3A0: - rp = BIT(2); - break; - case TYPEC_RP_USB: - default: - rp = 3 << 2; - break; - } - IT83XX_USBPD_CCGCR(port) = (IT83XX_USBPD_CCGCR(port) & ~(3 << 2)) | rp; - - return EC_SUCCESS; -} - -static int it83xx_tcpm_set_cc(int port, int pull) -{ - return it83xx_set_cc(port, pull); -} - -static int it83xx_tcpm_set_polarity(int port, enum tcpc_cc_polarity polarity) -{ - enum usbpd_cc_pin cc_pin = - (polarity == POLARITY_CC1 || polarity == POLARITY_CC1_DTS) ? - USBPD_CC_PIN_1 : USBPD_CC_PIN_2; - - it83xx_select_polarity(port, cc_pin); - - return EC_SUCCESS; -} - -__maybe_unused static int it83xx_tcpm_decode_sop_prime_enable(int port, - bool enable) -{ - /* Save SOP'/SOP'' enable state */ - sop_prime_en[port] = enable; - - if (rx_en[port]) { - if (enable) - IT83XX_USBPD_PDMSR(port) |= - (USBPD_REG_MASK_SOPP_ENABLE | - USBPD_REG_MASK_SOPPP_ENABLE); - else - IT83XX_USBPD_PDMSR(port) &= - ~(USBPD_REG_MASK_SOPP_ENABLE | - USBPD_REG_MASK_SOPPP_ENABLE); - } - - return EC_SUCCESS; -} - -static int it83xx_tcpm_set_vconn(int port, int enable) -{ - /* - * IT83XX doesn't have integrated circuit to source CC lines for VCONN. - * An external device like PPC or Power Switch has to source the VCONN. - */ - if (IS_ENABLED(CONFIG_USBC_VCONN)) { - if (enable) { - /* - * Unused cc will become Vconn SRC, disable cc analog - * module (ex.UP/RD/DET/Tx/Rx) and enable 5v tolerant. - */ - it83xx_enable_vconn(port, enable); - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) - /* Enable tcpc receive SOP' and SOP'' packet */ - it83xx_tcpm_decode_sop_prime_enable(port, true); - /* Turn on Vconn power switch. */ - board_pd_vconn_ctrl(port, - USBPD_GET_PULL_CC_SELECTION(port) ? - USBPD_CC_PIN_2 : USBPD_CC_PIN_1, - enable); - } else { - /* - * If the pd port has previous connection and supplies - * Vconn, then RO jumping to RW reset the system, - * we never know which cc is the previous Vconn pin, - * so we always turn both cc pins off when disable - * Vconn power switch. - */ - board_pd_vconn_ctrl(port, USBPD_CC_PIN_1, enable); - board_pd_vconn_ctrl(port, USBPD_CC_PIN_2, enable); - /* Disable tcpc receive SOP' and SOP'' packet */ - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) - it83xx_tcpm_decode_sop_prime_enable(port, - false); - /* - * Before disabling cc 5v tolerant, we need to make - * sure cc voltage detector is enabled and Vconn is - * dropped below 3.3v (>500us) to avoid the potential - * risk of voltage fed back into Vcore. - */ - usleep(IT83XX_USBPD_T_VCONN_BELOW_3_3V); - /* - * Since our cc are not Vconn SRC, enable cc analog - * module (ex.UP/RD/DET/Tx/Rx) and disable 5v tolerant. - */ - it83xx_enable_vconn(port, enable); - } - } - - return EC_SUCCESS; -} - -static int it83xx_tcpm_set_msg_header(int port, int power_role, int data_role) -{ - /* PD_ROLE_SINK 0, PD_ROLE_SOURCE 1 */ - if (power_role == PD_ROLE_SOURCE) - /* bit0: source */ - SET_MASK(IT83XX_USBPD_PDMSR(port), BIT(0)); - else - /* bit0: sink */ - CLEAR_MASK(IT83XX_USBPD_PDMSR(port), BIT(0)); - - it83xx_set_data_role(port, data_role); - - return EC_SUCCESS; -} - -static int it83xx_tcpm_set_rx_enable(int port, int enable) -{ - /* Save rx_on */ - rx_en[port] = enable; - - if (enable) { - IT83XX_USBPD_IMR(port) &= ~USBPD_REG_MASK_MSG_RX_DONE; - IT83XX_USBPD_PDMSR(port) |= USBPD_REG_MASK_SOP_ENABLE; - IT83XX_USBPD_VDMMCSR(port) |= USBPD_REG_MASK_HARD_RESET_DECODE; - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) - it83xx_tcpm_decode_sop_prime_enable(port, - sop_prime_en[port]); - } else { - IT83XX_USBPD_IMR(port) |= USBPD_REG_MASK_MSG_RX_DONE; - IT83XX_USBPD_PDMSR(port) &= ~(USBPD_REG_MASK_SOP_ENABLE | - USBPD_REG_MASK_SOPP_ENABLE | - USBPD_REG_MASK_SOPPP_ENABLE); - IT83XX_USBPD_VDMMCSR(port) &= ~USBPD_REG_MASK_HARD_RESET_DECODE; - } - - return EC_SUCCESS; -} - -static int it83xx_tcpm_transmit(int port, - enum tcpci_msg_type type, - uint16_t header, - const uint32_t *data) -{ - int status = TCPC_TX_COMPLETE_FAILED; - - switch (type) { - case TCPCI_MSG_SOP: - case TCPCI_MSG_SOP_PRIME: - case TCPCI_MSG_SOP_PRIME_PRIME: - case TCPCI_MSG_SOP_DEBUG_PRIME: - case TCPCI_MSG_SOP_DEBUG_PRIME_PRIME: - status = it83xx_tx_data(port, - type, - header, - data); - break; - case TCPCI_MSG_TX_BIST_MODE_2: - it83xx_send_bist_mode2_pattern(port); - status = TCPC_TX_COMPLETE_SUCCESS; - break; - case TCPCI_MSG_TX_HARD_RESET: - case TCPCI_MSG_CABLE_RESET: - status = it83xx_send_hw_reset(port, type); - break; - default: - status = TCPC_TX_COMPLETE_FAILED; - break; - } - pd_transmit_complete(port, status); - - return EC_SUCCESS; -} - -static int it83xx_tcpm_get_chip_info(int port, int live, - struct ec_response_pd_chip_info_v1 *chip_info) -{ - chip_info->vendor_id = USB_VID_ITE; - chip_info->product_id = ((IT83XX_GCTRL_CHIPID1 << 8) | - IT83XX_GCTRL_CHIPID2); - chip_info->device_id = IT83XX_GCTRL_CHIPVER & 0xf; - chip_info->fw_version_number = 0xEC; - - return EC_SUCCESS; -} - -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER -static int it83xx_tcpm_enter_low_power_mode(int port) -{ - /* - * ITE embedded TCPC SLEEP_MASK_USB_PD flag is only controlled by - * it83xx driver in set_pd_sleep_mask(), and do low power mode in - * idle_task(). - * In deep sleep mode, ITE TCPC clock is turned off, and the - * timer every 5ms to exit the mode and wakeup PD task to run - * (ex. change the CC lines termination). - */ - return EC_SUCCESS; -} -#endif - -static void it83xx_tcpm_switch_plug_out_type(int port) -{ - enum tcpc_cc_voltage_status cc1, cc2; - - /* Check what do we and partner cc assert */ - it83xx_tcpm_get_cc(port, &cc1, &cc2); - - if ((cc1 == TYPEC_CC_VOLT_RD && cc2 == TYPEC_CC_VOLT_RD) || - (cc1 == TYPEC_CC_VOLT_RA && cc2 == TYPEC_CC_VOLT_RA)) - /* We're source, switch to detect audio/debug plug out. */ - IT83XX_USBPD_TCDCR(port) = (IT83XX_USBPD_TCDCR(port) & - ~USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE) | - USBPD_REG_PLUG_OUT_DETECT_TYPE_SELECT | - USBPD_REG_PLUG_OUT_SELECT; - else if (cc1 == TYPEC_CC_VOLT_RD || cc2 == TYPEC_CC_VOLT_RD) - /* We're source, switch to detect sink plug out. */ - IT83XX_USBPD_TCDCR(port) = (IT83XX_USBPD_TCDCR(port) & - ~USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE & - ~USBPD_REG_PLUG_OUT_DETECT_TYPE_SELECT) | - USBPD_REG_PLUG_OUT_SELECT; - else if (cc1 >= TYPEC_CC_VOLT_RP_DEF || cc2 >= TYPEC_CC_VOLT_RP_DEF) - /* - * We're sink, disable detect interrupt, so messages on cc line - * won't trigger interrupt. - * NOTE: Plug out is detected by TCPM polling Vbus. - */ - IT83XX_USBPD_TCDCR(port) |= - USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE; - /* - * If not above cases, plug in interrupt will fire again, - * and call switch_plug_out_type() to set the right state. - */ -} - -void switch_plug_out_type(enum usbpd_port port) -{ - it83xx_tcpm_switch_plug_out_type(port); -} - -void set_pd_sleep_mask(int port) -{ - int i; - bool prevent_deep_sleep = false; - - /* - * Set SLEEP_MASK_USB_PD for deep sleep mode: - * 1.Enable deep sleep mode, when all ITE ports are in Unattach.SRC/SNK - * state (HOOK_DISCONNECT called) and other ports aren't pd_capable(). - * 2.Disable deep sleep mode, when one of ITE port is in Attach.SRC/SNK - * state (HOOK_CONNECT called) or one of other ports is pd_capable(). - */ - for (i = 0; i < CONFIG_USB_PD_ITE_ACTIVE_PORT_COUNT; ++i) { - if (IT83XX_USBPD_GCR(i) & USBPD_REG_MASK_BMC_PHY) { - prevent_deep_sleep = true; - break; - } - } - - /* - * Check if any other ports have a PD port partner connected. Deep - * sleep is forbidden if any PD port partner is connected. Above, we - * only checked for the ITE ports. - */ - if (!prevent_deep_sleep) { - for (; i < board_get_usb_pd_port_count(); i++) - if (pd_capable(i)) - prevent_deep_sleep = true; - } - - if (prevent_deep_sleep) - disable_sleep(SLEEP_MASK_USB_PD); - else - enable_sleep(SLEEP_MASK_USB_PD); -} - -static void it83xx_tcpm_hook_connect(void) -{ - int port = TASK_ID_TO_PD_PORT(task_get_current()); - -#ifdef CONFIG_USB_PD_TCPMV2 - /* - * There are five cases that hook_connect() be called by TCPMv2: - * 1)AttachWait.SNK -> Attached.SNK: disable detect interrupt. - * 2)AttachWait.SRC -> Attached.SRC: enable detect plug out. - * 3)AttachWait.SNK -> Try.SRC -> TryWait.SNK -> Attached.SNK: we do - * Try.SRC fail, disable detect interrupt. - * 4)AttachWait.SNK -> Try.SRC -> Attached.SRC: we do Try.SRC - * successfully, need to switch to detect plug out. - * 5)Attached.SRC -> TryWait.SNK -> Attached.SNK: partner do Try.SRC - * successfully, disable detect interrupt. - * - * NOTE: Try.SRC and TryWait.SNK are embedded respectively in - * SRC_DISCONNECT and SNK_DISCONNECT in TCPMv1. Every time we go to - * Try.SRC/TryWait.SNK state, the plug in interrupt will be enabled and - * fire for 3), 4), 5) cases, then set correctly for the SRC detect plug - * out or the SNK disable detect, so TCPMv1 needn't this. - */ - it83xx_tcpm_switch_plug_out_type(port); -#endif - /* Enable PD PHY Tx and Rx module since type-c has connected. */ - USBPD_ENABLE_BMC_PHY(port); - set_pd_sleep_mask(port); -} - -DECLARE_HOOK(HOOK_USB_PD_CONNECT, it83xx_tcpm_hook_connect, HOOK_PRIO_DEFAULT); - -static void it83xx_tcpm_hook_disconnect(void) -{ - int port = TASK_ID_TO_PD_PORT(task_get_current()); - - if (IS_ENABLED(IT83XX_INTC_PLUG_IN_OUT_SUPPORT)) - /* - * Switch to detect plug in and enable detect plug in interrupt, - * since pd task has detected a type-c physical disconnected. - */ - IT83XX_USBPD_TCDCR(port) &= ~(USBPD_REG_PLUG_OUT_SELECT | - USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE); - - /* exit BIST test data mode */ - USBPD_SW_RESET(port); - - /* - * Init rx status and disable PD PHY Tx and Rx module for better power - * consumption since type-c has disconnected. - */ - rx_en[port] = 0; - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) - sop_prime_en[port] = 0; - USBPD_DISABLE_BMC_PHY(port); - set_pd_sleep_mask(port); -} - -DECLARE_HOOK(HOOK_USB_PD_DISCONNECT, it83xx_tcpm_hook_disconnect, - HOOK_PRIO_DEFAULT); - -const struct tcpm_drv it83xx_tcpm_drv = { - .init = &it83xx_tcpm_init, - .release = &it83xx_tcpm_release, - .get_cc = &it83xx_tcpm_get_cc, - .select_rp_value = &it83xx_tcpm_select_rp_value, - .set_cc = &it83xx_tcpm_set_cc, - .set_polarity = &it83xx_tcpm_set_polarity, -#ifdef CONFIG_USB_PD_DECODE_SOP - .sop_prime_enable = &it83xx_tcpm_decode_sop_prime_enable, -#endif - .set_vconn = &it83xx_tcpm_set_vconn, - .set_msg_header = &it83xx_tcpm_set_msg_header, - .set_rx_enable = &it83xx_tcpm_set_rx_enable, - .get_message_raw = &it83xx_tcpm_get_message_raw, - .transmit = &it83xx_tcpm_transmit, -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - .drp_toggle = NULL, -#endif - .get_chip_info = &it83xx_tcpm_get_chip_info, -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER - .enter_low_power_mode = &it83xx_tcpm_enter_low_power_mode, -#endif -#ifdef CONFIG_USB_PD_FRS_TCPC - .set_frs_enable = &it83xx_tcpm_set_frs_enable, -#endif -}; diff --git a/driver/tcpm/it83xx_pd.h b/driver/tcpm/it83xx_pd.h deleted file mode 100644 index ff7c231f23..0000000000 --- a/driver/tcpm/it83xx_pd.h +++ /dev/null @@ -1,458 +0,0 @@ -/* Copyright 2016 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. - */ - -/* USB Power delivery port management */ -#ifndef __CROS_EC_DRIVER_TCPM_IT83XX_H -#define __CROS_EC_DRIVER_TCPM_IT83XX_H - -#include "driver/tcpm/it8xxx2_pd_public.h" - -/* USBPD Controller */ -#if defined(CONFIG_USB_PD_TCPM_DRIVER_IT83XX) -#define IT83XX_USBPD_BASE(port) (0x00F03700 + (0x100 * (port))) - -#define IT83XX_USBPD_GCR(p) REG8(IT83XX_USBPD_BASE(p)+0x0) -#define USBPD_REG_MASK_SW_RESET_BIT BIT(7) -#define USBPD_REG_MASK_TYPE_C_DETECT_RESET BIT(6) -#define USBPD_REG_MASK_BMC_PHY BIT(4) -#define USBPD_REG_MASK_AUTO_SEND_SW_RESET BIT(3) -#define USBPD_REG_MASK_AUTO_SEND_HW_RESET BIT(2) -#define USBPD_REG_MASK_SNIFFER_MODE BIT(1) -#define USBPD_REG_MASK_GLOBAL_ENABLE BIT(0) -#define IT83XX_USBPD_PDMSR(p) REG8(IT83XX_USBPD_BASE(p)+0x01) -#define USBPD_REG_MASK_SOPPP_ENABLE BIT(7) -#define USBPD_REG_MASK_SOPP_ENABLE BIT(6) -#define USBPD_REG_MASK_SOP_ENABLE BIT(5) -#define IT83XX_USBPD_CCGCR(p) REG8(IT83XX_USBPD_BASE(p)+0x04) -#define USBPD_REG_MASK_DISABLE_CC BIT(4) -#define IT83XX_USBPD_CCCSR(p) REG8(IT83XX_USBPD_BASE(p)+0x05) -#define USBPD_REG_MASK_CC2_DISCONNECT BIT(7) -#define USBPD_REG_MASK_CC2_DISCONNECT_5_1K_TO_GND BIT(6) -#define USBPD_REG_MASK_CC1_DISCONNECT BIT(3) -#define USBPD_REG_MASK_CC1_DISCONNECT_5_1K_TO_GND BIT(2) -#ifdef IT83XX_USBPD_CC_VOLTAGE_DETECTOR_INDEPENDENT -#define USBPD_REG_MASK_DISABLE_CC_VOL_DETECTOR (BIT(5) | BIT(1)) -#else -#define USBPD_REG_MASK_DISABLE_CC_VOL_DETECTOR BIT(1) -#endif -#define IT83XX_USBPD_CCPSR(p) REG8(IT83XX_USBPD_BASE(p)+0x06) -#define USBPD_REG_MASK_DISCONNECT_5_1K_CC2_DB BIT(6) -#define USBPD_REG_MASK_DISCONNECT_POWER_CC2 BIT(5) -#define USBPD_REG_MASK_DISCONNECT_5_1K_CC1_DB BIT(2) -#define USBPD_REG_MASK_DISCONNECT_POWER_CC1 BIT(1) -#define IT83XX_USBPD_DFPVDR(p) REG8(IT83XX_USBPD_BASE(p)+0x08) -#define IT83XX_USBPD_UFPVDR(p) REG8(IT83XX_USBPD_BASE(p)+0x09) -#define IT83XX_USBPD_PDPSR(p) REG8(IT83XX_USBPD_BASE(p)+0x0B) -#define USBPD_REG_MASK_AUTO_FRS_DISABLE BIT(7) -#define IT83XX_USBPD_CCADCR(p) REG8(IT83XX_USBPD_BASE(p)+0x0C) -#define IT83XX_USBPD_ISR(p) REG8(IT83XX_USBPD_BASE(p)+0x14) -#define USBPD_REG_MASK_TYPE_C_DETECT BIT(7) -#define USBPD_REG_MASK_CABLE_RESET_DETECT BIT(6) -#define USBPD_REG_MASK_HARD_RESET_DETECT BIT(5) -#define USBPD_REG_MASK_MSG_RX_DONE BIT(4) -#define USBPD_REG_MASK_AUTO_SOFT_RESET_TX_DONE BIT(3) -#define USBPD_REG_MASK_HARD_CABLE_RESET_TX_DONE BIT(2) -#define USBPD_REG_MASK_MSG_TX_DONE BIT(1) -#define USBPD_REG_MASK_TIMER_TIMEOUT BIT(0) -#define IT83XX_USBPD_IMR(p) REG8(IT83XX_USBPD_BASE(p)+0x15) -#define IT83XX_USBPD_MTCR(p) REG8(IT83XX_USBPD_BASE(p)+0x18) -#define USBPD_REG_MASK_SW_RESET_TX_STAT BIT(3) -#define USBPD_REG_MASK_TX_BUSY_STAT BIT(2) -#define USBPD_REG_MASK_TX_DISCARD_STAT BIT(2) -#ifdef IT83XX_PD_TX_ERROR_STATUS_BIT5 -#define USBPD_REG_MASK_TX_ERR_STAT BIT(5) -#else -#define USBPD_REG_MASK_TX_ERR_STAT BIT(1) -#endif -#define USBPD_REG_MASK_TX_START BIT(0) -#define IT83XX_USBPD_MTSR0(p) REG8(IT83XX_USBPD_BASE(p)+0x19) -#define USBPD_REG_MASK_CABLE_ENABLE BIT(7) -#define USBPD_REG_MASK_SEND_HW_RESET BIT(6) -#define USBPD_REG_MASK_SEND_BIST_MODE_2 BIT(5) -#define IT83XX_USBPD_MTSR1(p) REG8(IT83XX_USBPD_BASE(p)+0x1A) -#define IT83XX_USBPD_VDMMCSR(p) REG8(IT83XX_USBPD_BASE(p)+0x1B) -#define USBPD_REG_MASK_HARD_RESET_DECODE BIT(0) -#define IT83XX_USBPD_MRSR(p) REG8(IT83XX_USBPD_BASE(p)+0x1C) -#define USBPD_REG_GET_SOP_TYPE_RX(mrsr) (((mrsr) >> 4) & 0x7) -#define USBPD_REG_MASK_RX_MSG_VALID BIT(0) -#define IT83XX_USBPD_PEFSMR(p) REG8(IT83XX_USBPD_BASE(p)+0x1D) -#define IT83XX_USBPD_PES0R(p) REG8(IT83XX_USBPD_BASE(p)+0x1E) -#define IT83XX_USBPD_PES1R(p) REG8(IT83XX_USBPD_BASE(p)+0x1F) -#define IT83XX_USBPD_TDO(p) REG32(IT83XX_USBPD_BASE(p)+0x20) -#define IT83XX_USBPD_AGTMHLR(p) REG8(IT83XX_USBPD_BASE(p)+0x3C) -#define IT83XX_USBPD_AGTMHHR(p) REG8(IT83XX_USBPD_BASE(p)+0x3D) -#define IT83XX_USBPD_TMHLR(p) REG8(IT83XX_USBPD_BASE(p)+0x3E) -#define IT83XX_USBPD_TMHHR(p) REG8(IT83XX_USBPD_BASE(p)+0x3F) -#define IT83XX_USBPD_RDO0(p) REG32(IT83XX_USBPD_BASE(p)+0x40) -#define IT83XX_USBPD_RMH(p) REG16(IT83XX_USBPD_BASE(p)+0x5E) -#define IT83XX_USBPD_CCPSR0(p) REG8(IT83XX_USBPD_BASE(p)+0x60) -#define IT83XX_USBPD_BMCSR(p) REG8(IT83XX_USBPD_BASE(p)+0x64) -#define IT83XX_USBPD_PDMHSR(p) REG8(IT83XX_USBPD_BASE(p)+0x65) -#define IT83XX_USBPD_TCDCR(p) REG8(IT83XX_USBPD_BASE(p)+0x67) -#define USBPD_REG_PLUG_OUT_DETECT_TYPE_SELECT BIT(7) -#define USBPD_REG_MASK_TYPEC_PLUG_IN_OUT_ISR BIT(4) -#define USBPD_REG_PLUG_OUT_SELECT BIT(3) -#define USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE BIT(1) -#define USBPD_REG_PLUG_IN_OUT_DETECT_STAT BIT(0) -#define IT83XX_USBPD_PDQSCR(p) REG8(IT83XX_USBPD_BASE(p)+0x70) -#define USBPD_REG_FAST_SWAP_REQUEST_ENABLE BIT(1) -#define USBPD_REG_FAST_SWAP_DETECT_ENABLE BIT(0) -#define IT83XX_USBPD_PD30IR(p) REG8(IT83XX_USBPD_BASE(p)+0x78) -#define USBPD_REG_FAST_SWAP_DETECT_STAT BIT(4) -#define IT83XX_USBPD_MPD30IR(p) REG8(IT83XX_USBPD_BASE(p)+0x7A) -#define USBPD_REG_MASK_PD30_ISR BIT(7) -#define USBPD_REG_MASK_FAST_SWAP_DETECT_ISR BIT(4) - -#elif defined(CONFIG_USB_PD_TCPM_DRIVER_IT8XXX2) -#define IT83XX_USBPD_BASE(port) (0x00F03700 + (0x100 * (port) * (port))) - -#define IT83XX_USBPD_PDGCR(p) REG8(IT83XX_USBPD_BASE(p)+0x0) -#define USBPD_REG_MASK_SW_RESET_BIT BIT(7) -#define USBPD_REG_MASK_PROTOCOL_STATE_CLEAR BIT(6) -#define USBPD_REG_MASK_BIST_DATA_MODE BIT(4) -#define USBPD_REG_MASK_AUTO_BIST_RESPONSE BIT(3) -#define USBPD_REG_MASK_TX_MESSAGE_ENABLE BIT(2) -#define USBPD_REG_MASK_SNIFFER_MODE BIT(1) -#define USBPD_REG_MASK_BMC_PHY BIT(0) -#define IT83XX_USBPD_PDCSR0(p) REG8(IT83XX_USBPD_BASE(p)+0x01) -#define IT83XX_USBPD_PDMSR(p) REG8(IT83XX_USBPD_BASE(p)+0x02) -#define USBPD_REG_MASK_DISABLE_AUTO_GEN_TX_HEADER BIT(7) -#define USBPD_REG_MASK_AUTO_FRS_DISABLE BIT(6) -#define IT83XX_USBPD_PDCSR1(p) REG8(IT83XX_USBPD_BASE(p)+0x03) -#define USBPD_REG_MASK_CABLE_RESET_RX_ENABLE BIT(6) -#define USBPD_REG_MASK_HARD_RESET_RX_ENABLE BIT(5) -#define USBPD_REG_MASK_SOPPP_RX_ENABLE BIT(2) -#define USBPD_REG_MASK_SOPP_RX_ENABLE BIT(1) -#define USBPD_REG_MASK_SOP_RX_ENABLE BIT(0) -#define IT83XX_USBPD_CCGCR(p) REG8(IT83XX_USBPD_BASE(p)+0x04) -#define USBPD_REG_MASK_DISABLE_CC BIT(7) -#define USBPD_REG_MASK_DISABLE_CC_VOL_DETECTOR BIT(6) -#define USBPD_REG_MASK_CC_SELECT_RP_RESERVED (BIT(3) | BIT(2) | BIT(1)) -#define USBPD_REG_MASK_CC_SELECT_RP_DEF (BIT(3) | BIT(2)) -#define USBPD_REG_MASK_CC_SELECT_RP_1A5 BIT(3) -#define USBPD_REG_MASK_CC_SELECT_RP_3A0 BIT(2) -#define USBPD_REG_MASK_CC1_CC2_SELECTION BIT(0) -#define IT83XX_USBPD_CCCSR(p) REG8(IT83XX_USBPD_BASE(p)+0x05) -#define USBPD_REG_MASK_CC2_DISCONNECT BIT(7) -#define USBPD_REG_MASK_CC2_DISCONNECT_5_1K_TO_GND BIT(6) -#define USBPD_REG_MASK_CC1_DISCONNECT BIT(3) -#define USBPD_REG_MASK_CC1_DISCONNECT_5_1K_TO_GND BIT(2) -#ifdef IT83XX_USBPD_CC1_CC2_RESISTANCE_SEPARATE -#define USBPD_REG_MASK_CC1_CC2_RP_RD_SELECT (BIT(1) | BIT(5)) -#else -#define USBPD_REG_MASK_CC1_CC2_RP_RD_SELECT BIT(1) -#endif -#define IT83XX_USBPD_CCPSR(p) REG8(IT83XX_USBPD_BASE(p)+0x06) -#define USBPD_REG_MASK_DISCONNECT_5_1K_CC2_DB BIT(6) -#define USBPD_REG_MASK_DISCONNECT_POWER_CC2 BIT(5) -#define USBPD_REG_MASK_DISCONNECT_5_1K_CC1_DB BIT(2) -#define USBPD_REG_MASK_DISCONNECT_POWER_CC1 BIT(1) -#define IT83XX_USBPD_SRCVCRR(p) REG8(IT83XX_USBPD_BASE(p)+0x08) -#define USBPD_REG_MASK_SRC_COMPARE_CC2_VOLT_H BIT(5) -#define USBPD_REG_MASK_SRC_COMPARE_CC2_VOLT_L BIT(4) -#define USBPD_REG_MASK_SRC_COMPARE_CC1_VOLT_H BIT(1) -#define USBPD_REG_MASK_SRC_COMPARE_CC1_VOLT_L BIT(0) -#define IT83XX_USBPD_SNKVCRR(p) REG8(IT83XX_USBPD_BASE(p)+0x09) -#define USBPD_REG_MASK_SNK_COMPARE_CC2_VOLT_H BIT(6) -#define USBPD_REG_MASK_SNK_COMPARE_CC2_VOLT_M BIT(5) -#define USBPD_REG_MASK_SNK_COMPARE_CC2_VOLT_L BIT(4) -#define USBPD_REG_MASK_SNK_COMPARE_CC1_VOLT_H BIT(2) -#define USBPD_REG_MASK_SNK_COMPARE_CC1_VOLT_M BIT(1) -#define USBPD_REG_MASK_SNK_COMPARE_CC1_VOLT_L BIT(0) -#define IT83XX_USBPD_PDFSCR(p) REG8(IT83XX_USBPD_BASE(p)+0x0C) -#define USBPD_REG_FAST_SWAP_REQUEST_ENABLE BIT(1) -#define USBPD_REG_FAST_SWAP_DETECT_ENABLE BIT(0) -#define IT83XX_USBPD_IFS(p) REG8(IT83XX_USBPD_BASE(p)+0x12) -#define USBPD_REG_FAST_SWAP_DETECT_STAT BIT(4) -#define IT83XX_USBPD_MIFS(p) REG8(IT83XX_USBPD_BASE(p)+0x13) -#define USBPD_REG_MASK_FAST_SWAP_ISR BIT(7) -#define USBPD_REG_MASK_FAST_SWAP_DETECT_ISR BIT(4) -#define IT83XX_USBPD_ISR(p) REG8(IT83XX_USBPD_BASE(p)+0x14) -#define USBPD_REG_MASK_CABLE_RESET_DETECT BIT(6) -#define USBPD_REG_MASK_HARD_RESET_DETECT BIT(5) -#define USBPD_REG_MASK_MSG_RX_DONE BIT(4) -#define USBPD_REG_MASK_TX_ERROR_STAT BIT(3) -#define USBPD_REG_MASK_CABLE_RESET_TX_DONE BIT(2) -#define USBPD_REG_MASK_HARD_RESET_TX_DONE BIT(1) -#define USBPD_REG_MASK_MSG_TX_DONE BIT(0) -#define IT83XX_USBPD_IMR(p) REG8(IT83XX_USBPD_BASE(p)+0x15) -#define IT83XX_USBPD_MTCR(p) REG8(IT83XX_USBPD_BASE(p)+0x18) -#define USBPD_REG_MASK_TX_DISCARD_STAT BIT(7) -#define USBPD_REG_MASK_TX_NO_RESPONSE_STAT BIT(6) -#define USBPD_REG_MASK_TX_NOT_EN_STAT BIT(5) -#define USBPD_REG_MASK_CABLE_RESET BIT(3) -#define USBPD_REG_MASK_SEND_HW_RESET BIT(2) -#define USBPD_REG_MASK_SEND_BIST_MODE_2 BIT(1) -#define USBPD_REG_MASK_TX_START BIT(0) -#define IT83XX_USBPD_MTSR0(p) REG8(IT83XX_USBPD_BASE(p)+0x19) -#define IT83XX_USBPD_MHSR0(p) REG8(IT83XX_USBPD_BASE(p)+0x1A) -#define USBPD_REG_MASK_SOP_PORT_DATA_ROLE BIT(5) -#define IT83XX_USBPD_MHSR1(p) REG8(IT83XX_USBPD_BASE(p)+0x1B) -#define USBPD_REG_MASK_SOP_PORT_POWER_ROLE BIT(0) -#define IT83XX_USBPD_TDO(p) REG32(IT83XX_USBPD_BASE(p)+0x22) -#define IT83XX_USBPD_RMH(p) REG16(IT83XX_USBPD_BASE(p)+0x42) -#define IT83XX_USBPD_RDO(p) REG32(IT83XX_USBPD_BASE(p)+0x44) -#define IT83XX_USBPD_BMCDR0(p) REG8(IT83XX_USBPD_BASE(p)+0x61) -#define USBPD_REG_MASK_BMC_RX_THRESHOLD_SRC BIT(5) -#define USBPD_REG_MASK_BMC_RX_THRESHOLD_SNK BIT(1) -#define IT83XX_USBPD_TCDCR(p) REG8(IT83XX_USBPD_BASE(p)+0x67) -#define USBPD_REG_PLUG_OUT_DETECT_TYPE_SELECT BIT(7) -#define USBPD_REG_PLUG_OUT_SELECT BIT(6) -#define USBPD_REG_PD3_0_SNK_TX_OK_DISABLE BIT(5) -#define USBPD_REG_PD3_0_SNK_TX_NG_DISABLE BIT(3) -#define USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE BIT(1) -#define USBPD_REG_PLUG_IN_OUT_DETECT_STAT BIT(0) -#define IT83XX_USBPD_CCPSR0(p) REG8(IT83XX_USBPD_BASE(p)+0x70) -#define IT83XX_USBPD_CCPSR3_RISE(p) REG8(IT83XX_USBPD_BASE(p)+0x73) -#define IT83XX_USBPD_CCPSR4_FALL(p) REG8(IT83XX_USBPD_BASE(p)+0x74) -#endif /* !defined(CONFIG_USB_PD_TCPM_DRIVER_IT83XX) */ - -/* - * Dedicated setting for CC pin. - * This setting will connect CC pin to internal PD module directly without - * applying any GPIO/ALT configuration. - */ -#define IT83XX_USBPD_CC_PIN_CONFIG 0x86 -#define IT83XX_USBPD_CC_PIN_CONFIG2 0x06 - -/* - * Before disabling cc 5v tolerant, we need to make sure cc voltage - * detector is enabled and Vconn is dropped below 3.3v (>500us) to avoid - * the potential risk of voltage fed back into Vcore. - */ -#define IT83XX_USBPD_T_VCONN_BELOW_3_3V 500 /* us */ - -#ifndef CONFIG_USB_PD_TCPM_ITE_ON_CHIP -#define CONFIG_USB_PD_ITE_ACTIVE_PORT_COUNT 0 -#endif - -#define TASK_EVENT_PHY_TX_DONE TASK_EVENT_CUSTOM_BIT(PD_EVENT_FIRST_FREE_BIT) - -#define SET_MASK(reg, bit_mask) ((reg) |= (bit_mask)) -#define CLEAR_MASK(reg, bit_mask) ((reg) &= (~(bit_mask))) -#define IS_MASK_SET(reg, bit_mask) (((reg) & (bit_mask)) != 0) -#define IS_MASK_CLEAR(reg, bit_mask) (((reg) & (bit_mask)) == 0) - -#if defined(CONFIG_USB_PD_TCPM_DRIVER_IT83XX) -/* macros for set */ -#define USBPD_KICK_TX_START(port) \ - SET_MASK(IT83XX_USBPD_MTCR(port), \ - USBPD_REG_MASK_TX_START) -#define USBPD_SEND_HARD_RESET(port) \ - SET_MASK(IT83XX_USBPD_MTSR0(port), \ - USBPD_REG_MASK_SEND_HW_RESET) -#define USBPD_SW_RESET(port) \ - SET_MASK(IT83XX_USBPD_GCR(port), \ - USBPD_REG_MASK_SW_RESET_BIT) -#define USBPD_ENABLE_BMC_PHY(port) \ - SET_MASK(IT83XX_USBPD_GCR(port), \ - USBPD_REG_MASK_BMC_PHY) -#define USBPD_DISABLE_BMC_PHY(port) \ - CLEAR_MASK(IT83XX_USBPD_GCR(port), \ - USBPD_REG_MASK_BMC_PHY) -#define USBPD_START(port) \ - CLEAR_MASK(IT83XX_USBPD_CCGCR(port), \ - USBPD_REG_MASK_DISABLE_CC) -#define USBPD_ENABLE_SEND_BIST_MODE_2(port) \ - SET_MASK(IT83XX_USBPD_MTSR0(port), \ - USBPD_REG_MASK_SEND_BIST_MODE_2) -#define USBPD_DISABLE_SEND_BIST_MODE_2(port) \ - CLEAR_MASK(IT83XX_USBPD_MTSR0(port), \ - USBPD_REG_MASK_SEND_BIST_MODE_2) -#define USBPD_CLEAR_FRS_DETECT_STATUS(port) \ - (IT83XX_USBPD_PD30IR(port) = USBPD_REG_FAST_SWAP_DETECT_STAT) -#define USBPD_CC1_DISCONNECTED(p) \ - ((IT83XX_USBPD_CCCSR(p) | USBPD_REG_MASK_CC1_DISCONNECT) & \ - ~USBPD_REG_MASK_CC2_DISCONNECT) -#define USBPD_CC2_DISCONNECTED(p) \ - ((IT83XX_USBPD_CCCSR(p) | USBPD_REG_MASK_CC2_DISCONNECT) & \ - ~USBPD_REG_MASK_CC1_DISCONNECT) - -/* macros for get */ -#define USBPD_GET_POWER_ROLE(port) \ - (IT83XX_USBPD_PDMSR(port) & 1) -#define USBPD_GET_CC1_PULL_REGISTER_SELECTION(port) \ - (IT83XX_USBPD_CCGCR(port) & BIT(1)) -#define USBPD_GET_CC2_PULL_REGISTER_SELECTION(port) \ - (IT83XX_USBPD_BMCSR(port) & BIT(3)) -#define USBPD_GET_PULL_CC_SELECTION(port) \ - (IT83XX_USBPD_CCGCR(port) & 1) - -/* macros for check */ -#define USBPD_IS_TX_ERR(port) \ - IS_MASK_SET(IT83XX_USBPD_MTCR(port), USBPD_REG_MASK_TX_ERR_STAT) -#define USBPD_IS_TX_DISCARD(port) \ - IS_MASK_SET(IT83XX_USBPD_MTCR(port), USBPD_REG_MASK_TX_DISCARD_STAT) - -#elif defined(CONFIG_USB_PD_TCPM_DRIVER_IT8XXX2) -/* macros for set */ -#define USBPD_SW_RESET(port) \ - SET_MASK(IT83XX_USBPD_PDGCR(port), \ - USBPD_REG_MASK_SW_RESET_BIT) -#define USBPD_ENABLE_BMC_PHY(port) \ - SET_MASK(IT83XX_USBPD_PDGCR(port), \ - USBPD_REG_MASK_BMC_PHY) -#define USBPD_DISABLE_BMC_PHY(port) \ - CLEAR_MASK(IT83XX_USBPD_PDGCR(port), \ - USBPD_REG_MASK_BMC_PHY) -#define USBPD_START(port) \ - CLEAR_MASK(IT83XX_USBPD_CCGCR(port), \ - USBPD_REG_MASK_DISABLE_CC) -#define USBPD_SEND_HARD_RESET(port) \ - SET_MASK(IT83XX_USBPD_MTCR(port), \ - USBPD_REG_MASK_SEND_HW_RESET) -#define USBPD_SEND_CABLE_RESET(port) \ - SET_MASK(IT83XX_USBPD_MTCR(port), \ - USBPD_REG_MASK_CABLE_RESET) -#define USBPD_ENABLE_SEND_BIST_MODE_2(port) \ - SET_MASK(IT83XX_USBPD_MTCR(port), \ - USBPD_REG_MASK_SEND_BIST_MODE_2) -#define USBPD_DISABLE_SEND_BIST_MODE_2(port) \ - CLEAR_MASK(IT83XX_USBPD_MTCR(port), \ - USBPD_REG_MASK_SEND_BIST_MODE_2) -#define USBPD_KICK_TX_START(port) \ - SET_MASK(IT83XX_USBPD_MTCR(port), \ - USBPD_REG_MASK_TX_START) -#define USBPD_CLEAR_FRS_DETECT_STATUS(port) \ - (IT83XX_USBPD_IFS(port) = USBPD_REG_FAST_SWAP_DETECT_STAT) -#define USBPD_CC1_DISCONNECTED(p) \ - ((IT83XX_USBPD_CCCSR(p) | USBPD_REG_MASK_CC1_DISCONNECT) & \ - ~USBPD_REG_MASK_CC2_DISCONNECT) -#define USBPD_CC2_DISCONNECTED(p) \ - ((IT83XX_USBPD_CCCSR(p) | USBPD_REG_MASK_CC2_DISCONNECT) & \ - ~USBPD_REG_MASK_CC1_DISCONNECT) - -/* macros for get */ -#define USBPD_GET_POWER_ROLE(port) \ - (IT83XX_USBPD_MHSR1(port) & BIT(0)) -#define USBPD_GET_CC1_PULL_REGISTER_SELECTION(port) \ - (IT83XX_USBPD_CCCSR(port) & BIT(1)) -#define USBPD_GET_CC2_PULL_REGISTER_SELECTION(port) \ - (IT83XX_USBPD_CCCSR(port) & BIT(1)) -#define USBPD_GET_PULL_CC_SELECTION(port) \ - (IT83XX_USBPD_CCGCR(port) & BIT(0)) -#define USBPD_GET_SNK_COMPARE_CC1_VOLT(port) \ - (IT83XX_USBPD_SNKVCRR(port) & \ - (USBPD_REG_MASK_SNK_COMPARE_CC1_VOLT_L | \ - USBPD_REG_MASK_SNK_COMPARE_CC1_VOLT_M | \ - USBPD_REG_MASK_SNK_COMPARE_CC1_VOLT_H)) -#define USBPD_GET_SNK_COMPARE_CC2_VOLT(port) \ - ((IT83XX_USBPD_SNKVCRR(port) & \ - (USBPD_REG_MASK_SNK_COMPARE_CC2_VOLT_L | \ - USBPD_REG_MASK_SNK_COMPARE_CC2_VOLT_M | \ - USBPD_REG_MASK_SNK_COMPARE_CC2_VOLT_H)) >> 4) -#define USBPD_GET_SRC_COMPARE_CC1_VOLT(port) \ - (IT83XX_USBPD_SRCVCRR(port) & \ - (USBPD_REG_MASK_SRC_COMPARE_CC1_VOLT_L | \ - USBPD_REG_MASK_SRC_COMPARE_CC1_VOLT_H)) -#define USBPD_GET_SRC_COMPARE_CC2_VOLT(port) \ - ((IT83XX_USBPD_SRCVCRR(port) & \ - (USBPD_REG_MASK_SRC_COMPARE_CC2_VOLT_L | \ - USBPD_REG_MASK_SRC_COMPARE_CC2_VOLT_H)) >> 4) - -/* macros for check */ -#define USBPD_IS_TX_ERR(port) \ - IS_MASK_SET(IT83XX_USBPD_ISR(port), USBPD_REG_MASK_TX_ERROR_STAT) -#endif /* !defined(CONFIG_USB_PD_TCPM_DRIVER_IT83XX) */ - -/* macros for PD ISR */ -#define USBPD_IS_HARD_RESET_DETECT(port) \ - IS_MASK_SET(IT83XX_USBPD_ISR(port), USBPD_REG_MASK_HARD_RESET_DETECT) -#define USBPD_IS_HARD_CABLE_RESET_TX_DONE(port) \ - IS_MASK_SET(IT83XX_USBPD_ISR(port), \ - USBPD_REG_MASK_HARD_CABLE_RESET_TX_DONE) -#define USBPD_IS_TX_DONE(port) \ - IS_MASK_SET(IT83XX_USBPD_ISR(port), USBPD_REG_MASK_MSG_TX_DONE) -#define USBPD_IS_RX_DONE(port) \ - IS_MASK_SET(IT83XX_USBPD_ISR(port), USBPD_REG_MASK_MSG_RX_DONE) -#define USBPD_IS_PLUG_IN_OUT_DETECT(port)\ - IS_MASK_SET(IT83XX_USBPD_TCDCR(port), USBPD_REG_PLUG_IN_OUT_DETECT_STAT) -#define USBPD_IS_PLUG_IN(port) \ - IS_MASK_CLEAR(IT83XX_USBPD_TCDCR(port), USBPD_REG_PLUG_OUT_SELECT) -#if defined(CONFIG_USB_PD_TCPM_DRIVER_IT83XX) -#define USBPD_IS_FAST_SWAP_DETECT(port) \ - IS_MASK_SET(IT83XX_USBPD_PD30IR(port), USBPD_REG_FAST_SWAP_DETECT_STAT) -#elif defined(CONFIG_USB_PD_TCPM_DRIVER_IT8XXX2) -#define USBPD_IS_FAST_SWAP_DETECT(port) \ - IS_MASK_SET(IT83XX_USBPD_IFS(port), USBPD_REG_FAST_SWAP_DETECT_STAT) -#endif - -#if defined(CONFIG_USB_PD_TCPM_ITE_ON_CHIP) && defined(CONFIG_ZEPHYR) -/* Use the Zephyr names here. When upstreaming we can update this */ -#include <dt-bindings/interrupt-controller/ite-intc.h> - -#define IT83XX_GPIO_GPCRF4 GPCRF4 -#define IT83XX_GPIO_GPCRF5 GPCRF5 -#define IT83XX_GPIO_GPCRH1 GPCRH1 -#define IT83XX_GPIO_GPCRH2 GPCRH2 -#define IT83XX_GPIO_GPCRP0 IT8XXX2_GPIO_GPCRP0 -#define IT83XX_GPIO_GPCRP1 IT8XXX2_GPIO_GPCRP1 -#define IT83XX_IRQ_USBPD0 IT8XXX2_IRQ_USBPD0 -#define IT83XX_IRQ_USBPD1 IT8XXX2_IRQ_USBPD1 -#define IT83XX_IRQ_USBPD2 IT8XXX2_IRQ_USBPD2 -#define USB_VID_ITE 0x048d - -/* ITE chip supports PD features */ -#define IT83XX_INTC_FAST_SWAP_SUPPORT -#define IT83XX_INTC_PLUG_IN_OUT_SUPPORT -#endif - -enum usbpd_port { - USBPD_PORT_A, - USBPD_PORT_B, - USBPD_PORT_C, -}; - -enum usbpd_ufp_volt_status { - USBPD_UFP_STATE_SNK_OPEN = 0, - USBPD_UFP_STATE_SNK_DEF = 1, - USBPD_UFP_STATE_SNK_1_5 = 3, - USBPD_UFP_STATE_SNK_3_0 = 7, -}; - -enum usbpd_dfp_volt_status { - USBPD_DFP_STATE_SRC_RA = 0, - USBPD_DFP_STATE_SRC_RD = 1, - USBPD_DFP_STATE_SRC_OPEN = 3, -}; - -enum usbpd_power_role { - USBPD_POWER_ROLE_CONSUMER, - USBPD_POWER_ROLE_PROVIDER, - USBPD_POWER_ROLE_CONSUMER_PROVIDER, - USBPD_POWER_ROLE_PROVIDER_CONSUMER, -}; - -enum tuning_unit { - IT83XX_TX_PRE_DRIVING_TIME_DEFAULT, - IT83XX_TX_PRE_DRIVING_TIME_1_UNIT, - IT83XX_TX_PRE_DRIVING_TIME_2_UNIT, - IT83XX_TX_PRE_DRIVING_TIME_3_UNIT, -}; - -struct usbpd_ctrl_t { - volatile uint8_t *cc1; - volatile uint8_t *cc2; - uint8_t irq; -}; - -/* Data structure for board to adjust pd port rising and falling time */ -struct cc_para_t { - enum tuning_unit rising_time; - enum tuning_unit falling_time; -}; - -extern const struct usbpd_ctrl_t usbpd_ctrl_regs[]; -void it8xxx2_clear_tx_error_status(enum usbpd_port port); -void it8xxx2_get_tx_error_status(enum usbpd_port port); -void it83xx_Rd_5_1K_only_for_hibernate(int port); -void switch_plug_out_type(enum usbpd_port port); -/* - * Board-level callback function to get cc tuning parameters - * NOTE: board must define CONFIG_IT83XX_TUNE_CC_PHY - */ -const struct cc_para_t *board_get_cc_tuning_parameter(enum usbpd_port port); - -#endif /* __CROS_EC_DRIVER_TCPM_IT83XX_H */ diff --git a/driver/tcpm/it8xxx2.c b/driver/tcpm/it8xxx2.c deleted file mode 100644 index dd5d1231fc..0000000000 --- a/driver/tcpm/it8xxx2.c +++ /dev/null @@ -1,968 +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. - */ - -/* TCPM on ITE chip it8xxx2 with embedded TCPC */ - -#include "common.h" -#include "config.h" -#include "console.h" -#include "it83xx_pd.h" -#include "ite_pd_intc.h" -#include "registers.h" -#include "system.h" -#include "task.h" -#include "timer.h" -#include "util.h" -#include "usb_common.h" -#include "usb_pd.h" -#include "usb_pd_tcpm.h" -#include "hooks.h" - -#ifdef CONFIG_USB_PD_TCPMV1 -#if defined(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE) || \ - defined(CONFIG_USB_PD_VBUS_DETECT_TCPC) || \ - defined(CONFIG_USB_PD_TCPC_LOW_POWER) || \ - defined(CONFIG_USB_PD_DISCHARGE_TCPC) -#error "Unsupported config options of IT8xxx2 PD driver" -#endif -#endif - -#ifdef CONFIG_USB_PD_TCPMV2 -#if defined(CONFIG_USB_PD_VBUS_DETECT_TCPC) || \ - defined(CONFIG_USB_PD_DISCHARGE_TCPC) -#error "Unsupported config options of IT8xxx2 PD driver" -#endif -#endif - -#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) - -bool rx_en[IT83XX_USBPD_PHY_PORT_COUNT]; -STATIC_IF(CONFIG_USB_PD_DECODE_SOP) - bool sop_prime_en[IT83XX_USBPD_PHY_PORT_COUNT]; -static uint8_t tx_error_status[IT83XX_USBPD_PHY_PORT_COUNT] = {0}; - -const struct usbpd_ctrl_t usbpd_ctrl_regs[] = { - {&IT83XX_GPIO_GPCRF4, &IT83XX_GPIO_GPCRF5, IT83XX_IRQ_USBPD0}, - {&IT83XX_GPIO_GPCRH1, &IT83XX_GPIO_GPCRH2, IT83XX_IRQ_USBPD1}, - {&IT83XX_GPIO_GPCRP0, &IT83XX_GPIO_GPCRP1, IT83XX_IRQ_USBPD2}, -}; -BUILD_ASSERT(ARRAY_SIZE(usbpd_ctrl_regs) >= IT83XX_USBPD_PHY_PORT_COUNT); - -/* - * Disable cc analog and pd digital module, but only left Rd_5.1K (Not - * Rd_DB) analog module alive to assert Rd on CCs. EC reset or calling - * _init() are able to re-active cc and pd. - */ -void it83xx_Rd_5_1K_only_for_hibernate(int port) -{ - uint8_t cc_config = (port == USBPD_PORT_C ? - IT83XX_USBPD_CC_PIN_CONFIG2 : - IT83XX_USBPD_CC_PIN_CONFIG); - - /* This only apply to active PD port */ - if (*usbpd_ctrl_regs[port].cc1 == cc_config && - *usbpd_ctrl_regs[port].cc2 == cc_config) { - /* Disable PD Tx and Rx PHY */ - IT83XX_USBPD_PDGCR(port) &= ~USBPD_REG_MASK_BMC_PHY; - /* Disable CCs voltage detector */ - IT83XX_USBPD_CCGCR(port) |= - USBPD_REG_MASK_DISABLE_CC_VOL_DETECTOR; - /* Select Rp reserved value for not current leakage */ - IT83XX_USBPD_CCGCR(port) |= - USBPD_REG_MASK_CC_SELECT_RP_RESERVED; - /* - * Connect CCs analog module (ex.UP/RD/DET/TX/RX), and - * connect CCs 5.1K to GND, and - * CCs assert Rd - */ - IT83XX_USBPD_CCCSR(port) &= - ~(USBPD_REG_MASK_CC2_DISCONNECT | - USBPD_REG_MASK_CC2_DISCONNECT_5_1K_TO_GND | - USBPD_REG_MASK_CC1_DISCONNECT | - USBPD_REG_MASK_CC1_DISCONNECT_5_1K_TO_GND | - USBPD_REG_MASK_CC1_CC2_RP_RD_SELECT); - /* Disconnect CCs 5V tolerant */ - IT83XX_USBPD_CCPSR(port) |= - (USBPD_REG_MASK_DISCONNECT_POWER_CC2 | - USBPD_REG_MASK_DISCONNECT_POWER_CC1); - /* Enable CCs analog module */ - IT83XX_USBPD_CCGCR(port) &= ~USBPD_REG_MASK_DISABLE_CC; - } -} - -static enum tcpc_cc_voltage_status it8xxx2_get_cc(enum usbpd_port port, - enum usbpd_cc_pin cc_pin) -{ - enum usbpd_ufp_volt_status ufp_volt; - enum usbpd_dfp_volt_status dfp_volt; - enum tcpc_cc_voltage_status cc_state = TYPEC_CC_VOLT_OPEN; - - /* - * Because the message header bit(8) field has different definition - * between SOP and SOP'/SOP'', in order to not happen misjudgement - * when we receive SOP or SOP'/SOP'', the getting power role synchronize - * with pd[port].power_role (also synchronization with tcpm_set_cc) - * instead of message header. - */ - /* Sink */ - if (pd_get_power_role(port) == PD_ROLE_SINK) { - if (cc_pin == USBPD_CC_PIN_1) - ufp_volt = USBPD_GET_SNK_COMPARE_CC1_VOLT(port); - else - ufp_volt = USBPD_GET_SNK_COMPARE_CC2_VOLT(port); - - switch (ufp_volt) { - case USBPD_UFP_STATE_SNK_DEF: - cc_state = TYPEC_CC_VOLT_RP_DEF; - break; - case USBPD_UFP_STATE_SNK_1_5: - cc_state = TYPEC_CC_VOLT_RP_1_5; - break; - case USBPD_UFP_STATE_SNK_3_0: - cc_state = TYPEC_CC_VOLT_RP_3_0; - break; - case USBPD_UFP_STATE_SNK_OPEN: - cc_state = TYPEC_CC_VOLT_OPEN; - break; - default: - cc_state = TYPEC_CC_VOLT_OPEN; - break; - } - /* Source */ - } else { - if (cc_pin == USBPD_CC_PIN_1) - dfp_volt = USBPD_GET_SRC_COMPARE_CC1_VOLT(port); - else - dfp_volt = USBPD_GET_SRC_COMPARE_CC2_VOLT(port); - - switch (dfp_volt) { - case USBPD_DFP_STATE_SRC_RA: - cc_state = TYPEC_CC_VOLT_RA; - break; - case USBPD_DFP_STATE_SRC_RD: - cc_state = TYPEC_CC_VOLT_RD; - break; - case USBPD_DFP_STATE_SRC_OPEN: - cc_state = TYPEC_CC_VOLT_OPEN; - break; - default: - cc_state = TYPEC_CC_VOLT_OPEN; - break; - } - } - - return cc_state; -} - -static int it8xxx2_tcpm_get_message_raw(int port, uint32_t *buf, int *head) -{ - int cnt = PD_HEADER_CNT(IT83XX_USBPD_RMH(port)); - - if (!USBPD_IS_RX_DONE(port)) - return EC_ERROR_UNKNOWN; - - /* Store header */ - *head = IT83XX_USBPD_RMH(port); - - /* - * BIT[6:4] SOP type of Rx message - * 000b=SOP, 001b=SOP', 010b=SOP", 011b=Debug SOP', 100b=Debug SOP" - * 101b=HRDRST, 110b=CBLRST - * 000b~100b is aligned to enum tcpci_msg_type. - * - */ - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) - *head |= PD_HEADER_SOP((IT83XX_USBPD_MTSR0(port) >> 4) & 0x7); - - /* Check data message */ - if (cnt) - memcpy(buf, (uint32_t *)&IT83XX_USBPD_RDO(port), cnt * 4); - - return EC_SUCCESS; -} - -void it8xxx2_clear_tx_error_status(enum usbpd_port port) -{ - tx_error_status[port] = 0; -} - -void it8xxx2_get_tx_error_status(enum usbpd_port port) -{ - tx_error_status[port] = IT83XX_USBPD_MTCR(port) & - (USBPD_REG_MASK_TX_NOT_EN_STAT | - USBPD_REG_MASK_TX_DISCARD_STAT | - USBPD_REG_MASK_TX_NO_RESPONSE_STAT); -} - -static enum tcpc_transmit_complete it8xxx2_tx_data(enum usbpd_port port, - enum tcpci_msg_type type, - uint16_t header, - const uint32_t *buf) -{ - int r; - uint32_t evt; - uint8_t length = PD_HEADER_CNT(header); - - /* Set message header */ - IT83XX_USBPD_MHSR0(port) = (uint8_t)header; - IT83XX_USBPD_MHSR1(port) = (header >> 8); - - /* - * Bit[2:0] Tx message type - * 000b=SOP, 001b=SOP', 010b=SOP", 011b=Debug SOP', 100b=Debug SOP''. - */ - IT83XX_USBPD_MTSR0(port) = - (IT83XX_USBPD_MTSR0(port) & ~0x7) | (type & 0x7); - - /* Limited by PD_HEADER_CNT() */ - ASSERT(length <= 0x7); - - if (length) - /* Set data */ - memcpy((uint32_t *)&IT83XX_USBPD_TDO(port), buf, length * 4); - - for (r = 0; r <= CONFIG_PD_RETRY_COUNT; r++) { - /* Start Tx */ - USBPD_KICK_TX_START(port); - evt = task_wait_event_mask(TASK_EVENT_PHY_TX_DONE, - PD_T_TCPC_TX_TIMEOUT); - - /* - * Check Tx error status (TCPC won't set multi tx errors at one - * time transmission): - * 1) If we doesn't enable Tx. - * 2) If discard, means HW doesn't send the msg and resend. - * 3) If port partner doesn't respond GoodCRC. - * 4) If Tx timeout. - */ - if (tx_error_status[port] || (evt & TASK_EVENT_TIMER)) { - if (tx_error_status[port] & - USBPD_REG_MASK_TX_NOT_EN_STAT) { - CPRINTS("p%d TxErr: Tx EN and resend", port); - tx_error_status[port] &= - ~USBPD_REG_MASK_TX_NOT_EN_STAT; - IT83XX_USBPD_PDGCR(port) |= - USBPD_REG_MASK_TX_MESSAGE_ENABLE; - continue; - } else if (tx_error_status[port] & - USBPD_REG_MASK_TX_DISCARD_STAT) { - CPRINTS("p%d TxErr: Discard and resend", port); - tx_error_status[port] &= - ~USBPD_REG_MASK_TX_DISCARD_STAT; - continue; - } else if (tx_error_status[port] & - USBPD_REG_MASK_TX_NO_RESPONSE_STAT) { - /* HW had automatically resent message twice */ - tx_error_status[port] &= - ~USBPD_REG_MASK_TX_NO_RESPONSE_STAT; - return TCPC_TX_COMPLETE_FAILED; - } else if (evt & TASK_EVENT_TIMER) { - CPRINTS("p%d TxErr: Timeout", port); - return TCPC_TX_UNSET; - } - } else - break; - } - - if (r > CONFIG_PD_RETRY_COUNT) - return TCPC_TX_COMPLETE_DISCARDED; - - return TCPC_TX_COMPLETE_SUCCESS; -} - -static enum tcpc_transmit_complete it8xxx2_send_hw_reset(enum usbpd_port port) -{ - /* Send hard reset */ - USBPD_SEND_HARD_RESET(port); - usleep(MSEC); - - if (!(IT83XX_USBPD_ISR(port) & USBPD_REG_MASK_HARD_RESET_TX_DONE)) - return TCPC_TX_COMPLETE_FAILED; - IT83XX_USBPD_ISR(port) = USBPD_REG_MASK_HARD_RESET_TX_DONE; - - return TCPC_TX_COMPLETE_SUCCESS; -} - -static enum tcpc_transmit_complete it8xxx2_send_cable_reset( - enum usbpd_port port) -{ - /* Send cable reset */ - USBPD_SEND_CABLE_RESET(port); - usleep(MSEC); - - if (!(IT83XX_USBPD_ISR(port) & USBPD_REG_MASK_CABLE_RESET_TX_DONE)) - return TCPC_TX_COMPLETE_FAILED; - IT83XX_USBPD_ISR(port) = USBPD_REG_MASK_CABLE_RESET_TX_DONE; - - return TCPC_TX_COMPLETE_SUCCESS; -} - -static void it8xxx2_send_bist_mode2_pattern(enum usbpd_port port) -{ - USBPD_ENABLE_SEND_BIST_MODE_2(port); - usleep(PD_T_BIST_TRANSMIT); - USBPD_DISABLE_SEND_BIST_MODE_2(port); -} - -static void it8xxx2_enable_vconn(enum usbpd_port port, int enabled) -{ - enum usbpd_cc_pin cc_pin; - - if (USBPD_GET_PULL_CC_SELECTION(port)) - cc_pin = USBPD_CC_PIN_1; - else - cc_pin = USBPD_CC_PIN_2; - - if (enabled) { - /* Disable unused CC to become VCONN */ - if (cc_pin == USBPD_CC_PIN_1) { - IT83XX_USBPD_CCCSR(port) = USBPD_CC2_DISCONNECTED(port); - IT83XX_USBPD_CCPSR(port) = (IT83XX_USBPD_CCPSR(port) - & ~USBPD_REG_MASK_DISCONNECT_POWER_CC2) - | USBPD_REG_MASK_DISCONNECT_POWER_CC1; - } else { - IT83XX_USBPD_CCCSR(port) = USBPD_CC1_DISCONNECTED(port); - IT83XX_USBPD_CCPSR(port) = (IT83XX_USBPD_CCPSR(port) - & ~USBPD_REG_MASK_DISCONNECT_POWER_CC1) - | USBPD_REG_MASK_DISCONNECT_POWER_CC2; - } - } else { - /* Connect cc analog module (ex.UP/RD/DET/TX/RX) */ - IT83XX_USBPD_CCCSR(port) &= ~(USBPD_REG_MASK_CC2_DISCONNECT | - USBPD_REG_MASK_CC1_DISCONNECT); - /* Disable cc 5v tolerant */ - IT83XX_USBPD_CCPSR(port) |= - (USBPD_REG_MASK_DISCONNECT_POWER_CC1 | - USBPD_REG_MASK_DISCONNECT_POWER_CC2); - } -} - -static void it8xxx2_enable_cc(enum usbpd_port port, int enable) -{ - if (enable) - IT83XX_USBPD_CCGCR(port) &= ~USBPD_REG_MASK_DISABLE_CC; - else - IT83XX_USBPD_CCGCR(port) |= USBPD_REG_MASK_DISABLE_CC; -} - -static void it8xxx2_set_power_role(enum usbpd_port port, int power_role) -{ - /* 0: PD_ROLE_SINK, 1: PD_ROLE_SOURCE */ - if (power_role == PD_ROLE_SOURCE) { - /* - * Bit[0:6] BMC Rx threshold setting - * 000 1000b: power neutral - * 010 0000b: sinking power => - * High to low Y3Rx threshold = 0.38, - * Low to high Y3Rx threshold = 0.54. - * 000 0010b: sourcing power => - * High to low Y3Rx threshold = 0.64, - * Low to high Y3Rx threshold = 0.79. - */ - IT83XX_USBPD_BMCDR0(port) = USBPD_REG_MASK_BMC_RX_THRESHOLD_SRC; - /* Bit0: source */ - IT83XX_USBPD_MHSR1(port) |= USBPD_REG_MASK_SOP_PORT_POWER_ROLE; - /* Bit1: CC1 and CC2 select Rp */ - IT83XX_USBPD_CCCSR(port) |= USBPD_REG_MASK_CC1_CC2_RP_RD_SELECT; - } else { - /* - * Bit[0:6] BMC Rx threshold setting - * 000 1000b: power neutral - * 010 0000b: sinking power => - * High to low Y3Rx threshold = 0.38, - * Low to high Y3Rx threshold = 0.54. - * 000 0010b: sourcing power => - * High to low Y3Rx threshold = 0.64, - * Low to high Y3Rx threshold = 0.79. - */ - IT83XX_USBPD_BMCDR0(port) = USBPD_REG_MASK_BMC_RX_THRESHOLD_SNK; - /* Bit0: sink */ - IT83XX_USBPD_MHSR1(port) &= ~USBPD_REG_MASK_SOP_PORT_POWER_ROLE; - /* Bit1: CC1 and CC2 select Rd */ - IT83XX_USBPD_CCCSR(port) &= - ~USBPD_REG_MASK_CC1_CC2_RP_RD_SELECT; - } -} - -static void it8xxx2_set_data_role(enum usbpd_port port, int data_role) -{ - /* 0: PD_ROLE_UFP 1: PD_ROLE_DFP */ - if (data_role == PD_ROLE_DFP) - /* Bit5: DFP */ - IT83XX_USBPD_MHSR0(port) |= USBPD_REG_MASK_SOP_PORT_DATA_ROLE; - else - /* Bit5: UFP */ - IT83XX_USBPD_MHSR0(port) &= ~USBPD_REG_MASK_SOP_PORT_DATA_ROLE; -} - -static void it8xxx2_select_polarity(enum usbpd_port port, - enum usbpd_cc_pin cc_pin) -{ - /* CC1/CC2 selection */ - if (cc_pin == USBPD_CC_PIN_1) - IT83XX_USBPD_CCGCR(port) |= USBPD_REG_MASK_CC1_CC2_SELECTION; - else - IT83XX_USBPD_CCGCR(port) &= ~USBPD_REG_MASK_CC1_CC2_SELECTION; -} - -static int it8xxx2_set_cc(enum usbpd_port port, int pull) -{ - int enable_cc = 1; - - switch (pull) { - case TYPEC_CC_RD: - it8xxx2_set_power_role(port, PD_ROLE_SINK); - break; - case TYPEC_CC_RP: - it8xxx2_set_power_role(port, PD_ROLE_SOURCE); - break; - case TYPEC_CC_OPEN: - /* Power-down CC1 & CC2 to remove Rp/Rd */ - enable_cc = 0; - break; - default: - return EC_ERROR_UNIMPLEMENTED; - } - - it8xxx2_enable_cc(port, enable_cc); - return EC_SUCCESS; -} - -static int it8xxx2_tcpm_release(int port) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -static int it8xxx2_tcpm_get_cc(int port, - enum tcpc_cc_voltage_status *cc1, - enum tcpc_cc_voltage_status *cc2) -{ - *cc2 = it8xxx2_get_cc(port, USBPD_CC_PIN_2); - *cc1 = it8xxx2_get_cc(port, USBPD_CC_PIN_1); - - return EC_SUCCESS; -} - -static int it8xxx2_tcpm_select_rp_value(int port, int rp_sel) -{ - uint8_t rp; - - /* - * Bit[3-1]: CC output current (effective when Rp assert in 05h Bit[1]) - * 111: reserved - * 010: 330uA outpt (3.0A) - * 100: 180uA outpt (1.5A) - * 110: 80uA outpt (USB default) - */ - switch (rp_sel) { - case TYPEC_RP_1A5: - rp = USBPD_REG_MASK_CC_SELECT_RP_1A5; - break; - case TYPEC_RP_3A0: - rp = USBPD_REG_MASK_CC_SELECT_RP_3A0; - break; - case TYPEC_RP_USB: - default: - rp = USBPD_REG_MASK_CC_SELECT_RP_DEF; - break; - } - IT83XX_USBPD_CCGCR(port) = (IT83XX_USBPD_CCGCR(port) & ~(7 << 1)) | rp; - - return EC_SUCCESS; -} - -static int it8xxx2_tcpm_set_cc(int port, int pull) -{ - return it8xxx2_set_cc(port, pull); -} - -static int it8xxx2_tcpm_set_polarity(int port, enum tcpc_cc_polarity polarity) -{ - enum usbpd_cc_pin cc_pin = - (polarity == POLARITY_CC1 || polarity == POLARITY_CC1_DTS) ? - USBPD_CC_PIN_1 : USBPD_CC_PIN_2; - - it8xxx2_select_polarity(port, cc_pin); - - return EC_SUCCESS; -} - -__maybe_unused static int it8xxx2_tcpm_decode_sop_prime_enable(int port, - bool enable) -{ - /* Save SOP'/SOP'' enable state */ - sop_prime_en[port] = enable; - - if (!rx_en[port]) - return EC_SUCCESS; - - if (enable) - IT83XX_USBPD_PDCSR1(port) |= - (USBPD_REG_MASK_SOPP_RX_ENABLE | - USBPD_REG_MASK_SOPPP_RX_ENABLE); - else - IT83XX_USBPD_PDCSR1(port) &= - ~(USBPD_REG_MASK_SOPP_RX_ENABLE | - USBPD_REG_MASK_SOPPP_RX_ENABLE); - - return EC_SUCCESS; -} - -static int it8xxx2_tcpm_set_vconn(int port, int enable) -{ - /* - * IT8xxx2 doesn't have integrated circuit to source CC lines for VCONN. - * An external device like PPC or Power Switch has to source the VCONN. - */ - if (IS_ENABLED(CONFIG_USBC_VCONN)) { - if (enable) { - /* - * Unused cc will become Vconn SRC, disable cc analog - * module (ex.UP/RD/DET/Tx/Rx) and enable 5v tolerant. - */ - it8xxx2_enable_vconn(port, enable); - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) - /* Enable tcpc receive SOP' and SOP'' packet */ - it8xxx2_tcpm_decode_sop_prime_enable(port, - true); - /* Turn on Vconn power switch. */ - board_pd_vconn_ctrl(port, - USBPD_GET_PULL_CC_SELECTION(port) ? - USBPD_CC_PIN_2 : USBPD_CC_PIN_1, - enable); - } else { - /* - * If the pd port has previous connection and supplies - * Vconn, then RO jumping to RW reset the system, - * we never know which cc is the previous Vconn pin, - * so we always turn both cc pins off when disable - * Vconn power switch. - */ - board_pd_vconn_ctrl(port, USBPD_CC_PIN_1, enable); - board_pd_vconn_ctrl(port, USBPD_CC_PIN_2, enable); - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) - /* Disable tcpc receive SOP' and SOP'' packet */ - it8xxx2_tcpm_decode_sop_prime_enable(port, - false); - /* - * Before disabling cc 5v tolerant, we need to make - * sure cc voltage detector is enabled and Vconn is - * dropped below 3.3v (>500us) to avoid the potential - * risk of voltage fed back into Vcore. - */ - usleep(IT83XX_USBPD_T_VCONN_BELOW_3_3V); - /* - * Since our cc are not Vconn SRC, enable cc analog - * module (ex.UP/RD/DET/Tx/Rx) and disable 5v tolerant. - */ - it8xxx2_enable_vconn(port, enable); - } - } - - return EC_SUCCESS; -} - -static int it8xxx2_tcpm_set_msg_header(int port, int power_role, int data_role) -{ - /* 0: PD_ROLE_SINK, 1: PD_ROLE_SOURCE */ - if (power_role == PD_ROLE_SOURCE) - /* Bit0: source */ - IT83XX_USBPD_MHSR1(port) |= USBPD_REG_MASK_SOP_PORT_POWER_ROLE; - else - /* Bit0: sink */ - IT83XX_USBPD_MHSR1(port) &= ~USBPD_REG_MASK_SOP_PORT_POWER_ROLE; - - it8xxx2_set_data_role(port, data_role); - - return EC_SUCCESS; -} - -static int it8xxx2_tcpm_set_rx_enable(int port, int enable) -{ - /* Save rx_on */ - rx_en[port] = !!enable; - - if (enable) { - IT83XX_USBPD_IMR(port) &= ~USBPD_REG_MASK_MSG_RX_DONE; - IT83XX_USBPD_PDCSR1(port) |= - (USBPD_REG_MASK_SOP_RX_ENABLE | - USBPD_REG_MASK_HARD_RESET_RX_ENABLE); - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) - it8xxx2_tcpm_decode_sop_prime_enable(port, - sop_prime_en[port]); - } else { - IT83XX_USBPD_IMR(port) |= USBPD_REG_MASK_MSG_RX_DONE; - IT83XX_USBPD_PDCSR1(port) &= ~(USBPD_REG_MASK_SOP_RX_ENABLE | - USBPD_REG_MASK_SOPP_RX_ENABLE | - USBPD_REG_MASK_SOPPP_RX_ENABLE | - USBPD_REG_MASK_HARD_RESET_RX_ENABLE); - } - - return EC_SUCCESS; -} - -static int it8xxx2_tcpm_transmit(int port, - enum tcpci_msg_type type, - uint16_t header, - const uint32_t *data) -{ - int status = TCPC_TX_COMPLETE_FAILED; - - switch (type) { - case TCPCI_MSG_SOP: - case TCPCI_MSG_SOP_PRIME: - case TCPCI_MSG_SOP_PRIME_PRIME: - case TCPCI_MSG_SOP_DEBUG_PRIME: - case TCPCI_MSG_SOP_DEBUG_PRIME_PRIME: - status = it8xxx2_tx_data(port, - type, - header, - data); - break; - case TCPCI_MSG_TX_BIST_MODE_2: - it8xxx2_send_bist_mode2_pattern(port); - status = TCPC_TX_COMPLETE_SUCCESS; - break; - case TCPCI_MSG_TX_HARD_RESET: - status = it8xxx2_send_hw_reset(port); - break; - case TCPCI_MSG_CABLE_RESET: - status = it8xxx2_send_cable_reset(port); - break; - default: - status = TCPC_TX_COMPLETE_FAILED; - break; - } - pd_transmit_complete(port, status); - - return EC_SUCCESS; -} - -static int it8xxx2_tcpm_get_chip_info(int port, int live, - struct ec_response_pd_chip_info_v1 *chip_info) -{ - chip_info->vendor_id = USB_VID_ITE; - chip_info->product_id = ((IT83XX_GCTRL_CHIPID1 << 8) | - IT83XX_GCTRL_CHIPID2); - chip_info->device_id = IT83XX_GCTRL_CHIPVER & 0xf; - chip_info->fw_version_number = 0xEC; - - return EC_SUCCESS; -} - -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER -static int it8xxx2_tcpm_enter_low_power_mode(int port) -{ - /* - * ITE embedded TCPC SLEEP_MASK_USB_PD flag is only controlled by - * it8xxx2 driver in it8xxx2_set_pd_sleep_mask(), and do low power - * mode in idle_task(). - * In deep sleep mode, ITE TCPC clock is turned off, and the - * timer every 5ms to exit the mode and wakeup PD task to run - * (ex. change the CC lines termination). - */ - return EC_SUCCESS; -} -#endif - -#ifdef CONFIG_USB_PD_FRS_TCPC -static int it8xxx2_tcpm_set_frs_enable(int port, int enable) -{ - uint8_t mask = (USBPD_REG_FAST_SWAP_REQUEST_ENABLE | - USBPD_REG_FAST_SWAP_DETECT_ENABLE); - - if (enable) { - /* - * Disable HW auto turn off FRS requestion and detection - * when we receive soft or hard reset. - */ - IT83XX_USBPD_PDMSR(port) &= ~USBPD_REG_MASK_AUTO_FRS_DISABLE; - /* W/C status */ - IT83XX_USBPD_IFS(port) = 0x33; - /* Enable FRS detection (cc to GND) interrupt */ - IT83XX_USBPD_MIFS(port) &= ~(USBPD_REG_MASK_FAST_SWAP_ISR | - USBPD_REG_MASK_FAST_SWAP_DETECT_ISR); - /* Enable FRS detection (cc to GND) */ - IT83XX_USBPD_PDFSCR(port) = (IT83XX_USBPD_PDFSCR(port) & ~mask) - | USBPD_REG_FAST_SWAP_DETECT_ENABLE; - /* - * TODO(b/160210457): Enable HW auto trigger - * GPH3(port0)/GPH4(port1) output H/L after we detect FRS cc - * low signal. - */ - } else { - /* Disable FRS detection (cc to GND) interrupt */ - IT83XX_USBPD_MIFS(port) |= (USBPD_REG_MASK_FAST_SWAP_ISR | - USBPD_REG_MASK_FAST_SWAP_DETECT_ISR); - /* Disable FRS detection and requestion */ - IT83XX_USBPD_PDFSCR(port) &= ~mask; - /* - * TODO(b/160210457): Disable HW auto trigger - * GPH3(port0)/GPH4(port1) output H/L after we detect FRS cc - * low signal. - */ - } - - return EC_SUCCESS; -} -#endif - -static void it8xxx2_tcpm_switch_plug_out_type(int port) -{ - enum tcpc_cc_voltage_status cc1, cc2; - - /* Check what do we and partner cc assert */ - it8xxx2_tcpm_get_cc(port, &cc1, &cc2); - - if ((cc1 == TYPEC_CC_VOLT_RD && cc2 == TYPEC_CC_VOLT_RD) || - (cc1 == TYPEC_CC_VOLT_RA && cc2 == TYPEC_CC_VOLT_RA)) - /* We're source, switch to detect audio/debug plug out. */ - IT83XX_USBPD_TCDCR(port) = (IT83XX_USBPD_TCDCR(port) & - ~USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE) | - USBPD_REG_PLUG_OUT_DETECT_TYPE_SELECT | - USBPD_REG_PLUG_OUT_SELECT; - else if (cc1 == TYPEC_CC_VOLT_RD || cc2 == TYPEC_CC_VOLT_RD) - /* We're source, switch to detect sink plug out. */ - IT83XX_USBPD_TCDCR(port) = (IT83XX_USBPD_TCDCR(port) & - ~USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE & - ~USBPD_REG_PLUG_OUT_DETECT_TYPE_SELECT) | - USBPD_REG_PLUG_OUT_SELECT; - else if (cc1 >= TYPEC_CC_VOLT_RP_DEF || cc2 >= TYPEC_CC_VOLT_RP_DEF) - /* - * We're sink, disable detect interrupt, so messages on cc line - * won't trigger interrupt. - * NOTE: Plug out is detected by TCPM polling Vbus. - */ - IT83XX_USBPD_TCDCR(port) |= - USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE; - /* - * If not above cases, plug in interrupt will fire again, - * and call switch_plug_out_type() to set the right state. - */ -} - -void switch_plug_out_type(enum usbpd_port port) -{ - it8xxx2_tcpm_switch_plug_out_type(port); -} - -static void it8xxx2_init(enum usbpd_port port, int role) -{ - uint8_t cc_config = (port == USBPD_PORT_C ? - IT83XX_USBPD_CC_PIN_CONFIG2 : - IT83XX_USBPD_CC_PIN_CONFIG); - - if (IS_ENABLED(CONFIG_IT83XX_TUNE_CC_PHY)) { - /* Tune cc Tx pre-driving time */ - const struct cc_para_t *ptr = - board_get_cc_tuning_parameter(port); - - IT83XX_USBPD_CCPSR3_RISE(port) = ptr->rising_time; - IT83XX_USBPD_CCPSR4_FALL(port) = ptr->falling_time; - } - /* Reset and disable HW auto generate message header */ - IT83XX_USBPD_PDMSR(port) &= ~USBPD_REG_MASK_DISABLE_AUTO_GEN_TX_HEADER; - USBPD_SW_RESET(port); - /* According PD version set HW auto retry count */ - IT83XX_USBPD_PDCSR0(port) = (IT83XX_USBPD_PDCSR0(port) & ~0xC0) | - (CONFIG_PD_RETRY_COUNT << 6); - /* Disable Rx decode */ - it8xxx2_tcpm_set_rx_enable(port, 0); - if (IS_ENABLED(CONFIG_USB_PD_TCPMV1)) { - uint8_t flags = 0; - /* - * If explicit contract is set in bbram when EC boot up, then - * TCPMv1 set soft reset as first state instead of - * unattached.SNK, so we need to enable BMC PHY for tx module. - * - * NOTE: If the platform is without battery and connects to - * adapter, then cold reset EC, our Rd is always asserted on cc, - * so adapter keeps providing 5v and data in BBRAM are still - * alive. - */ - if ((pd_get_saved_port_flags(port, &flags) == EC_SUCCESS) && - (flags & PD_BBRMFLG_EXPLICIT_CONTRACT)) - USBPD_ENABLE_BMC_PHY(port); - } - /* Disable all interrupts */ - IT83XX_USBPD_IMR(port) = 0xff; - /* W/C status */ - IT83XX_USBPD_ISR(port) = 0xff; - /* Enable cc voltage detector */ - IT83XX_USBPD_CCGCR(port) &= ~USBPD_REG_MASK_DISABLE_CC_VOL_DETECTOR; - /* Select Rp value USB-DEFAULT (Rd value default connect with 5.1k) */ - it8xxx2_tcpm_select_rp_value(port, TYPEC_RP_USB); - /* Which cc pin connect in attached state. Default to cc1 */ - it8xxx2_select_polarity(port, USBPD_CC_PIN_1); - /* Change data role as the same power role */ - it8xxx2_set_data_role(port, role); - /* Set default power role and assert Rp/Rd */ - it8xxx2_set_power_role(port, role); - /* Disable vconn: connect cc analog module, disable cc 5v tolerant */ - it8xxx2_tcpm_set_vconn(port, 0); - /* Enable tx done and hard reset detect interrupt */ - IT83XX_USBPD_IMR(port) &= ~(USBPD_REG_MASK_MSG_TX_DONE | - USBPD_REG_MASK_HARD_RESET_DETECT); -#ifdef IT83XX_INTC_PLUG_IN_OUT_SUPPORT - /* - * When tcpc detect type-c plug in (cc lines voltage change), it will - * interrupt fw to wake pd task, so task can react immediately. - * - * W/C status and enable type-c plug-in detect interrupt. - */ - IT83XX_USBPD_TCDCR(port) = (IT83XX_USBPD_TCDCR(port) & - ~(USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE | - USBPD_REG_PLUG_OUT_SELECT)) | - USBPD_REG_PLUG_IN_OUT_DETECT_STAT; -#endif - /* Set cc1/cc2 pins alternate mode */ - *usbpd_ctrl_regs[port].cc1 = cc_config; - *usbpd_ctrl_regs[port].cc2 = cc_config; - task_clear_pending_irq(usbpd_ctrl_regs[port].irq); -#ifdef CONFIG_ZEPHYR - irq_connect_dynamic(usbpd_ctrl_regs[port].irq, 0, - (void (*)(const void *))chip_pd_irq, (void *)port, 0); -#endif - task_enable_irq(usbpd_ctrl_regs[port].irq); - USBPD_START(port); - /* - * Disconnect CCs Rd_DB from GND - * NOTE: CCs assert both Rd_5.1k and Rd_DB from USBPD_START() to - * disconnect Rd_DB about 1.5us. - */ - IT83XX_USBPD_CCPSR(port) |= (USBPD_REG_MASK_DISCONNECT_5_1K_CC2_DB | - USBPD_REG_MASK_DISCONNECT_5_1K_CC1_DB); -} - -static int it8xxx2_tcpm_init(int port) -{ - /* Initialize physical layer */ - it8xxx2_init(port, PD_ROLE_DEFAULT(port)); - - return EC_SUCCESS; -} - -static void it8xxx2_set_pd_sleep_mask(int port) -{ - int i; - bool prevent_deep_sleep = false; - - /* - * Set SLEEP_MASK_USB_PD for deep sleep mode: - * 1.Enable deep sleep mode, when all ITE ports are in Unattach.SRC/SNK - * state (HOOK_DISCONNECT called) and other ports aren't pd_capable(). - * 2.Disable deep sleep mode, when one of ITE port is in Attach.SRC/SNK - * state (HOOK_CONNECT called) or one of other ports is pd_capable(). - */ - for (i = 0; i < CONFIG_USB_PD_ITE_ACTIVE_PORT_COUNT; ++i) { - if (IT83XX_USBPD_PDGCR(i) & USBPD_REG_MASK_BMC_PHY) { - prevent_deep_sleep = true; - break; - } - } - - /* - * Check if any other ports have a PD port partner connected. Deep - * sleep is forbidden if any PD port partner is connected. Above, we - * only checked for the ITE ports. - */ - if (!prevent_deep_sleep) { - for (; i < board_get_usb_pd_port_count(); i++) - if (pd_capable(i)) - prevent_deep_sleep = true; - } - - if (prevent_deep_sleep) - disable_sleep(SLEEP_MASK_USB_PD); - else - enable_sleep(SLEEP_MASK_USB_PD); -} - -static void it8xxx2_tcpm_hook_connect(void) -{ - int port = TASK_ID_TO_PD_PORT(task_get_current()); - -#ifdef CONFIG_USB_PD_TCPMV2 - /* - * There are five cases that hook_connect() be called by TCPMv2: - * 1)AttachWait.SNK -> Attached.SNK: disable detect interrupt. - * 2)AttachWait.SRC -> Attached.SRC: enable detect plug out. - * 3)AttachWait.SNK -> Try.SRC -> TryWait.SNK -> Attached.SNK: we do - * Try.SRC fail, disable detect interrupt. - * 4)AttachWait.SNK -> Try.SRC -> Attached.SRC: we do Try.SRC - * successfully, need to switch to detect plug out. - * 5)Attached.SRC -> TryWait.SNK -> Attached.SNK: partner do Try.SRC - * successfully, disable detect interrupt. - * - * NOTE: Try.SRC and TryWait.SNK are embedded respectively in - * SRC_DISCONNECT and SNK_DISCONNECT in TCPMv1. Every time we go to - * Try.SRC/TryWait.SNK state, the plug in interrupt will be enabled and - * fire for 3), 4), 5) cases, then set correctly for the SRC detect plug - * out or the SNK disable detect, so TCPMv1 needn't this. - */ - it8xxx2_tcpm_switch_plug_out_type(port); -#endif - /* Enable PD PHY Tx and Rx module since type-c has connected. */ - USBPD_ENABLE_BMC_PHY(port); - it8xxx2_set_pd_sleep_mask(port); -} - -DECLARE_HOOK(HOOK_USB_PD_CONNECT, it8xxx2_tcpm_hook_connect, HOOK_PRIO_DEFAULT); - -static void it8xxx2_tcpm_hook_disconnect(void) -{ - int port = TASK_ID_TO_PD_PORT(task_get_current()); - - if (IS_ENABLED(IT83XX_INTC_PLUG_IN_OUT_SUPPORT)) - /* - * Switch to detect plug in and enable detect plug in interrupt, - * since pd task has detected a type-c physical disconnected. - */ - IT83XX_USBPD_TCDCR(port) &= ~(USBPD_REG_PLUG_OUT_SELECT | - USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE); - - /* Exit BIST test data mode */ - USBPD_SW_RESET(port); - - /* - * Init rx status and disable PD PHY Tx and Rx module for better power - * consumption since type-c has disconnected. - */ - rx_en[port] = 0; - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) - sop_prime_en[port] = 0; - USBPD_DISABLE_BMC_PHY(port); - it8xxx2_set_pd_sleep_mask(port); -} - -DECLARE_HOOK(HOOK_USB_PD_DISCONNECT, it8xxx2_tcpm_hook_disconnect, - HOOK_PRIO_DEFAULT); - -const struct tcpm_drv it8xxx2_tcpm_drv = { - .init = &it8xxx2_tcpm_init, - .release = &it8xxx2_tcpm_release, - .get_cc = &it8xxx2_tcpm_get_cc, - .select_rp_value = &it8xxx2_tcpm_select_rp_value, - .set_cc = &it8xxx2_tcpm_set_cc, - .set_polarity = &it8xxx2_tcpm_set_polarity, -#ifdef CONFIG_USB_PD_DECODE_SOP - .sop_prime_enable = &it8xxx2_tcpm_decode_sop_prime_enable, -#endif - .set_vconn = &it8xxx2_tcpm_set_vconn, - .set_msg_header = &it8xxx2_tcpm_set_msg_header, - .set_rx_enable = &it8xxx2_tcpm_set_rx_enable, - .get_message_raw = &it8xxx2_tcpm_get_message_raw, - .transmit = &it8xxx2_tcpm_transmit, -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - .drp_toggle = NULL, -#endif - .get_chip_info = &it8xxx2_tcpm_get_chip_info, -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER - .enter_low_power_mode = &it8xxx2_tcpm_enter_low_power_mode, -#endif -#ifdef CONFIG_USB_PD_FRS_TCPC - .set_frs_enable = &it8xxx2_tcpm_set_frs_enable, -#endif -}; diff --git a/driver/tcpm/ite_pd_intc.c b/driver/tcpm/ite_pd_intc.c deleted file mode 100644 index 2b5a391dfe..0000000000 --- a/driver/tcpm/ite_pd_intc.c +++ /dev/null @@ -1,87 +0,0 @@ -/* Copyright 2021 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 "common.h" -#include "it83xx_pd.h" -#include "ite_pd_intc.h" -#include "task.h" -#include "tcpm/tcpm.h" -#include "usb_pd.h" - -void chip_pd_irq(enum usbpd_port port) -{ - task_clear_pending_irq(usbpd_ctrl_regs[port].irq); - - /* check status */ - if (IS_ENABLED(IT83XX_INTC_FAST_SWAP_SUPPORT) && - IS_ENABLED(CONFIG_USB_PD_FRS_TCPC) && - IS_ENABLED(CONFIG_USB_PD_REV30)) { - /* - * FRS detection must handle first, because we need to short - * the interrupt -> board_frs_handler latency-critical time. - */ - if (USBPD_IS_FAST_SWAP_DETECT(port)) { - /* clear detect FRS signal (cc to GND) status */ - USBPD_CLEAR_FRS_DETECT_STATUS(port); - if (board_frs_handler) - board_frs_handler(port); - /* inform TCPMv2 to change state */ - pd_got_frs_signal(port); - } - } - - if (USBPD_IS_HARD_RESET_DETECT(port)) { - /* clear interrupt */ - IT83XX_USBPD_ISR(port) = USBPD_REG_MASK_HARD_RESET_DETECT; - USBPD_SW_RESET(port); - task_set_event(PD_PORT_TO_TASK_ID(port), - PD_EVENT_RX_HARD_RESET); - } - - if (USBPD_IS_RX_DONE(port)) { - tcpm_enqueue_message(port); - /* clear RX done interrupt */ - IT83XX_USBPD_ISR(port) = USBPD_REG_MASK_MSG_RX_DONE; - } - - if (USBPD_IS_TX_DONE(port)) { -#ifdef CONFIG_USB_PD_TCPM_DRIVER_IT8XXX2 - it8xxx2_clear_tx_error_status(port); - /* check TX status, clear by TX_DONE status too */ - if (USBPD_IS_TX_ERR(port)) - it8xxx2_get_tx_error_status(port); -#endif - /* clear TX done interrupt */ - IT83XX_USBPD_ISR(port) = USBPD_REG_MASK_MSG_TX_DONE; - task_set_event(PD_PORT_TO_TASK_ID(port), - TASK_EVENT_PHY_TX_DONE); - } - - if (IS_ENABLED(IT83XX_INTC_PLUG_IN_OUT_SUPPORT)) { - if (USBPD_IS_PLUG_IN_OUT_DETECT(port)) { - if (USBPD_IS_PLUG_IN(port)) - /* - * When tcpc detect type-c plug in: - * 1)If we are sink, disable detect interrupt, - * messages on cc line won't trigger interrupt. - * 2)If we are source, then set plug out - * detection. - */ - switch_plug_out_type(port); - else - /* - * When tcpc detect type-c plug out: - * switch to detect plug in. - */ - IT83XX_USBPD_TCDCR(port) &= - ~USBPD_REG_PLUG_OUT_SELECT; - - /* clear type-c device plug in/out detect interrupt */ - IT83XX_USBPD_TCDCR(port) |= - USBPD_REG_PLUG_IN_OUT_DETECT_STAT; - task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_CC); - } - } -} diff --git a/driver/tcpm/ite_pd_intc.h b/driver/tcpm/ite_pd_intc.h deleted file mode 100644 index 8123e1a233..0000000000 --- a/driver/tcpm/ite_pd_intc.h +++ /dev/null @@ -1,22 +0,0 @@ -/* Copyright 2021 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. - */ - -/* ITE PD INTC control module */ - -#ifndef __CROS_EC_ITE_PD_INTC_H -#define __CROS_EC_ITE_PD_INTC_H - -/** - * ITE embedded PD interrupt routine - * - * NOTE: Enable ITE embedded PD that it requires CONFIG_USB_PD_TCPM_ITE_ON_CHIP - * - * @param port Type-C port number - * - * @return none - */ -void chip_pd_irq(enum usbpd_port port); - -#endif /* __CROS_EC_ITE_PD_INTC_H */ diff --git a/driver/tcpm/mt6370.c b/driver/tcpm/mt6370.c deleted file mode 100644 index 100a4d9eeb..0000000000 --- a/driver/tcpm/mt6370.c +++ /dev/null @@ -1,222 +0,0 @@ -/* Copyright 2018 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. - * - * MT6370 TCPC Driver - */ - -#include "console.h" -#include "hooks.h" -#include "mt6370.h" -#include "task.h" -#include "tcpm/tcpci.h" -#include "tcpm/tcpm.h" -#include "timer.h" -#include "usb_mux.h" -#include "usb_pd.h" -#include "util.h" - -#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args) - -static int mt6370_polarity; - -/* i2c_write function which won't wake TCPC from low power mode. */ -static int mt6370_i2c_write8(int port, int reg, int val) -{ - return i2c_write8(tcpc_config[port].i2c_info.port, - tcpc_config[port].i2c_info.addr_flags, reg, val); -} - -static int mt6370_init(int port) -{ - int rv, val; - - rv = tcpc_read(port, MT6370_REG_IDLE_CTRL, &val); - - /* Only do soft-reset in shipping mode. (b:122017882) */ - if (!(val & MT6370_REG_SHIPPING_OFF)) { - - /* Software reset. */ - rv = tcpc_write(port, MT6370_REG_SWRESET, 1); - if (rv) - return rv; - - /* Need 1 ms for software reset. */ - msleep(1); - } - - /* The earliest point that we can do generic init. */ - rv = tcpci_tcpm_init(port); - - if (rv) - return rv; - - /* - * AUTO IDLE off, shipping off, select CK_300K from BICIO_320K, - * PD3.0 ext-msg on. - */ - rv = tcpc_write(port, MT6370_REG_IDLE_CTRL, - MT6370_REG_IDLE_SET(0, 1, 0, 0)); - /* CC Detect Debounce 5 */ - rv |= tcpc_write(port, MT6370_REG_TTCPC_FILTER, 5); - /* DRP Duty */ - rv |= tcpc_write(port, MT6370_REG_DRP_TOGGLE_CYCLE, 4); - rv |= tcpc_write16(port, MT6370_REG_DRP_DUTY_CTRL, 400); - /* Vconn OC on */ - rv |= tcpc_write(port, MT6370_REG_VCONN_CLIMITEN, 1); - /* PHY control */ - rv |= tcpc_write(port, MT6370_REG_PHY_CTRL1, - MT6370_REG_PHY_CTRL1_SET(0, 7, 0, 1)); - rv |= tcpc_write(port, MT6370_REG_PHY_CTRL3, 0x82); - - return rv; -} - -static inline int mt6370_init_cc_params(int port, int cc_res) -{ - int rv, en, sel; - - if (cc_res == TYPEC_CC_VOLT_RP_DEF) { /* RXCC threshold : 0.55V */ - en = 1; - sel = MT6370_OCCTRL_600MA | MT6370_MASK_BMCIO_RXDZSEL; - } else { /* RD threshold : 0.4V & RP threshold : 0.7V */ - en = 0; - sel = MT6370_OCCTRL_600MA; - } - rv = tcpc_write(port, MT6370_REG_BMCIO_RXDZEN, en); - if (!rv) - rv = tcpc_write(port, MT6370_REG_BMCIO_RXDZSEL, sel); - return rv; -} - -static int mt6370_get_cc(int port, enum tcpc_cc_voltage_status *cc1, - enum tcpc_cc_voltage_status *cc2) -{ - int status; - int rv; - int role, is_snk; - - rv = tcpc_read(port, TCPC_REG_CC_STATUS, &status); - - /* If tcpc read fails, return error and CC as open */ - if (rv) { - *cc1 = TYPEC_CC_VOLT_OPEN; - *cc2 = TYPEC_CC_VOLT_OPEN; - return rv; - } - - *cc1 = TCPC_REG_CC_STATUS_CC1(status); - *cc2 = TCPC_REG_CC_STATUS_CC2(status); - - /* - * If status is not open, then OR in termination to convert to - * enum tcpc_cc_voltage_status. - * - * MT6370 TCPC follows USB PD 1.0 protocol. When DRP not auto-toggling, - * it will not update the DRP_RESULT bits in TCPC_REG_CC_STATUS, - * instead, we should check CC1/CC2 bits in TCPC_REG_ROLE_CTRL. - */ - rv = tcpc_read(port, TCPC_REG_ROLE_CTRL, &role); - - if (TCPC_REG_ROLE_CTRL_DRP(role)) - is_snk = TCPC_REG_CC_STATUS_TERM(status); - else - /* CC1/CC2 states are the same, checking one-side is enough. */ - is_snk = TCPC_REG_CC_STATUS_CC1(role) == TYPEC_CC_RD; - - if (is_snk) { - if (*cc1 != TYPEC_CC_VOLT_OPEN) - *cc1 |= 0x04; - if (*cc2 != TYPEC_CC_VOLT_OPEN) - *cc2 |= 0x04; - } - - rv = mt6370_init_cc_params(port, (int)mt6370_polarity ? *cc1 : *cc2); - return rv; -} - -static int mt6370_set_cc(int port, int pull) -{ - if (pull == TYPEC_CC_RD) - mt6370_init_cc_params(port, TYPEC_CC_VOLT_RP_DEF); - return tcpci_tcpm_set_cc(port, pull); -} - -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER -static int mt6370_enter_low_power_mode(int port) -{ - int rv; - - /* VBUS_DET_EN for detecting charger plug. */ - rv = tcpc_write(port, MT6370_REG_BMC_CTRL, - MT6370_REG_BMCIO_LPEN | MT6370_REG_VBUS_DET_EN); - - if (rv) - return rv; - - return tcpci_enter_low_power_mode(port); -} -#endif - -static int mt6370_set_polarity(int port, enum tcpc_cc_polarity polarity) -{ - enum tcpc_cc_voltage_status cc1, cc2; - - mt6370_polarity = polarity; - mt6370_get_cc(port, &cc1, &cc2); - return tcpci_tcpm_set_polarity(port, polarity); -} - -int mt6370_vconn_discharge(int port) -{ - /* - * Write to mt6370 in low-power mode may return fail, but it is - * actually written. So we just ignore its return value. - */ - mt6370_i2c_write8(port, MT6370_REG_OVP_FLAG_SEL, - MT6370_REG_DISCHARGE_LVL); - /* Set MT6370_REG_DISCHARGE_EN bit and also the rest default value. */ - mt6370_i2c_write8(port, MT6370_REG_BMC_CTRL, - MT6370_REG_DISCHARGE_EN | - MT6370_REG_BMC_CTRL_DEFAULT); - - return EC_SUCCESS; -} - -/* MT6370 is a TCPCI compatible port controller */ -const struct tcpm_drv mt6370_tcpm_drv = { - .init = &mt6370_init, - .release = &tcpci_tcpm_release, - .get_cc = &mt6370_get_cc, -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - .check_vbus_level = &tcpci_tcpm_check_vbus_level, -#endif - .select_rp_value = &tcpci_tcpm_select_rp_value, - .set_cc = &mt6370_set_cc, - .set_polarity = &mt6370_set_polarity, -#ifdef CONFIG_USB_PD_DECODE_SOP - .sop_prime_enable = &tcpci_tcpm_sop_prime_enable, -#endif - .set_vconn = &tcpci_tcpm_set_vconn, - .set_msg_header = &tcpci_tcpm_set_msg_header, - .set_rx_enable = &tcpci_tcpm_set_rx_enable, - .get_message_raw = &tcpci_tcpm_get_message_raw, - .transmit = &tcpci_tcpm_transmit, - .tcpc_alert = &tcpci_tcpc_alert, -#ifdef CONFIG_USB_PD_DISCHARGE_TCPC - .tcpc_discharge_vbus = &tcpci_tcpc_discharge_vbus, -#endif -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - .drp_toggle = &tcpci_tcpc_drp_toggle, -#endif - .get_chip_info = &tcpci_get_chip_info, -#ifdef CONFIG_USB_PD_PPC - .set_snk_ctrl = &tcpci_tcpm_set_snk_ctrl, - .set_src_ctrl = &tcpci_tcpm_set_src_ctrl, -#endif -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER - .enter_low_power_mode = &mt6370_enter_low_power_mode, -#endif - .set_bist_test_mode = &tcpci_set_bist_test_mode, -}; diff --git a/driver/tcpm/mt6370.h b/driver/tcpm/mt6370.h deleted file mode 100644 index cdc3112a3e..0000000000 --- a/driver/tcpm/mt6370.h +++ /dev/null @@ -1,200 +0,0 @@ -/* Copyright 2018 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. - * - * MT6370 TCPC Driver - */ - -#ifndef __CROS_EC_USB_PD_TCPM_MT6370_H -#define __CROS_EC_USB_PD_TCPM_MT6370_H - -/* MT6370 Private RegMap */ - -#define MT6370_REG_PHY_CTRL1 0x80 -#define MT6370_REG_PHY_CTRL2 0x81 -#define MT6370_REG_PHY_CTRL3 0x82 -#define MT6370_REG_PHY_CTRL6 0x85 - -#define MT6370_REG_CLK_CTRL2 0x87 -#define MT6370_REG_CLK_CTRL3 0x88 - -#define MT6370_REG_RUST_STATUS 0x8A -#define MT6370_REG_RUST_INT_EVENT 0x8B -#define MT6370_REG_RUST_MASK 0x8C -#define MT6370_REG_BMC_CTRL 0x90 -#define MT6370_REG_BMCIO_RXDZSEL 0x93 -#define MT6370_REG_VCONN_CLIMITEN 0x95 - -#define MT6370_REG_OVP_FLAG_SEL 0x96 - -#define MT6370_REG_RT_STATUS 0x97 -#define MT6370_REG_RT_INT 0x98 -#define MT6370_REG_RT_MASK 0x99 -#define RT5081_REG_BMCIO_RXDZEN 0x9A -#define MT6370_REG_IDLE_CTRL 0x9B -#define MT6370_REG_INTRST_CTRL 0x9C -#define MT6370_REG_WATCHDOG_CTRL 0x9D -#define MT6370_REG_I2CRST_CTRL 0X9E - -#define MT6370_REG_SWRESET 0xA0 -#define MT6370_REG_TTCPC_FILTER 0xA1 -#define MT6370_REG_DRP_TOGGLE_CYCLE 0xA2 -#define MT6370_REG_DRP_DUTY_CTRL 0xA3 -#define MT6370_REG_RUST_DETECTION 0xAD -#define MT6370_REG_RUST_CONTROL 0xAE -#define MT6370_REG_BMCIO_RXDZEN 0xAF -#define MT6370_REG_DRP_RUST 0xB9 - -#define MT6370_REG_UNLOCK_PW2 0xF0 -#define MT6370_REG_UNLOCK_PW1 0xF1 - -#define MT6370_TCPC_I2C_ADDR_FLAGS 0x4E - -/* - * MT6370_REG_PHY_CTRL1 0x80 - */ - -#define MT6370_REG_PHY_CTRL1_SET(retry_discard, toggle_cnt, bus_idle_cnt, \ - rx_filter) \ - ((retry_discard << 7) | (toggle_cnt << 4) | (bus_idle_cnt << 2) | \ - (rx_filter & 0x03)) - -/* - * MT6370_REG_CLK_CTRL2 0x87 - */ - -#define MT6370_REG_CLK_DIV_600K_EN BIT(7) -#define MT6370_REG_CLK_BCLK2_EN BIT(6) -#define MT6370_REG_CLK_BCLK2_TG_EN BIT(5) -#define MT6370_REG_CLK_DIV_300K_EN BIT(3) -#define MT6370_REG_CLK_CK_300K_EN BIT(2) -#define MT6370_REG_CLK_BCLK_EN BIT(1) -#define MT6370_REG_CLK_BCLK_TH_EN BIT(0) - -/* - * MT6370_REG_CLK_CTRL3 0x88 - */ - -#define MT6370_REG_CLK_OSCMUX_RG_EN BIT(7) -#define MT6370_REG_CLK_CK_24M_EN BIT(6) -#define MT6370_REG_CLK_OSC_RG_EN BIT(5) -#define MT6370_REG_CLK_DIV_2P4M_EN BIT(4) -#define MT6370_REG_CLK_CK_2P4M_EN BIT(3) -#define MT6370_REG_CLK_PCLK_EN BIT(2) -#define MT6370_REG_CLK_PCLK_RG_EN BIT(1) -#define MT6370_REG_CLK_PCLK_TG_EN BIT(0) - -/* - * MT6370_REG_RX_TX_DBG 0x8b - */ - -#define MT6370_REG_RX_TX_DBG_RX_BUSY BIT(7) -#define MT6370_REG_RX_TX_DBG_TX_BUSY BIT(6) - -/* - * MT6370_REG_BMC_CTRL 0x90 - */ - -#define MT6370_REG_IDLE_EN BIT(6) -#define MT6370_REG_DISCHARGE_EN BIT(5) -#define MT6370_REG_BMCIO_LPRPRD BIT(4) -#define MT6370_REG_BMCIO_LPEN BIT(3) -#define MT6370_REG_BMCIO_BG_EN BIT(2) -#define MT6370_REG_VBUS_DET_EN BIT(1) -#define MT6370_REG_BMCIO_OSC_EN BIT(0) -#define MT6370_REG_BMC_CTRL_DEFAULT \ - (MT6370_REG_BMCIO_BG_EN | MT6370_REG_VBUS_DET_EN | \ - MT6370_REG_BMCIO_OSC_EN) - -/* - * MT6370_REG_BMCIO_RXDZSEL 0x93 - */ - -#define MT6370_MASK_OCCTRL_SEL 0xE0 -#define MT6370_OCCTRL_600MA 0x80 -#define MT6370_MASK_BMCIO_RXDZSEL BIT(0) - -/* - * MT6370_REG_OVP_FLAG_SEL 0x96 - */ - -#define MT6370_MASK_DISCHARGE_LVL 0x03 -#define MT6370_REG_DISCHARGE_LVL BIT(0) - -/* - * MT6370_REG_RT_STATUS 0x97 - */ - -#define MT6370_REG_RA_DETACH BIT(5) -#define MT6370_REG_VBUS_80 BIT(1) - -/* - * MT6370_REG_RT_INT 0x98 - */ - -#define MT6370_REG_INT_RA_DETACH BIT(5) -#define MT6370_REG_INT_WATCHDOG BIT(2) -#define MT6370_REG_INT_VBUS_80 BIT(1) -#define MT6370_REG_INT_WAKEUP BIT(0) - -/* - * MT6370_REG_RT_MASK 0x99 - */ - -#define MT6370_REG_M_RA_DETACH BIT(5) -#define MT6370_REG_M_WATCHDOG BIT(2) -#define MT6370_REG_M_VBUS_80 BIT(1) -#define MT6370_REG_M_WAKEUP BIT(0) - -/* - * MT6370_REG_IDLE_CTRL 0x9B - */ - -#define MT6370_REG_CK_300K_SEL BIT(7) -#define MT6370_REG_SHIPPING_OFF BIT(5) -#define MT6370_REG_ENEXTMSG BIT(4) -#define MT6370_REG_AUTOIDLE_EN BIT(3) - -/* timeout = (tout*2+1) * 6.4ms */ -#ifdef CONFIG_USB_PD_REV30 -#define MT6370_REG_IDLE_SET(ck300, ship_dis, auto_idle, tout) \ - ((ck300 << 7) | (ship_dis << 5) | (auto_idle << 3) | (tout & 0x07) | \ - MT6370_REG_ENEXTMSG) -#else -#define MT6370_REG_IDLE_SET(ck300, ship_dis, auto_idle, tout) \ - ((ck300 << 7) | (ship_dis << 5) | (auto_idle << 3) | (tout & 0x07)) -#endif - -/* - * MT6370_REG_INTRST_CTRL 0x9C - */ - -#define MT6370_REG_INTRST_EN BIT(7) - -/* timeout = (tout+1) * 0.2sec */ -#define MT6370_REG_INTRST_SET(en, tout) ((en << 7) | (tout & 0x03)) - -/* - * MT6370_REG_WATCHDOG_CTRL 0x9D - */ - -#define MT6370_REG_WATCHDOG_EN BIT(7) - -/* timeout = (tout+1) * 0.4sec */ -#define MT6370_REG_WATCHDOG_CTRL_SET(en, tout) ((en << 7) | (tout & 0x07)) - -/* - * MT6370_REG_I2CRST_CTRL 0x9E - */ - -#define MT6370_REG_I2CRST_EN BIT(7) - -/* timeout = (tout+1) * 12.5ms */ -#define MT6370_REG_I2CRST_SET(en, tout) ((en << 7) | (tout & 0x0f)) - -extern const struct tcpm_drv mt6370_tcpm_drv; - -/* Enable VCONN discharge. */ -int mt6370_vconn_discharge(int port); - -#endif /* __CROS_EC_USB_PD_TCPM_MT6370_H */ diff --git a/driver/tcpm/nct38xx.c b/driver/tcpm/nct38xx.c deleted file mode 100644 index 00240516e5..0000000000 --- a/driver/tcpm/nct38xx.c +++ /dev/null @@ -1,377 +0,0 @@ -/* - * Copyright 2019 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. - */ - -/* Type-C port manager for Nuvoton NCT38XX. */ - -#include "common.h" -#include "console.h" -#include "hooks.h" -#include "nct38xx.h" -#include "task.h" -#include "tcpm/tcpci.h" -#include "usb_common.h" - -#if !defined(CONFIG_USB_PD_TCPM_TCPCI) -#error "NCT38XX is using part of standard TCPCI control" -#error "Please upgrade your board configuration" -#endif - -#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) -#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) - -static enum nct38xx_boot_type boot_type[CONFIG_USB_PD_PORT_MAX_COUNT]; - -enum nct38xx_boot_type nct38xx_get_boot_type(int port) -{ - return boot_type[port]; -} - -void nct38xx_reset_notify(int port) -{ - /* A full reset also resets the chip's dead battery boot status */ - boot_type[port] = NCT38XX_BOOT_UNKNOWN; -} - -static int nct38xx_init(int port) -{ - int rv; - int reg; - - /* - * Detect dead battery boot by the default role control value of 0x0A - * once per EC run - */ - if (boot_type[port] == NCT38XX_BOOT_UNKNOWN) { - RETURN_ERROR(tcpc_read(port, TCPC_REG_ROLE_CTRL, ®)); - - if (reg == NCT38XX_ROLE_CTRL_DEAD_BATTERY) - boot_type[port] = NCT38XX_BOOT_DEAD_BATTERY; - else - boot_type[port] = NCT38XX_BOOT_NORMAL; - } - - RETURN_ERROR(tcpc_read(port, TCPC_REG_POWER_STATUS, ®)); - - /* - * Set TCPC_CONTROL.DebugAccessoryControl = 1 to control by TCPM, - * not TCPC in most cases. This must be left alone if we're on a - * dead battery boot with a debug accessory. CC line detection will - * be delayed if we have booted from a dead battery with a debug - * accessory and change this bit (see b/186799392). - */ - if ((boot_type[port] == NCT38XX_BOOT_DEAD_BATTERY) && - (reg & TCPC_REG_POWER_STATUS_DEBUG_ACC_CON)) - CPRINTS("C%d: Booted in dead battery mode, not changing debug" - " control", port); - else if (tcpc_config[port].flags & TCPC_FLAGS_NO_DEBUG_ACC_CONTROL) - CPRINTS("C%d: NO_DEBUG_ACC_CONTROL", port); - else - RETURN_ERROR(tcpc_update8(port, TCPC_REG_TCPC_CTRL, - TCPC_REG_TCPC_CTRL_DEBUG_ACC_CONTROL, - MASK_SET)); - - /* - * Write to the CONTROL_OUT_EN register to enable: - * [6] - CONNDIREN : Connector direction indication output enable - * [2] - SNKEN : VBUS sink enable output enable - * [0] - SRCEN : VBUS source voltage enable output enable - */ - reg = NCT38XX_REG_CTRL_OUT_EN_SRCEN | - NCT38XX_REG_CTRL_OUT_EN_SNKEN | - NCT38XX_REG_CTRL_OUT_EN_CONNDIREN; - - rv = tcpc_write(port, NCT38XX_REG_CTRL_OUT_EN, reg); - if (rv) - return rv; - - /* Disable OVP */ - rv = tcpc_update8(port, - TCPC_REG_FAULT_CTRL, - TCPC_REG_FAULT_CTRL_VBUS_OVP_FAULT_DIS, - MASK_SET); - if (rv) - return rv; - - /* Enable VBus monitor and Disable FRS */ - rv = tcpc_update8(port, - TCPC_REG_POWER_CTRL, - (TCPC_REG_POWER_CTRL_VBUS_VOL_MONITOR_DIS | - TCPC_REG_POWER_CTRL_FRS_ENABLE), - MASK_CLR); - if (rv) - return rv; - - /* Set FRS direction for SNK detect, if FRS is enabled */ - if (IS_ENABLED(CONFIG_USB_PD_FRS_TCPC)) { - reg = TCPC_REG_DEV_CAP_2_SNK_FR_SWAP; - rv = tcpc_write(port, TCPC_REG_DEV_CAP_2, reg); - if (rv) - return rv; - - reg = TCPC_REG_CONFIG_EXT_1_FR_SWAP_SNK_DIR; - rv = tcpc_write(port, TCPC_REG_CONFIG_EXT_1, reg); - if (rv) - return rv; - } - - /* Start VBus monitor */ - rv = tcpc_write(port, TCPC_REG_COMMAND, - TCPC_REG_COMMAND_ENABLE_VBUS_DETECT); - if (rv) - return rv; - - /** - * Set driver specific ALERT mask bits - * - * Wake up on faults - */ - reg = TCPC_REG_ALERT_FAULT; - - /* - * Enable the Vendor Define alert event only when the IO expander - * feature is defined - */ - if (IS_ENABLED(CONFIG_IO_EXPANDER_NCT38XX)) - reg |= TCPC_REG_ALERT_VENDOR_DEF; - - rv = tcpc_update16(port, - TCPC_REG_ALERT_MASK, - reg, - MASK_SET); - - if (rv) - return rv; - - /* Enable full VCONN protection (Over-Current and Short-Circuit) */ - reg = NCT38XX_REG_VBC_FAULT_CTL_VC_OCP_EN | - NCT38XX_REG_VBC_FAULT_CTL_VC_SCP_EN | - NCT38XX_REG_VBC_FAULT_CTL_FAULT_VC_OFF; - - rv = tcpc_update8(port, - NCT38XX_REG_VBC_FAULT_CTL, - reg, - MASK_SET); - - return rv; -} - -static int nct38xx_tcpm_init(int port) -{ - int rv; - - rv = tcpci_tcpm_init(port); - if (rv) - return rv; - - return nct38xx_init(port); -} - -static int nct38xx_tcpm_set_cc(int port, int pull) -{ - /* - * Setting the CC lines to open/open requires that the NCT CTRL_OUT - * register has sink disabled. Otherwise, when no battery is connected: - * - * 1. You set CC lines to Open/Open. This is physically happening on - * the CC line. - * 2. Since CC is now Open/Open, the internal TCPC HW state machine - * is no longer in Attached.Snk and therefore our TCPC HW - * automatically opens the sink switch (de-assert the VBSNK_EN pin) - * 3. Since sink switch is open, the TCPC VCC voltage starts to drop. - * 4. When TCPC VCC gets below ~2.7V the TCPC will reset and therefore - * it will present Rd/Rd on the CC lines. Also the VBSNK_EN pin - * after reset is Hi-Z, so the sink switch will get closed again. - * - * Disabling SNKEN makes the VBSNK_EN pin Hi-Z, so - * USB_Cx_TCPC_VBSNK_EN_L will be asserted by external - * pull-down, so only do so if already sinking, otherwise - * both source and sink switches can be closed, which should - * never happen (b/166850036). - * - * SNKEN will be re-enabled in nct38xx_init above (from tcpm_init), or - * when CC lines are set again, or when sinking is disabled. - */ - int rv; - enum mask_update_action action = - pull == TYPEC_CC_OPEN && tcpm_get_snk_ctrl(port) ? - MASK_CLR : MASK_SET; - - rv = tcpc_update8(port, - NCT38XX_REG_CTRL_OUT_EN, - NCT38XX_REG_CTRL_OUT_EN_SNKEN, - action); - if (rv) - return rv; - - return tcpci_tcpm_set_cc(port, pull); -} - -#ifdef CONFIG_USB_PD_PPC -static int nct38xx_tcpm_set_snk_ctrl(int port, int enable) -{ - int rv; - - /* - * To disable sinking, SNKEN must be enabled so that - * USB_Cx_TCPC_VBSNK_EN_L will be driven high. - */ - if (!enable) { - rv = tcpc_update8(port, - NCT38XX_REG_CTRL_OUT_EN, - NCT38XX_REG_CTRL_OUT_EN_SNKEN, - MASK_SET); - if (rv) - return rv; - } - - return tcpci_tcpm_set_snk_ctrl(port, enable); -} -#endif - -static inline int tcpc_read_alert_no_lpm_exit(int port, int *val) -{ - return tcpc_addr_read16_no_lpm_exit(port, - tcpc_config[port].i2c_info.addr_flags, - TCPC_REG_ALERT, val); -} - -/* Map Type-C port to IOEX port */ -__overridable int board_map_nct38xx_tcpc_port_to_ioex(int port) -{ - return port; -} - -static void nct38xx_tcpc_alert(int port) -{ - int alert, rv; - - /* - * The nct3808 is a dual port chip with a shared ALERT - * pin. Avoid taking a port out of LPM if it is not alerting. - * - * The nct38xx exits Idle mode when ALERT is signaled, so there - * is no need to run the TCPM LPM exit code to check the ALERT - * register bits (Ref. NCT38n7/8 Datasheet S 2.3.4 "Setting the - * I2C to * Idle"). In fact, running the TCPM LPM exit code - * causes a new CC Status ALERT which has the effect of creating - * a new ALERT as a side-effect of handing an ALERT. - */ - rv = tcpc_read_alert_no_lpm_exit(port, &alert); - if (rv == EC_SUCCESS && alert == TCPC_REG_ALERT_NONE) { - /* No ALERT on this port, return early. */ - return; - } - - /* Process normal TCPC ALERT event and clear status. */ - tcpci_tcpc_alert(port); - - /* - * If the IO expander feature is enabled, use the ALERT register - * value read before it was cleared by calling - * tcpci_tcpc_alert(). Check the Vendor Defined Alert bit to - * handle the IOEX IO's interrupt event. - */ - if (IS_ENABLED(CONFIG_IO_EXPANDER_NCT38XX) && - rv == EC_SUCCESS && (alert & TCPC_REG_ALERT_VENDOR_DEF)) { - int ioexport; - - ioexport = board_map_nct38xx_tcpc_port_to_ioex(port); - nct38xx_ioex_event_handler(ioexport); - } -} - -static int nct3807_handle_fault(int port, int fault) -{ - int rv = EC_SUCCESS; - - /* Registers are set to default, initialize for our use */ - if (fault & TCPC_REG_FAULT_STATUS_ALL_REGS_RESET) { - rv = nct38xx_init(port); - } else { - /* We don't use TCPC OVP, so just disable it */ - if (fault & TCPC_REG_FAULT_STATUS_VBUS_OVER_VOLTAGE) { - /* Disable OVP */ - rv = tcpc_update8(port, - TCPC_REG_FAULT_CTRL, - TCPC_REG_FAULT_CTRL_VBUS_OVP_FAULT_DIS, - MASK_SET); - if (rv) - return rv; - } - /* Failing AutoDischargeDisconnect should disable it */ - if (fault & TCPC_REG_FAULT_STATUS_AUTO_DISCHARGE_FAIL) - tcpm_enable_auto_discharge_disconnect(port, 0); - } - return rv; -} - -__maybe_unused static int nct38xx_set_frs_enable(int port, int enable) -{ - /* - * From b/192012189: Enabling FRS for this chip should: - * - * 1. Make sure that the sink will not disconnect if Vbus will drop - * due to the Fast Role Swap by setting VBUS_SINK_DISCONNECT_THRESHOLD - * to 0 - * 2. Enable the FRS interrupt (already done in TCPCI alert init) - * 3. Set POWER_CONTORL.FastRoleSwapEnable to 1 - */ - RETURN_ERROR(tcpc_write16(port, - TCPC_REG_VBUS_SINK_DISCONNECT_THRESH, - enable ? 0x0000 : - TCPC_REG_VBUS_SINK_DISCONNECT_THRESH_DEFAULT)); - - return tcpc_update8(port, - TCPC_REG_POWER_CTRL, - TCPC_REG_POWER_CTRL_FRS_ENABLE, - enable ? MASK_SET : MASK_CLR); -} - -const struct tcpm_drv nct38xx_tcpm_drv = { - .init = &nct38xx_tcpm_init, - .release = &tcpci_tcpm_release, - .get_cc = &tcpci_tcpm_get_cc, -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - .check_vbus_level = &tcpci_tcpm_check_vbus_level, -#endif - .select_rp_value = &tcpci_tcpm_select_rp_value, - .set_cc = &nct38xx_tcpm_set_cc, - .set_polarity = &tcpci_tcpm_set_polarity, -#ifdef CONFIG_USB_PD_DECODE_SOP - .sop_prime_enable = &tcpci_tcpm_sop_prime_enable, -#endif - .set_vconn = &tcpci_tcpm_set_vconn, - .set_msg_header = &tcpci_tcpm_set_msg_header, - .set_rx_enable = &tcpci_tcpm_set_rx_enable, - .get_message_raw = &tcpci_tcpm_get_message_raw, - .transmit = &tcpci_tcpm_transmit, - .tcpc_alert = &nct38xx_tcpc_alert, -#ifdef CONFIG_USB_PD_DISCHARGE_TCPC - .tcpc_discharge_vbus = &tcpci_tcpc_discharge_vbus, -#endif - .tcpc_enable_auto_discharge_disconnect = - &tcpci_tcpc_enable_auto_discharge_disconnect, - .debug_accessory = &tcpci_tcpc_debug_accessory, - -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - .drp_toggle = &tcpci_tcpc_drp_toggle, -#endif -#ifdef CONFIG_USB_PD_PPC - .get_snk_ctrl = &tcpci_tcpm_get_snk_ctrl, - .set_snk_ctrl = &nct38xx_tcpm_set_snk_ctrl, - .get_src_ctrl = &tcpci_tcpm_get_src_ctrl, - .set_src_ctrl = &tcpci_tcpm_set_src_ctrl, -#endif - .get_chip_info = &tcpci_get_chip_info, -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER - .enter_low_power_mode = &tcpci_enter_low_power_mode, -#endif - .set_bist_test_mode = &tcpci_set_bist_test_mode, -#ifdef CONFIG_USB_PD_FRS_TCPC - .set_frs_enable = &nct38xx_set_frs_enable, -#endif - .handle_fault = &nct3807_handle_fault, -}; diff --git a/driver/tcpm/nct38xx.h b/driver/tcpm/nct38xx.h deleted file mode 100644 index a63a9f0808..0000000000 --- a/driver/tcpm/nct38xx.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2019 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. - */ - -/* Nuvoton Type-C port controller */ - -#ifndef __CROS_EC_USB_PD_TCPM_NCT38XX_H -#define __CROS_EC_USB_PD_TCPM_NCT38XX_H - -/* Chip variant ID (Part number) */ -#define NCT38XX_VARIANT_MASK 0x1C -#define NCT38XX_VARIANT_3807 0x0 -#define NCT38XX_VARIANT_3808 0x2 - -/* There are two IO ports in NCT3807 */ -#define NCT38XX_NCT3807_MAX_IO_PORT 2 -/* There is only one IO port in NCT3808 */ -#define NCT38XX_NCT3808_MAX_IO_PORT 1 - -#define NCT38XX_SUPPORT_GPIO_FLAGS (GPIO_OPEN_DRAIN | GPIO_INPUT | \ - GPIO_OUTPUT | GPIO_LOW | GPIO_HIGH | GPIO_INT_F_RISING | \ - GPIO_INT_F_FALLING | GPIO_INT_F_HIGH | GPIO_INT_F_LOW) - -/* I2C interface */ -#define NCT38XX_I2C_ADDR1_1_FLAGS 0x70 -#define NCT38XX_I2C_ADDR1_2_FLAGS 0x71 -#define NCT38XX_I2C_ADDR1_3_FLAGS 0x72 -#define NCT38XX_I2C_ADDR1_4_FLAGS 0x73 - -#define NCT38XX_I2C_ADDR2_1_FLAGS 0x74 -#define NCT38XX_I2C_ADDR2_2_FLAGS 0x75 -#define NCT38XX_I2C_ADDR2_3_FLAGS 0x76 -#define NCT38XX_I2C_ADDR2_4_FLAGS 0x77 - -#define NCT38XX_REG_VENDOR_ID_L 0x00 -#define NCT38XX_REG_VENDOR_ID_H 0x01 -#define NCT38XX_VENDOR_ID 0x0416 - -#define NCT38XX_PRODUCT_ID 0xC301 - -/* - * Default value from the ROLE_CTRL register on first boot will depend on - * whether we're coming from a dead battery state. - */ -#define NCT38XX_ROLE_CTRL_DEAD_BATTERY 0x0A -#define NCT39XX_ROLE_CTRL_GOOD_BATTERY 0x4A - -#define NCT38XX_REG_GPIO_DATA_IN(n) (0xC0 + ((n) * 8)) -#define NCT38XX_REG_GPIO_DATA_OUT(n) (0xC1 + ((n) * 8)) -#define NCT38XX_REG_GPIO_DIR(n) (0xC2 + ((n) * 8)) -#define NCT38XX_REG_GPIO_OD_SEL(n) (0xC3 + ((n) * 8)) -#define NCT38XX_REG_GPIO_ALERT_RISE(n) (0xC4 + ((n) * 8)) -#define NCT38XX_REG_GPIO_ALERT_FALL(n) (0xC5 + ((n) * 8)) -#define NCT38XX_REG_GPIO_ALERT_LEVEL(n) (0xC6 + ((n) * 8)) -#define NCT38XX_REG_GPIO_ALERT_MASK(n) (0xC7 + ((n) * 8)) -#define NCT38XX_REG_MUX_CONTROL 0xD0 -#define NCT38XX_REG_GPIO_ALERT_STAT(n) (0xD4 + (n)) - -/* NCT3808 only supports GPIO 2/3/4/6/7 */ -#define NCT38XXX_3808_VALID_GPIO_MASK 0xDC - -#define NCT38XX_REG_CTRL_OUT_EN 0xD2 -#define NCT38XX_REG_CTRL_OUT_EN_SRCEN (1 << 0) -#define NCT38XX_REG_CTRL_OUT_EN_FASTEN (1 << 1) -#define NCT38XX_REG_CTRL_OUT_EN_SNKEN (1 << 2) -#define NCT38XX_REG_CTRL_OUT_EN_CONNDIREN (1 << 6) - -#define NCT38XX_REG_VBC_FAULT_CTL 0xD7 -#define NCT38XX_REG_VBC_FAULT_CTL_VC_OCP_EN (1 << 0) -#define NCT38XX_REG_VBC_FAULT_CTL_VC_SCP_EN (1 << 1) -#define NCT38XX_REG_VBC_FAULT_CTL_FAULT_VC_OFF (1 << 3) -#define NCT38XX_REG_VBC_FAULT_CTL_VB_OCP_OFF (1 << 4) -#define NCT38XX_REG_VBC_FAULT_CTL_VC_OVP_OFF (1 << 5) - -#define NCT38XX_RESET_HOLD_DELAY_MS 1 - -/* - * From the datasheet (section 4.4.2 Reset Timing) as following: - * | Min | Max | - * ----------------------+-------+-------+ - * NCT3807 (single port) | x | 1.5ms | - * ----------------------+-------+-------+ - * NCT3808 (dual port) | x | 3ms | - * ----------------------+-------+-------+ - */ -#define NCT3807_RESET_POST_DELAY_MS 2 -#define NCT3808_RESET_POST_DELAY_MS 3 - -extern const struct tcpm_drv nct38xx_tcpm_drv; - -/* - * The interrupt handler to handle Vendor Define ALERT event from IOEX chip. - * - * Normally, the Vendor Define event should be checked by the NCT38XX TCPCI - * driver's tcpc_alert function. - * This function is only included when NCT38XX TCPC driver is not included. - * (i.e. CONFIG_USB_PD_TCPM_NCT38XX is not defined) - */ -void nct38xx_ioex_handle_alert(int ioex); - -/* - * Check which IO's interrupt event is triggered. If any, call its - * registered interrupt handler. - * - * @param ioex I/O expander number - * @return EC_SUCCESS on success else error - */ -int nct38xx_ioex_event_handler(int ioex); - -/* - * Board level function to map USB-C port to IOEX port - * - * Default function assumes USB-C port number to be same as the - * I/O expander port number. If this logic differs, add an - * overridable function at the board level. - * - * @param port USB-C port number - * @return IOEX port number - */ -__override_proto int board_map_nct38xx_tcpc_port_to_ioex(int port); - -enum nct38xx_boot_type { - NCT38XX_BOOT_UNKNOWN, - NCT38XX_BOOT_DEAD_BATTERY, - NCT38XX_BOOT_NORMAL, -}; - -/** - * Collect our boot type from the driver - * - * @param port USB-C port number - * @return Returns the boot type detected for this chip - */ -enum nct38xx_boot_type nct38xx_get_boot_type(int port); - -/** - * Notify the driver that the TCPC has been reset, and any stored state from - * the chip should therefore be gathered again. This should be called when - * board_reset_pd_mcu is called after init time. - * - * @param port USB-C port number which has been reset - */ -void nct38xx_reset_notify(int port); - -extern const struct ioexpander_drv nct38xx_ioexpander_drv; - -#endif /* defined(__CROS_EC_USB_PD_TCPM_NCT38XX_H) */ diff --git a/driver/tcpm/ps8xxx.c b/driver/tcpm/ps8xxx.c deleted file mode 100644 index 4643c669c0..0000000000 --- a/driver/tcpm/ps8xxx.c +++ /dev/null @@ -1,1037 +0,0 @@ -/* Copyright 2017 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. - */ - -/* - * Type-C port manager for Parade PS8XXX with integrated superspeed muxes. - * - * Supported TCPCs: - * - PS8705 - * - PS8751 - * - PS8755 - * - PS8805 - * - PS8815 - */ - -#include "common.h" -#include "console.h" -#include "ps8xxx.h" -#include "tcpm/tcpci.h" -#include "tcpm/tcpm.h" -#include "timer.h" -#include "usb_mux.h" -#include "usb_pd.h" - -#if !defined(CONFIG_USB_PD_TCPM_PS8705) && \ - !defined(CONFIG_USB_PD_TCPM_PS8751) && \ - !defined(CONFIG_USB_PD_TCPM_PS8755) && \ - !defined(CONFIG_USB_PD_TCPM_PS8805) && \ - !defined(CONFIG_USB_PD_TCPM_PS8815) -#error "Unsupported PS8xxx TCPC." -#endif - -#if !defined(CONFIG_USB_PD_TCPM_TCPCI) || \ - !defined(CONFIG_USB_PD_TCPM_MUX) || \ - !defined(CONFIG_USBC_SS_MUX) - -#error "PS8XXX is using a standard TCPCI interface with integrated mux control" -#error "Please upgrade your board configuration" - -#endif - -#ifdef CONFIG_USB_PD_TCPM_PS8751 -/* PS8751 cannot run with PD 3.0 (see b/148554997 for details) */ -#if defined(CONFIG_USB_PD_REV30) -#error "PS8751 cannot run with PD 3.0. Fall back to using PD 2.0" -#endif - -#endif /* CONFIG_USB_PD_TCPM_PS8751 */ - -#ifdef CONFIG_USB_PD_TCPM_PS8751_CUSTOM_MUX_DRIVER -#if !defined(CONFIG_USB_PD_TCPM_PS8751) -#error "Custom MUX driver is available only for PS8751" -#endif - -#endif /* CONFIG_USB_PD_TCPM_PS8751_CUSTOM_MUX_DRIVER */ - -#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) -#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) - -#define PS8XXX_I2C_RECOVERY_DELAY_MS 10 - -/* - * The product_id per ports here is expected to be set in callback function - - * .init of tcpm_drv by calling board_get_ps8xxx_product_id(). - * - * In case of CONFIG_USB_PD_TCPM_MULTI_PS8XXX enabled, board code should - * override the board_get_ps8xxx_product_id() for getting the correct id. - */ -static uint16_t product_id[CONFIG_USB_PD_PORT_MAX_COUNT]; - -/* - * Revisions A1 and A0 of the PS8815 can corrupt the transmit buffer when - * updating the transmit buffer within 1ms of writing the ROLE_CONTROL - * register. When this version of silicon is detected, add a 1ms delay before - * all writes to the transmit buffer. - * - * See b/171430855 for details. - */ -static uint8_t ps8xxx_role_control_delay_ms[CONFIG_USB_PD_PORT_MAX_COUNT]; - -/* - * b/178664884, on PS8815, firmware revision 0x10 and older can report an - * incorrect value on the the CC lines. This flag controls when to apply - * the workaround. - */ -static bool ps8815_disable_rp_detect[CONFIG_USB_PD_PORT_MAX_COUNT]; -static bool ps8815_disconnected[CONFIG_USB_PD_PORT_MAX_COUNT]; -/* - * timestamp of the next possible toggle to ensure the 2-ms spacing - * between IRQ_HPD. - */ -static uint64_t hpd_deadline[CONFIG_USB_PD_PORT_MAX_COUNT]; - -void ps8xxx_wake_from_standby(const struct usb_mux *me); - -#if defined(CONFIG_USB_PD_TCPM_PS8705) || \ - defined(CONFIG_USB_PD_TCPM_PS8751) || \ - defined(CONFIG_USB_PD_TCPM_PS8755) || \ - defined(CONFIG_USB_PD_TCPM_PS8805) -/* - * DCI is enabled by default and burns about 40 mW when the port is in - * USB2 mode or when a C-to-A dongle is attached, so force it off. - */ - -static int ps8xxx_addr_dci_disable(int port, int i2c_addr, int i2c_reg) -{ - int status; - int dci; - - status = tcpc_addr_read(port, i2c_addr, i2c_reg, &dci); - if (status != EC_SUCCESS) - return status; - if ((dci & PS8XXX_REG_MUX_USB_DCI_CFG_MODE_MASK) != - PS8XXX_REG_MUX_USB_DCI_CFG_MODE_OFF) { - dci &= ~PS8XXX_REG_MUX_USB_DCI_CFG_MODE_MASK; - dci |= PS8XXX_REG_MUX_USB_DCI_CFG_MODE_OFF; - if (tcpc_addr_write(port, i2c_addr, i2c_reg, dci) != EC_SUCCESS) - return status; - } - return EC_SUCCESS; -} -#endif /* CONFIG_USB_PD_TCPM_PS875[15] || CONFIG_USB_PD_TCPM_PS8[78]05 */ - -#if defined(CONFIG_USB_PD_TCPM_PS8705) || \ - defined(CONFIG_USB_PD_TCPM_PS8755) || \ - defined(CONFIG_USB_PD_TCPM_PS8805) -static int ps8705_dci_disable(int port) -{ - int p1_addr; - int p3_addr; - int regval; - int rv; - - /* Enable access to debug pages. */ - p3_addr = tcpc_config[port].i2c_info.addr_flags; - rv = tcpc_addr_read(port, p3_addr, PS8XXX_REG_I2C_DEBUGGING_ENABLE, - ®val); - if (rv) - return rv; - - rv = tcpc_addr_write(port, p3_addr, PS8XXX_REG_I2C_DEBUGGING_ENABLE, - PS8XXX_REG_I2C_DEBUGGING_ENABLE_ON); - - /* Disable Auto DCI */ - p1_addr = PS8751_P3_TO_P1_FLAGS(p3_addr); - rv = ps8xxx_addr_dci_disable(port, p1_addr, - PS8XXX_P1_REG_MUX_USB_DCI_CFG); - - /* - * PS8705/PS8755/PS8805 will automatically re-assert bit:0 on the - * PS8XXX_REG_I2C_DEBUGGING_ENABLE register. - */ - return rv; -} -#endif /* CONFIG_USB_PD_TCPM_PS8755 || CONFIG_USB_PD_TCPM_PS8[78]05 */ - -#ifdef CONFIG_USB_PD_TCPM_PS8751 -static int ps8751_dci_disable(int port) -{ - int p3_addr; - - p3_addr = tcpc_config[port].i2c_info.addr_flags; - return ps8xxx_addr_dci_disable(port, p3_addr, - PS8751_REG_MUX_USB_DCI_CFG); -} -#endif /* CONFIG_USB_PD_TCPM_PS8751 */ - -#ifdef CONFIG_USB_PD_TCPM_PS8815 -static int ps8815_dci_disable(int port) -{ - /* DCI is disabled on the ps8815 */ - return EC_SUCCESS; -} -#endif /* CONFIG_USB_PD_TCPM_PS8815 */ - -#ifdef CONFIG_USB_PD_TCPM_PS8805 -static int ps8805_gpio_mask[] = { - PS8805_REG_GPIO_0, - PS8805_REG_GPIO_1, - PS8805_REG_GPIO_2, -}; - -int ps8805_gpio_set_level(int port, enum ps8805_gpio signal, int level) -{ - int rv; - int regval; - int mask; - - if (signal >= PS8805_GPIO_NUM) - return EC_ERROR_INVAL; - - rv = i2c_read8(tcpc_config[port].i2c_info.port, - PS8805_VENDOR_DEFINED_I2C_ADDR, - PS8805_REG_GPIO_CONTROL, ®val); - if (rv) - return rv; - - mask = ps8805_gpio_mask[signal]; - if (level) - regval |= mask; - else - regval &= ~mask; - - return i2c_write8(tcpc_config[port].i2c_info.port, - PS8805_VENDOR_DEFINED_I2C_ADDR, - PS8805_REG_GPIO_CONTROL, regval); -} - -int ps8805_gpio_get_level(int port, enum ps8805_gpio signal, int *level) -{ - int regval; - int rv; - - if (signal >= PS8805_GPIO_NUM) - return EC_ERROR_INVAL; - - rv = i2c_read8(tcpc_config[port].i2c_info.port, - PS8805_VENDOR_DEFINED_I2C_ADDR, - PS8805_REG_GPIO_CONTROL, ®val); - if (rv) - return rv; - *level = !!(regval & ps8805_gpio_mask[signal]); - - return EC_SUCCESS; -} -#endif /* CONFIG_USB_PD_TCPM_PS8805 */ - -enum ps8xxx_variant_regs { - REG_FIRST_INDEX = 0, - /* NOTE: The rev will read as 0x00 if the FW has malfunctioned. */ - REG_FW_VER = REG_FIRST_INDEX, - REG_MAX_COUNT, -}; - -struct ps8xxx_variant_map { - int product_id; - int (*dci_disable_ptr)(int port); - int reg_map[REG_MAX_COUNT]; -}; - -/* - * variant_map here is leveraged to lookup from ps8xxx_variant_regs to i2c - * register and corresponding dci_disable function based on product_id. - */ -static struct ps8xxx_variant_map variant_map[] = { -#ifdef CONFIG_USB_PD_TCPM_PS8705 - { - PS8705_PRODUCT_ID, - ps8705_dci_disable, - { - [REG_FW_VER] = 0x82, - } - }, -#endif -#ifdef CONFIG_USB_PD_TCPM_PS8751 - { - PS8751_PRODUCT_ID, - ps8751_dci_disable, - { - [REG_FW_VER] = 0x90, - } - }, -#endif -#ifdef CONFIG_USB_PD_TCPM_PS8755 - { - PS8755_PRODUCT_ID, - ps8705_dci_disable, - { - [REG_FW_VER] = 0x82, - } - }, -#endif -#ifdef CONFIG_USB_PD_TCPM_PS8805 - { - PS8805_PRODUCT_ID, - ps8705_dci_disable, - { - [REG_FW_VER] = 0x82, - } - }, -#endif -#ifdef CONFIG_USB_PD_TCPM_PS8815 - { - PS8815_PRODUCT_ID, - ps8815_dci_disable, - { - [REG_FW_VER] = 0x82, - } - }, -#endif -}; - -static int get_reg_by_product(const int port, - const enum ps8xxx_variant_regs reg) -{ - int i; - - if (reg < REG_FIRST_INDEX || reg >= REG_MAX_COUNT) - return INT32_MAX; - - for (i = 0; i < ARRAY_SIZE(variant_map); i++) { - if (product_id[port] == - variant_map[i].product_id) { - return variant_map[i].reg_map[reg]; - } - } - - CPRINTS("%s: failed to get register number by product_id.", __func__); - return INT32_MAX; -} - -static int dp_set_hpd(const struct usb_mux *me, int enable) -{ - int reg; - int rv; - - rv = mux_read(me, MUX_IN_HPD_ASSERTION_REG, ®); - if (rv) - return rv; - if (enable) - reg |= IN_HPD; - else - reg &= ~IN_HPD; - return mux_write(me, MUX_IN_HPD_ASSERTION_REG, reg); -} - -static int dp_set_irq(const struct usb_mux *me, int enable) -{ - int reg; - int rv; - - rv = mux_read(me, MUX_IN_HPD_ASSERTION_REG, ®); - if (rv) - return rv; - if (enable) - reg |= HPD_IRQ; - else - reg &= ~HPD_IRQ; - return mux_write(me, MUX_IN_HPD_ASSERTION_REG, reg); -} - -__overridable -uint16_t board_get_ps8xxx_product_id(int port) -{ - /* Board supporting multiple chip sources in ps8xxx.c MUST override this - * function to judge the real chip source for this board. For example, - * SKU ID / strappings / provisioning in the factory can be the ways. - */ - - if (IS_ENABLED(CONFIG_USB_PD_TCPM_MULTI_PS8XXX)) { - CPRINTS("%s: board should override this function.", __func__); - return 0; - } else if (IS_ENABLED(CONFIG_USB_PD_TCPM_PS8705)) { - return PS8705_PRODUCT_ID; - } else if (IS_ENABLED(CONFIG_USB_PD_TCPM_PS8751)) { - return PS8751_PRODUCT_ID; - } else if (IS_ENABLED(CONFIG_USB_PD_TCPM_PS8755)) { - return PS8755_PRODUCT_ID; - } else if (IS_ENABLED(CONFIG_USB_PD_TCPM_PS8805)) { - return PS8805_PRODUCT_ID; - } else if (IS_ENABLED(CONFIG_USB_PD_TCPM_PS8815)) { - return PS8815_PRODUCT_ID; - } - - CPRINTS("%s: Any new product id is not defined here?", __func__); - return 0; -} - -bool check_ps8755_chip(int port) -{ - int val; - int p0_addr; - int status; - bool is_ps8755 = false; - - p0_addr = PS8751_P3_TO_P0_FLAGS(tcpc_config[port].i2c_info.addr_flags); - status = tcpc_addr_read(port, p0_addr, PS8755_P0_REG_SM, &val); - if (status == EC_SUCCESS && val == PS8755_P0_REG_SM_VALUE) - is_ps8755 = true; - - return is_ps8755; -} - -void ps8xxx_tcpc_update_hpd_status(const struct usb_mux *me, - mux_state_t mux_state) -{ - int port = me->usb_port; - int hpd_lvl = (mux_state & USB_PD_MUX_HPD_LVL) ? 1 : 0; - int hpd_irq = (mux_state & USB_PD_MUX_HPD_IRQ) ? 1 : 0; - - if (IS_ENABLED(CONFIG_USB_PD_TCPM_PS8751_CUSTOM_MUX_DRIVER) && - product_id[me->usb_port] == PS8751_PRODUCT_ID && - me->flags & USB_MUX_FLAG_NOT_TCPC) - ps8xxx_wake_from_standby(me); - - dp_set_hpd(me, hpd_lvl); - - if (hpd_irq) { - uint64_t now = get_time().val; - /* wait for the minimum spacing between IRQ_HPD if needed */ - if (now < hpd_deadline[port]) - usleep(hpd_deadline[port] - now); - - dp_set_irq(me, 0); - usleep(HPD_DSTREAM_DEBOUNCE_IRQ); - dp_set_irq(me, hpd_irq); - } - /* enforce 2-ms delay between HPD pulses */ - hpd_deadline[port] = get_time().val + HPD_USTREAM_DEBOUNCE_LVL; -} - -static int ps8xxx_tcpc_bist_mode_2(int port) -{ - int rv; - - /* Generate BIST for 50ms. */ - rv = tcpc_write(port, - PS8XXX_REG_BIST_CONT_MODE_BYTE0, PS8751_BIST_COUNTER_BYTE0); - rv |= tcpc_write(port, - PS8XXX_REG_BIST_CONT_MODE_BYTE1, PS8751_BIST_COUNTER_BYTE1); - rv |= tcpc_write(port, - PS8XXX_REG_BIST_CONT_MODE_BYTE2, PS8751_BIST_COUNTER_BYTE2); - - /* Auto stop */ - rv |= tcpc_write(port, PS8XXX_REG_BIST_CONT_MODE_CTR, 0); - - /* Start BIST MODE 2 */ - rv |= tcpc_write(port, TCPC_REG_TRANSMIT, TCPCI_MSG_TX_BIST_MODE_2); - - return rv; -} - -static int ps8xxx_tcpm_transmit(int port, enum tcpci_msg_type type, - uint16_t header, const uint32_t *data) -{ - if (type == TCPCI_MSG_TX_BIST_MODE_2) - return ps8xxx_tcpc_bist_mode_2(port); - else - return tcpci_tcpm_transmit(port, type, header, data); -} - -static int ps8xxx_tcpm_release(int port) -{ - int version; - int status; - int reg = get_reg_by_product(port, REG_FW_VER); - - status = tcpc_read(port, reg, &version); - if (status != 0) { - /* wait for chip to wake up */ - msleep(10); - } - - return tcpci_tcpm_release(port); -} - -static void ps8xxx_role_control_delay(int port) -{ - int delay; - - delay = ps8xxx_role_control_delay_ms[port]; - if (delay) - msleep(delay); -} - -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE -static int ps8xxx_set_role_ctrl(int port, enum tcpc_drp drp, - enum tcpc_rp_value rp, enum tcpc_cc_pull pull) -{ - int rv; - - rv = tcpci_set_role_ctrl(port, drp, rp, pull); - - /* - * b/171430855 delay 1 ms after ROLE_CONTROL updates to prevent - * transmit buffer corruption - */ - ps8xxx_role_control_delay(port); - - return rv; -} - -static int ps8xxx_tcpc_drp_toggle(int port) -{ - int rv; - int status; - int opposite_pull; - - /* - * Workaround for PS8805/PS8815, which can't restart Connection - * Detection if the partner already presents pull. Now starts with - * the opposite pull. Check b/149570002. - */ - if (product_id[port] == PS8805_PRODUCT_ID || - product_id[port] == PS8815_PRODUCT_ID) { - if (ps8815_disable_rp_detect[port]) { - CPRINTS("TCPC%d: rearm Rp disable detect on connect", - port); - ps8815_disconnected[port] = true; - } - - /* Check CC_STATUS for the current pull */ - rv = tcpc_read(port, TCPC_REG_CC_STATUS, &status); - if (status & TCPC_REG_CC_STATUS_CONNECT_RESULT_MASK) { - /* Current pull: Rd */ - opposite_pull = TYPEC_CC_RP; - } else { - /* Current pull: Rp */ - opposite_pull = TYPEC_CC_RD; - } - - /* Set auto drp toggle, starting with the opposite pull */ - rv |= ps8xxx_set_role_ctrl(port, TYPEC_DRP, TYPEC_RP_USB, - opposite_pull); - - /* Set Look4Connection command */ - rv |= tcpc_write(port, TCPC_REG_COMMAND, - TCPC_REG_COMMAND_LOOK4CONNECTION); - - return rv; - } else { - return tcpci_tcpc_drp_toggle(port); - } -} -#endif - -#ifdef CONFIG_USB_PD_TCPM_PS8805_FORCE_DID -static int ps8805_make_device_id(int port, int *id) -{ - int p0_addr; - int val; - int status; - - p0_addr = PS8751_P3_TO_P0_FLAGS(tcpc_config[port].i2c_info.addr_flags); - - status = tcpc_addr_read(port, p0_addr, PS8805_P0_REG_CHIP_REVISION, - &val); - if (status != EC_SUCCESS) - return status; - switch (val & 0xF0) { - case 0x00: /* A2 chip */ - *id = 1; - break; - case 0xa0: /* A3 chip */ - *id = 2; - break; - default: - return EC_ERROR_UNKNOWN; - } - return EC_SUCCESS; -} -#endif - -#ifdef CONFIG_USB_PD_TCPM_PS8815_FORCE_DID -/* - * Early ps8815 A1 firmware reports 0x0001 in the TCPCI Device ID - * registers which makes it indistinguishable from A0. This - * overrides the Device ID based if vendor specific registers - * identify the chip as A1. - * - * See b/159289062. - * - * The ps8815 A2 reports device ID 0x0001 instead of 0x0003 when the - * firmware is bad (mis-programmed). - */ -static int ps8815_make_device_id(int port, int *id) -{ - int p1_addr; - int val; - int status; - - /* P1 registers are always accessible on PS8815 */ - p1_addr = PS8751_P3_TO_P1_FLAGS(tcpc_config[port].i2c_info.addr_flags); - - status = tcpc_addr_read16(port, p1_addr, PS8815_P1_REG_HW_REVISION, - &val); - if (status != EC_SUCCESS) - return status; - - switch (val) { - case 0x0a00: - *id = 1; - break; - case 0x0a01: - *id = 2; - break; - case 0x0a02: - *id = 3; - break; - default: - return EC_ERROR_UNKNOWN; - } - return EC_SUCCESS; -} -#endif - -/* - * The ps8815 can take up to 50ms (FW_INIT_DELAY_MS) to fully wake up - * from sleep/low power mode - specially when it contains an application - * block firmware update. When the chip is asleep, the 1st I2C - * transaction will fail but the chip will begin to wake up within 10ms - * (I2C_RECOVERY_DELAY_MS). After this delay, I2C transactions succeed, - * but the firmware is still not fully operational. The way to check if - * the firmware is ready, is to poll the firmware register for a - * non-zero value. This logic applies to all ps8xxx family members - * supported by this driver. - */ - -static int ps8xxx_lpm_recovery_delay(int port) -{ - int val; - int status; - int fw_reg; - timestamp_t deadline; - - fw_reg = get_reg_by_product(port, REG_FW_VER); - - deadline = get_time(); - deadline.val += PS8815_FW_INIT_DELAY_MS * 1000; - - val = 0; - for (;;) { - if (timestamp_expired(deadline, NULL)) - return EC_ERROR_TIMEOUT; - - status = tcpc_read(port, fw_reg, &val); - if (status != EC_SUCCESS) { - /* wait for chip to wake up */ - msleep(PS8XXX_I2C_RECOVERY_DELAY_MS); - continue; - } - if (val != 0) - break; - msleep(1); - } - - return EC_SUCCESS; -} - -static int ps8xxx_get_chip_info(int port, int live, - struct ec_response_pd_chip_info_v1 *chip_info) -{ - int val; - int reg; - int rv = tcpci_get_chip_info(port, live, chip_info); - - if (rv != EC_SUCCESS) - return rv; - - if (chip_info == NULL) - return EC_SUCCESS; - - if (!live) { - uint16_t pid; - - pid = board_get_ps8xxx_product_id(port); - if (pid == 0) - return EC_ERROR_UNKNOWN; - product_id[port] = pid; - chip_info->vendor_id = PS8XXX_VENDOR_ID; - chip_info->product_id = product_id[port]; - } - -#ifdef CONFIG_USB_PD_TCPM_PS8805_FORCE_DID - if (chip_info->product_id == PS8805_PRODUCT_ID && - chip_info->device_id == 0x0001) { - rv = ps8805_make_device_id(port, &val); - if (rv != EC_SUCCESS) - return rv; - chip_info->device_id = val; - } -#endif -#ifdef CONFIG_USB_PD_TCPM_PS8815_FORCE_DID - if (chip_info->product_id == PS8815_PRODUCT_ID && - chip_info->device_id == 0x0001) { - rv = ps8815_make_device_id(port, &val); - if (rv != EC_SUCCESS) - return rv; - chip_info->device_id = val; - } -#endif - reg = get_reg_by_product(port, REG_FW_VER); - rv = tcpc_read(port, reg, &val); - if (rv != EC_SUCCESS) - return rv; - - chip_info->fw_version_number = val; - - /* Treat unexpected values as error (FW not initiated from reset) */ - if (live && ( - chip_info->vendor_id != PS8XXX_VENDOR_ID || - chip_info->product_id != board_get_ps8xxx_product_id(port) || - chip_info->fw_version_number == 0)) - return EC_ERROR_UNKNOWN; - -#if defined(CONFIG_USB_PD_TCPM_PS8751) && \ - defined(CONFIG_USB_PD_VBUS_DETECT_TCPC) - /* - * Min firmware version of PS8751 to ensure that it can detect Vbus - * properly. See b/109769787#comment7 - */ - chip_info->min_req_fw_version_number = 0x39; -#endif - - return rv; -} - -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER -static int ps8xxx_enter_low_power_mode(int port) -{ - /* - * PS8751 has the auto sleep function that enters low power mode on - * its own in ~2 seconds. Other chips don't have it. Stub it out for - * PS8751. - */ - if (product_id[port] == PS8751_PRODUCT_ID) - return EC_SUCCESS; - - return tcpci_enter_low_power_mode(port); -} -#endif - -static int ps8xxx_dci_disable(int port) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(variant_map); i++) { - if (product_id[port] == variant_map[i].product_id) - return variant_map[i].dci_disable_ptr(port); - } - - CPRINTS("%s: failed to get dci_disable function pointers.", __func__); - return EC_ERROR_INVAL; -} - -__maybe_unused static int ps8815_transmit_buffer_workaround_check(int port) -{ - int p1_addr; - int val; - int status; - - if (product_id[port] != PS8815_PRODUCT_ID) - return EC_SUCCESS; - - /* P1 registers are always accessible on PS8815 */ - p1_addr = PS8751_P3_TO_P1_FLAGS(tcpc_config[port].i2c_info.addr_flags); - - status = tcpc_addr_read16(port, p1_addr, PS8815_P1_REG_HW_REVISION, - &val); - if (status != EC_SUCCESS) - return status; - - switch (val) { - case 0x0a00: - case 0x0a01: - ps8xxx_role_control_delay_ms[port] = 1; - break; - default: - break; - } - - return EC_SUCCESS; -} - -__maybe_unused static int ps8815_disable_rp_detect_workaround_check(int port) -{ - int val; - int rv; - int reg; - - ps8815_disable_rp_detect[port] = false; - ps8815_disconnected[port] = true; - - reg = get_reg_by_product(port, REG_FW_VER); - rv = tcpc_read(port, reg, &val); - if (rv != EC_SUCCESS) - return rv; - - /* - * RP detect is a problem in firmware version 0x10 and older. - */ - if (val <= 0x10) - ps8815_disable_rp_detect[port] = true; - - return EC_SUCCESS; -} - -__overridable void board_ps8xxx_tcpc_init(int port) -{} - -static int ps8xxx_tcpm_init(int port) -{ - int status; - - product_id[port] = board_get_ps8xxx_product_id(port); - - status = ps8xxx_lpm_recovery_delay(port); - if (status != EC_SUCCESS) { - CPRINTS("C%d: init: LPM recovery failed", port); - return status; - } - - if (IS_ENABLED(CONFIG_USB_PD_TCPM_PS8815)) { - status = ps8815_transmit_buffer_workaround_check(port); - if (status != EC_SUCCESS) - return status; - status = ps8815_disable_rp_detect_workaround_check(port); - if (status != EC_SUCCESS) - return status; - } - - board_ps8xxx_tcpc_init(port); - - status = tcpci_tcpm_init(port); - if (status != EC_SUCCESS) - return status; - - return ps8xxx_dci_disable(port); -} - -#ifdef CONFIG_USB_PD_TCPM_PS8751 -/* - * TODO(twawrzynczak): Remove this workaround when no - * longer needed. See: https://issuetracker.google.com/147684491 - * - * This is a workaround for what appears to be a bug in PS8751 firmware - * version 0x44. (Does the bug exist in other PS8751 firmware versions? - * Should this workaround be limited to only 0x44?) - * - * With nothing connected to the port, sometimes after DRP is disabled, - * the CC_STATUS register reads the CC state incorrectly (reading it - * as though a port partner is detected), which ends up confusing - * our TCPM. The workaround for this seems to be a short sleep and - * then re-reading the CC state. In other words, the issue shows up - * as a short glitch or transient, which an extra read and then a short - * delay will allow the transient to disappear. - */ -static int ps8751_get_gcc(int port, enum tcpc_cc_voltage_status *cc1, - enum tcpc_cc_voltage_status *cc2) -{ - int rv; - int status; - rv = tcpc_read(port, TCPC_REG_CC_STATUS, &status); - if (rv) - return rv; - - /* Derived empirically */ - usleep(300); - - return tcpci_tcpm_get_cc(port, cc1, cc2); -} -#endif - -static int ps8xxx_tcpm_set_cc(int port, int pull) -{ - int rv; - - /* - * b/178664884: Before presenting Rp on initial connect, disable - * internal function that checks Rp value. This is a workaround - * in the PS8815 firmware that reports an incorrect value on the CC - * lines. - * - * The PS8815 self-clears these bits. - */ - if (ps8815_disable_rp_detect[port] && ps8815_disconnected[port] && - pull == TYPEC_CC_RP) { - CPRINTS("TCPC%d: disable chip based Rp detect on connection", - port); - tcpc_write(port, PS8XXX_REG_RP_DETECT_CONTROL, - RP_DETECT_DISABLE); - ps8815_disconnected[port] = false; - } - - rv = tcpci_tcpm_set_cc(port, pull); - - /* - * b/171430855 delay 1 ms after ROLE_CONTROL updates to prevent - * transmit buffer corruption - */ - ps8xxx_role_control_delay(port); - - return rv; -} - -static int ps8xxx_tcpm_get_cc(int port, enum tcpc_cc_voltage_status *cc1, - enum tcpc_cc_voltage_status *cc2) -{ -#ifdef CONFIG_USB_PD_TCPM_PS8751 - if (product_id[port] == PS8751_PRODUCT_ID) - return ps8751_get_gcc(port, cc1, cc2); -#endif - - return tcpci_tcpm_get_cc(port, cc1, cc2); -} - -const struct tcpm_drv ps8xxx_tcpm_drv = { - .init = ps8xxx_tcpm_init, - .release = ps8xxx_tcpm_release, - .get_cc = ps8xxx_tcpm_get_cc, -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - .check_vbus_level = tcpci_tcpm_check_vbus_level, -#endif - .select_rp_value = tcpci_tcpm_select_rp_value, - .set_cc = ps8xxx_tcpm_set_cc, - .set_polarity = tcpci_tcpm_set_polarity, -#ifdef CONFIG_USB_PD_DECODE_SOP - .sop_prime_enable = tcpci_tcpm_sop_prime_enable, -#endif - .set_vconn = tcpci_tcpm_set_vconn, - .set_msg_header = tcpci_tcpm_set_msg_header, - .set_rx_enable = tcpci_tcpm_set_rx_enable, - .get_message_raw = tcpci_tcpm_get_message_raw, - .transmit = ps8xxx_tcpm_transmit, - .tcpc_alert = tcpci_tcpc_alert, -#ifdef CONFIG_USB_PD_DISCHARGE_TCPC - .tcpc_discharge_vbus = tcpci_tcpc_discharge_vbus, -#endif -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - .drp_toggle = ps8xxx_tcpc_drp_toggle, -#endif -#ifdef CONFIG_USB_PD_PPC - .set_snk_ctrl = tcpci_tcpm_set_snk_ctrl, - .set_src_ctrl = tcpci_tcpm_set_src_ctrl, -#endif - .get_chip_info = ps8xxx_get_chip_info, -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER - .enter_low_power_mode = ps8xxx_enter_low_power_mode, -#endif - .set_bist_test_mode = tcpci_set_bist_test_mode, -}; - -#ifdef CONFIG_CMD_I2C_STRESS_TEST_TCPC -struct i2c_stress_test_dev ps8xxx_i2c_stress_test_dev = { - .reg_info = { - .read_reg = PS8XXX_REG_VENDOR_ID_L, - .read_val = PS8XXX_VENDOR_ID & 0xFF, - .write_reg = MUX_IN_HPD_ASSERTION_REG, - }, - .i2c_read = tcpc_i2c_read, - .i2c_write = tcpc_i2c_write, -}; -#endif /* CONFIG_CMD_I2C_STRESS_TEST_TCPC */ - -#ifdef CONFIG_USB_PD_TCPM_PS8751_CUSTOM_MUX_DRIVER - -static int ps8xxx_mux_init(const struct usb_mux *me) -{ - RETURN_ERROR(tcpci_tcpm_mux_init(me)); - - /* If this MUX is also the TCPC, then skip init */ - if (!(me->flags & USB_MUX_FLAG_NOT_TCPC)) - return EC_SUCCESS; - - product_id[me->usb_port] = board_get_ps8xxx_product_id(me->usb_port); - - return EC_SUCCESS; -} - -/* - * PS8751 goes to standby mode automatically when both CC lines are set to RP. - * In standby mode it doesn't respond to first I2C access, but next - * transactions are working fine (until it goes to sleep again). - * - * To wake device documentation recommends read content of 0xA0 register. - */ -void ps8xxx_wake_from_standby(const struct usb_mux *me) -{ - int reg; - - /* Since we are waking up device, this call will most likely fail */ - mux_read(me, PS8XXX_REG_I2C_DEBUGGING_ENABLE, ®); - msleep(10); -} - -static int ps8xxx_mux_set(const struct usb_mux *me, mux_state_t mux_state, - bool *ack_required) -{ - if (product_id[me->usb_port] == PS8751_PRODUCT_ID && - me->flags & USB_MUX_FLAG_NOT_TCPC) { - ps8xxx_wake_from_standby(me); - - /* - * To operate properly, when working as mux only, PS8751 CC - * lines needs to be RD all the time. Changing to RP after - * setting mux breaks SuperSpeed connection. - */ - if (mux_state != USB_PD_MUX_NONE) - RETURN_ERROR(mux_write(me, TCPC_REG_ROLE_CTRL, - TCPC_REG_ROLE_CTRL_SET(TYPEC_NO_DRP, - TYPEC_RP_USB, - TYPEC_CC_RD, - TYPEC_CC_RD))); - } - - return tcpci_tcpm_mux_set(me, mux_state, ack_required); -} - -static int ps8xxx_mux_get(const struct usb_mux *me, mux_state_t *mux_state) -{ - if (product_id[me->usb_port] == PS8751_PRODUCT_ID && - me->flags & USB_MUX_FLAG_NOT_TCPC) - ps8xxx_wake_from_standby(me); - - return tcpci_tcpm_mux_get(me, mux_state); -} - -static int ps8xxx_mux_enter_low_power(const struct usb_mux *me) -{ - /* - * Set PS8751 lines to RP. This allows device to standby - * automatically after ~2 seconds - */ - if (product_id[me->usb_port] == PS8751_PRODUCT_ID && - me->flags & USB_MUX_FLAG_NOT_TCPC) { - /* - * It may happen that this write will fail, but - * RP seems to be set correctly - */ - mux_write(me, TCPC_REG_ROLE_CTRL, - TCPC_REG_ROLE_CTRL_SET(TYPEC_NO_DRP, TYPEC_RP_USB, - TYPEC_CC_RP, TYPEC_CC_RP)); - return EC_SUCCESS; - } - - return tcpci_tcpm_mux_enter_low_power(me); -} - -const struct usb_mux_driver ps8xxx_usb_mux_driver = { - .init = ps8xxx_mux_init, - .set = ps8xxx_mux_set, - .get = ps8xxx_mux_get, - .enter_low_power_mode = ps8xxx_mux_enter_low_power, -}; - -#endif /* CONFIG_USB_PD_TCPM_PS8751_CUSTOM_MUX_DRIVER */ diff --git a/driver/tcpm/ps8xxx.h b/driver/tcpm/ps8xxx.h deleted file mode 100644 index 8458dbb7e5..0000000000 --- a/driver/tcpm/ps8xxx.h +++ /dev/null @@ -1,146 +0,0 @@ -/* Copyright 2017 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 "usb_mux.h" - -#include "driver/tcpm/ps8xxx_public.h" - -/* Parade Tech Type-C port controller */ - -#ifndef __CROS_EC_USB_PD_TCPM_PS8XXX_H -#define __CROS_EC_USB_PD_TCPM_PS8XXX_H - -#define PS8751_P3_TO_P0_FLAGS(p3_flags) ((p3_flags) - 3) -#define PS8751_P3_TO_P1_FLAGS(p3_flags) ((p3_flags) - 2) - -#define PS8751_BIST_TIMER_FREQ 15000000 -#define PS8751_BIST_DELAY_MS 50 - -#define PS8751_BIST_COUNTER (PS8751_BIST_TIMER_FREQ / MSEC \ - * PS8751_BIST_DELAY_MS) - -#define PS8751_BIST_COUNTER_BYTE0 (PS8751_BIST_COUNTER & 0xff) -#define PS8751_BIST_COUNTER_BYTE1 ((PS8751_BIST_COUNTER >> 8) & 0xff) -#define PS8751_BIST_COUNTER_BYTE2 ((PS8751_BIST_COUNTER >> 16) & 0xff) - -#define PS8XXX_REG_RP_DETECT_CONTROL 0x9B -#define RP_DETECT_DISABLE 0x30 - -#define PS8XXX_REG_I2C_DEBUGGING_ENABLE 0xA0 -#define PS8XXX_REG_I2C_DEBUGGING_ENABLE_ON 0x30 -#define PS8XXX_REG_I2C_DEBUGGING_ENABLE_OFF 0x31 /* default */ -#define PS8XXX_REG_BIST_CONT_MODE_BYTE0 0xBC -#define PS8XXX_REG_BIST_CONT_MODE_BYTE1 0xBD -#define PS8XXX_REG_BIST_CONT_MODE_BYTE2 0xBE -#define PS8XXX_REG_BIST_CONT_MODE_CTR 0xBF -#define PS8XXX_REG_DET_CTRL0 0x08 - -#define PS8XXX_REG_MUX_USB_DCI_CFG_MODE_MASK 0xC0 -#define PS8XXX_REG_MUX_USB_DCI_CFG_MODE_OFF 0x80 - -#define MUX_IN_HPD_ASSERTION_REG 0xD0 -#define IN_HPD BIT(0) -#define HPD_IRQ BIT(1) - -#define PS8XXX_P1_REG_MUX_USB_DCI_CFG 0x4B - -#define PS8755_P0_REG_SM 0x06 -#define PS8755_P0_REG_SM_VALUE 0x80 - -#if defined(CONFIG_USB_PD_TCPM_PS8751) -/* Vendor defined registers */ -#define PS8XXX_REG_VENDOR_ID_L 0x00 -#define PS8XXX_REG_VENDOR_ID_H 0x01 -#define PS8XXX_REG_MUX_DP_EQ_CONFIGURATION 0xD3 -#define PS8XXX_REG_MUX_DP_OUTPUT_CONFIGURATION 0xD4 -#define PS8XXX_REG_MUX_USB_C2SS_EQ 0xE7 -#define PS8XXX_REG_MUX_USB_C2SS_HS_THRESHOLD 0xE8 -#define PS8751_REG_MUX_USB_DCI_CFG 0xED -#endif - -/* Vendor defined registers */ -#define PS8815_P1_REG_HW_REVISION 0xF0 - -/* - * Below register is defined from Parade PS8815 Register Table, - * See b:189587527 for more detail. - */ - -/* Displayport related settings */ -#define PS8815_REG_DP_EQ_SETTING 0xF8 -#define PS8815_AUTO_EQ_DISABLE BIT(7) -#define PS8815_DPEQ_LOSS_UP_21DB 0x09 -#define PS8815_DPEQ_LOSS_UP_20DB 0x08 -#define PS8815_DPEQ_LOSS_UP_19DB 0x07 -#define PS8815_DPEQ_LOSS_UP_18DB 0x06 -#define PS8815_DPEQ_LOSS_UP_17DB 0x05 -#define PS8815_DPEQ_LOSS_UP_16DB 0x04 -#define PS8815_DPEQ_LOSS_UP_13DB 0x03 -#define PS8815_DPEQ_LOSS_UP_12DB 0x02 -#define PS8815_DPEQ_LOSS_UP_10DB 0x01 -#define PS8815_DPEQ_LOSS_UP_9DB 0x00 -#define PS8815_REG_DP_EQ_COMP_SHIFT 3 -#define PS8815_AUX_INTERCEPTION_DISABLE BIT(1) - -/* - * PS8805 register to distinguish chip revision - * bit 7-4: 1010b is A3 chip, 0000b is A2 chip - */ -#define PS8805_P0_REG_CHIP_REVISION 0x62 - -/* - * PS8805 GPIO control register. Note the device I2C address of 0x1A is - * independent of the ADDR pin on the chip, and not the same address being used - * for TCPCI functions. - */ -#define PS8805_VENDOR_DEFINED_I2C_ADDR 0x1A -#define PS8805_REG_GPIO_CONTROL 0x21 -#define PS8805_REG_GPIO_0 BIT(7) -#define PS8805_REG_GPIO_1 BIT(5) -#define PS8805_REG_GPIO_2 BIT(6) - -enum ps8805_gpio { - PS8805_GPIO_0, - PS8805_GPIO_1, - PS8805_GPIO_2, - PS8805_GPIO_NUM, -}; - -/** - * Set PS8805 gpio signal to desired level - * - * @param port: The Type-C port number. - * @param signal PS8805 gpio number (0, 1, or 2) - * @param level desired level - * @return EC_SUCCESS if I2C accesses are successful - */ -int ps8805_gpio_set_level(int port, enum ps8805_gpio signal, int level); - -/** - * Get PS8805 gpio signal value - * - * @param port: The Type-C port number. - * @param signal PS8805 gpio number (0, 1, or 2) - * @param pointer location to store gpio level - * @return EC_SUCCESS if I2C accesses are successful - */ -int ps8805_gpio_get_level(int port, enum ps8805_gpio signal, int *level); - -/** - * Check if the chip is PS8755 - * - * @param port: The Type-C port number. - * @return true if hidden register sm is 0x80 - */ -bool check_ps8755_chip(int port); - -/* - * Allow boards to customize for PS8XXX initial if board has - * specific settings. - * - * @param port: The Type-C port number. - */ -__override_proto void board_ps8xxx_tcpc_init(int port); - -#endif /* defined(__CROS_EC_USB_PD_TCPM_PS8XXX_H) */ diff --git a/driver/tcpm/raa489000.c b/driver/tcpm/raa489000.c deleted file mode 100644 index c4976bab4e..0000000000 --- a/driver/tcpm/raa489000.c +++ /dev/null @@ -1,325 +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. - * - * Renesas RAA489000 TCPC driver - */ - -#include "charge_manager.h" -#include "charger.h" -#include "common.h" -#include "console.h" -#include "driver/charger/isl923x.h" -#include "i2c.h" -#include "raa489000.h" -#include "tcpm/tcpci.h" -#include "tcpm/tcpm.h" -#include "timer.h" - -#define DEFAULT_R_AC 20 -#define R_AC CONFIG_CHARGER_SENSE_RESISTOR_AC -#define AC_CURRENT_TO_REG(CUR) ((CUR) * R_AC / DEFAULT_R_AC) - -#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) -#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) - -static int dev_id[CONFIG_USB_PD_PORT_MAX_COUNT] = { -1 }; - -static int raa489000_enter_low_power_mode(int port) -{ - int rv; - - rv = tcpc_write16(port, RAA489000_PD_PHYSICAL_SETTING1, 0); - if (rv) - CPRINTS("RAA489000(%d): Failed to set PD PHY setting1!", port); - - rv = tcpc_write16(port, RAA489000_TCPC_SETTING1, 0); - if (rv) - CPRINTS("RAA489000(%d): Failed to set TCPC setting1!", port); - - return tcpci_enter_low_power_mode(port); -} - -/* Configure output current in the TCPC because it is controlling Vbus */ -int raa489000_set_output_current(int port, enum tcpc_rp_value rp) -{ - int regval; - int selected_cur = rp == TYPEC_RP_3A0 ? - RAA489000_VBUS_CURRENT_TARGET_3A : - RAA489000_VBUS_CURRENT_TARGET_1_5A; - - regval = AC_CURRENT_TO_REG(selected_cur) + - selected_cur % (DEFAULT_R_AC/R_AC); - - return tcpc_write16(port, RAA489000_VBUS_CURRENT_TARGET, - regval); -} - -int raa489000_init(int port) -{ - int rv; - int regval; - int device_id; - int i2c_port; - struct charge_port_info chg = { 0 }; - int vbus_mv = 0; - - /* Perform unlock sequence */ - rv = tcpc_write16(port, 0xAA, 0xDAA0); - if (rv) - CPRINTS("c%d: failed unlock step1", port); - rv = tcpc_write16(port, 0xAA, 0xACE0); - if (rv) - CPRINTS("c%d: failed unlock step2", port); - rv = tcpc_write16(port, 0xAA, 0x0D0B); - if (rv) - CPRINTS("c%d: failed unlock step3", port); - - device_id = -1; - rv = tcpc_read16(port, TCPC_REG_BCD_DEV, &device_id); - if (rv) - CPRINTS("C%d: Failed to read DEV_ID", port); - CPRINTS("%s(%d): DEVICE_ID=%d", __func__, port, device_id); - dev_id[port] = device_id; - - /* Enable the ADC */ - /* - * TODO(b:147316511) Since this register can be accessed by multiple - * tasks, we should add a mutex when modifying this register. - * - * See(b:178981107,b:178728138) When the battery does not exist, - * we must enable ADC function so that charger_get_vbus_voltage - * can get the correct voltage. - */ - i2c_port = tcpc_config[port].i2c_info.port; - rv = i2c_read16(i2c_port, ISL923X_ADDR_FLAGS, - ISL9238_REG_CONTROL3, ®val); - regval |= RAA489000_ENABLE_ADC; - rv |= i2c_write16(i2c_port, ISL923X_ADDR_FLAGS, - ISL9238_REG_CONTROL3, regval); - if (rv) - CPRINTS("c%d: failed to enable ADCs", port); - - /* Enable Vbus detection */ - rv = tcpc_write(port, TCPC_REG_COMMAND, - TCPC_REG_COMMAND_ENABLE_VBUS_DETECT); - if (rv) - CPRINTS("c%d: failed to enable vbus detect cmd", port); - - - /* - * If VBUS is present, start sinking from it if we haven't already - * chosen a charge port and no battery is connected. This is - * *kinda hacky* doing it here, but we must start sinking VBUS now, - * otherwise the board may die (See b/150702984, b/178728138). This - * works as this part is a combined charger IC and TCPC. - */ - usleep(853); - charger_get_vbus_voltage(port, &vbus_mv); - - /* - * Disable the ADC - * - * See(b:178356507) 9mW is reduced on S0iX power consumption - * by clearing 'Enable ADC' bit. - */ - if (IS_ENABLED(CONFIG_OCPC) && (port != 0)) { - i2c_port = tcpc_config[port].i2c_info.port; - rv = i2c_read16(i2c_port, ISL923X_ADDR_FLAGS, - ISL9238_REG_CONTROL3, ®val); - regval &= ~RAA489000_ENABLE_ADC; - rv |= i2c_write16(i2c_port, ISL923X_ADDR_FLAGS, - ISL9238_REG_CONTROL3, regval); - if (rv) - CPRINTS("c%d: failed to disable ADCs", port); - } - - if ((vbus_mv > 3900) && - charge_manager_get_active_charge_port() == CHARGE_PORT_NONE && - !pd_is_battery_capable()) { - chg.current = 500; - chg.voltage = 5000; - charge_manager_update_charge(CHARGE_SUPPLIER_VBUS, port, &chg); - board_set_active_charge_port(port); - } - - if (device_id > 1) { - /* - * A1 silicon has a DEVICE_ID of 1. For B0 and newer, we need - * allow the TCPC to control VBUS in order to start VBUS ADC - * sampling. This is a requirement to clear the TCPC - * initialization status but in POWER_STATUS. Otherwise, the - * common TCPCI init will fail. (See b/154191301) - */ - rv = tcpc_read16(port, RAA489000_TCPC_SETTING1, ®val); - regval |= RAA489000_TCPC_PWR_CNTRL; - rv = tcpc_write16(port, RAA489000_TCPC_SETTING1, regval); - if (rv) - CPRINTS("C%d: failed to set TCPC power control", port); - } - - /* Note: registers may not be ready until TCPCI init succeeds */ - rv = tcpci_tcpm_init(port); - if (rv) - return rv; - - /* - * Set some vendor defined registers to enable the CC comparators and - * remove the dead battery resistors. This only needs to be done on - * early silicon versions. - */ - if (device_id <= 1) { - rv = tcpc_write16(port, RAA489000_TYPEC_SETTING1, - RAA489000_SETTING1_RDOE | - RAA489000_SETTING1_CC2_CMP3_EN | - RAA489000_SETTING1_CC2_CMP2_EN | - RAA489000_SETTING1_CC2_CMP1_EN | - RAA489000_SETTING1_CC1_CMP3_EN | - RAA489000_SETTING1_CC1_CMP2_EN | - RAA489000_SETTING1_CC1_CMP1_EN | - RAA489000_SETTING1_CC_DB_EN); - if (rv) - CPRINTS("c%d: failed to enable CC comparators", port); - } - - /* Set Rx enable for receiver comparator */ - rv = tcpc_read16(port, RAA489000_PD_PHYSICAL_SETTING1, ®val); - regval |= RAA489000_PD_PHY_SETTING1_RECEIVER_EN | - RAA489000_PD_PHY_SETTING1_SQUELCH_EN | - RAA489000_PD_PHY_SETTING1_TX_LDO11_EN; - rv |= tcpc_write16(port, RAA489000_PD_PHYSICAL_SETTING1, regval); - if (rv) - CPRINTS("c%d: failed to set PD PHY setting1", port); - - /* - * Disable VBUS auto discharge, we'll turn it on later as its needed to - * goodcrc. - */ - rv = tcpc_read(port, TCPC_REG_POWER_CTRL, ®val); - regval &= ~TCPC_REG_POWER_CTRL_AUTO_DISCHARGE_DISCONNECT; - rv |= tcpc_write(port, TCPC_REG_POWER_CTRL, regval); - if (rv) - CPRINTS("c%d: failed to set auto discharge", port); - - if (device_id <= 1) { - /* The vendor says to set this setting. */ - rv = tcpc_write16(port, RAA489000_PD_PHYSICAL_PARAMETER1, - 0x6C07); - if (rv) - CPRINTS("c%d: failed to set PD PHY PARAM1", port); - } - - /* Enable the correct TCPCI interface version */ - rv = tcpc_read16(port, RAA489000_TCPC_SETTING1, ®val); - if (!(tcpc_config[port].flags & TCPC_FLAGS_TCPCI_REV2_0)) - regval |= RAA489000_TCPCV1_0_EN; - else - regval &= ~RAA489000_TCPCV1_0_EN; - - if (device_id <= 1) { - /* Allow the TCPC to control VBUS. */ - regval |= RAA489000_TCPC_PWR_CNTRL; - } - - rv = tcpc_write16(port, RAA489000_TCPC_SETTING1, regval); - if (rv) - CPRINTS("c%d: failed to set TCPCIv1.0 mode", port); - - /* - * Set Vbus OCP UV here, PD tasks will set target current - */ - rv = tcpc_write16(port, RAA489000_VBUS_OCP_UV_THRESHOLD, - RAA489000_OCP_THRESHOLD_VALUE); - if (rv) - CPRINTS("c%d: failed to set OCP threshold", port); - - /* Set Vbus Target Voltage */ - rv = tcpc_write16(port, RAA489000_VBUS_VOLTAGE_TARGET, - RAA489000_VBUS_VOLTAGE_TARGET_5160MV); - if (rv) - CPRINTS("c%d: failed to set Vbus Target Voltage", port); - - return rv; -} - -int raa489000_tcpm_set_cc(int port, int pull) -{ - int rv; - - rv = tcpci_tcpm_set_cc(port, pull); - if (dev_id[port] > 1 || rv) - return rv; - - /* Older silicon needs the TCPM to set RDOE to 1 after setting Rp */ - if (pull == TYPEC_CC_RP) - rv = tcpc_update16(port, RAA489000_TYPEC_SETTING1, - RAA489000_SETTING1_RDOE, MASK_SET); - - return rv; -} - -int raa489000_debug_detach(int port) -{ - int rv; - int power_status; - - /* - * Force RAA489000 to see debug detach by running: - * - * 1. Set POWER_CONTROL. AutoDischargeDisconnect=1 - * 2. Set ROLE_CONTROL=0x0F(OPEN,OPEN) - * 3. Set POWER_CONTROL. AutoDischargeDisconnect=0 - * - * Only if we have sufficient battery or are not sinking. Otherwise, - * we would risk brown-out during the CC open set. - */ - RETURN_ERROR(tcpc_read(port, TCPC_REG_POWER_STATUS, &power_status)); - - if (!pd_is_battery_capable() && - (power_status & TCPC_REG_POWER_STATUS_SINKING_VBUS)) - return EC_SUCCESS; - - tcpci_tcpc_enable_auto_discharge_disconnect(port, 1); - - rv = tcpci_tcpm_set_cc(port, TYPEC_CC_OPEN); - - tcpci_tcpc_enable_auto_discharge_disconnect(port, 0); - - return rv; -} - -/* RAA489000 is a TCPCI compatible port controller */ -const struct tcpm_drv raa489000_tcpm_drv = { - .init = &raa489000_init, - .release = &tcpci_tcpm_release, - .get_cc = &tcpci_tcpm_get_cc, -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - .check_vbus_level = &tcpci_tcpm_check_vbus_level, -#endif - .select_rp_value = &tcpci_tcpm_select_rp_value, - .set_cc = &raa489000_tcpm_set_cc, - .set_polarity = &tcpci_tcpm_set_polarity, -#ifdef CONFIG_USB_PD_DECODE_SOP - .sop_prime_enable = &tcpci_tcpm_sop_prime_enable, -#endif - .set_vconn = &tcpci_tcpm_set_vconn, - .set_msg_header = &tcpci_tcpm_set_msg_header, - .set_rx_enable = &tcpci_tcpm_set_rx_enable, - .get_message_raw = &tcpci_tcpm_get_message_raw, - .transmit = &tcpci_tcpm_transmit, - .tcpc_alert = &tcpci_tcpc_alert, -#ifdef CONFIG_USB_PD_DISCHARGE_TCPC - .tcpc_discharge_vbus = &tcpci_tcpc_discharge_vbus, -#endif -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - .drp_toggle = &tcpci_tcpc_drp_toggle, -#endif - .get_chip_info = &tcpci_get_chip_info, -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER - .enter_low_power_mode = &raa489000_enter_low_power_mode, -#endif - .set_bist_test_mode = &tcpci_set_bist_test_mode, - .tcpc_enable_auto_discharge_disconnect = - &tcpci_tcpc_enable_auto_discharge_disconnect, - .debug_detach = &raa489000_debug_detach, -}; diff --git a/driver/tcpm/raa489000.h b/driver/tcpm/raa489000.h deleted file mode 100644 index 2a4c7c6b3d..0000000000 --- a/driver/tcpm/raa489000.h +++ /dev/null @@ -1,86 +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. - * - * TCPC driver for Renesas RAA489000 Buck-boost charger with TCPC - */ - -#include "compile_time_macros.h" -#include "usb_pd_tcpm.h" - -#ifndef __CROS_EC_USB_PD_TCPM_RAA489000_H -#define __CROS_EC_USB_PD_TCPM_RAA489000_H - -#define RAA489000_TCPC0_I2C_FLAGS 0x22 -#define RAA489000_TCPC1_I2C_FLAGS 0x23 -#define RAA489000_TCPC2_I2C_FLAGS 0x24 -#define RAA489000_TCPC3_I2C_FLAGS 0x25 - -/* Vendor registers */ -#define RAA489000_TCPC_SETTING1 0x80 -#define RAA489000_VBUS_VOLTAGE_TARGET 0x90 -#define RAA489000_VBUS_CURRENT_TARGET 0x92 -#define RAA489000_VBUS_OCP_UV_THRESHOLD 0x94 -#define RAA489000_TYPEC_SETTING1 0xC0 -#define RAA489000_PD_PHYSICAL_SETTING1 0xE0 -#define RAA489000_PD_PHYSICAL_PARAMETER1 0xE8 - -/* TCPC_SETTING_1 */ -#define RAA489000_TCPCV1_0_EN BIT(0) -#define RAA489000_TCPC_PWR_CNTRL BIT(4) - -/* VBUS_CURRENT_TARGET */ -#define RAA489000_VBUS_CURRENT_TARGET_3A 0x66 /* 3.0A + iOvershoot */ -#define RAA489000_VBUS_CURRENT_TARGET_1_5A 0x38 /* 1.5A + iOvershoot */ - -/* VBUS_VOLTAGE_TARGET */ -#define RAA489000_VBUS_VOLTAGE_TARGET_5160MV 0x102 /* 5.16V */ -#define RAA489000_VBUS_VOLTAGE_TARGET_5220MV 0x105 /* 5.22V */ - -/* VBUS_OCP_UV_THRESHOLD */ -/* Detect voltage level of overcurrent protection during Sourcing VBUS */ -#define RAA489000_OCP_THRESHOLD_VALUE 0x00BE /* 4.75V */ - -/* TYPEC_SETTING1 - only older silicon */ -/* Enables for reverse current protection */ -#define RAA489000_SETTING1_IP2_EN BIT(9) -#define RAA489000_SETTING1_IP1_EN BIT(8) - -/* Switches from dead-battery Rd */ -#define RAA489000_SETTING1_RDOE BIT(7) - -/* CC comparator enables */ -#define RAA489000_SETTING1_CC2_CMP3_EN BIT(6) -#define RAA489000_SETTING1_CC2_CMP2_EN BIT(5) -#define RAA489000_SETTING1_CC2_CMP1_EN BIT(4) -#define RAA489000_SETTING1_CC1_CMP3_EN BIT(3) -#define RAA489000_SETTING1_CC1_CMP2_EN BIT(2) -#define RAA489000_SETTING1_CC1_CMP1_EN BIT(1) - -/* CC debounce enable */ -#define RAA489000_SETTING1_CC_DB_EN BIT(0) - -/* PD_PHYSICAL_SETTING_1 */ -#define RAA489000_PD_PHY_SETTING1_RECEIVER_EN BIT(9) -#define RAA489000_PD_PHY_SETTING1_SQUELCH_EN BIT(8) -#define RAA489000_PD_PHY_SETTING1_TX_LDO11_EN BIT(0) - -/* PD_PHYSICAL_PARMETER_1 */ -#define PD_PHY_PARAM1_NOISE_FILTER_CNT_MASK (GENMASK(4, 0)) - -/** - * - * Set output current limit on the TCPC. Note, this chip also offers an OTG - * current level register in the charger i2c page but we must use the TCPC - * current limit because the TCPC is controlling Vbus. - * - * @param port USB-C port number - * @param rp Rp value for current limit (either 1.5A or 3A) - * - * @return Zero if the current limit set was successful, non-zero otherwise - */ -int raa489000_set_output_current(int port, enum tcpc_rp_value rp); - -extern const struct tcpm_drv raa489000_tcpm_drv; - -#endif diff --git a/driver/tcpm/rt1715.c b/driver/tcpm/rt1715.c deleted file mode 100644 index ed3d283bc9..0000000000 --- a/driver/tcpm/rt1715.c +++ /dev/null @@ -1,263 +0,0 @@ -/* Copyright 2021 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. - */ -/* Richtek RT1715 Type-C port controller */ - -#include "common.h" -#include "rt1715.h" -#include "tcpm/tcpci.h" -#include "tcpm/tcpm.h" -#include "timer.h" -#include "usb_pd.h" -#include "usb_pd_tcpm.h" - -#ifndef CONFIG_USB_PD_TCPM_TCPCI -#error "RT1715 is using a standard TCPCI interface" -#error "Please upgrade your board configuration" -#endif - -static int rt1715_polarity[CONFIG_USB_PD_PORT_MAX_COUNT]; -static bool rt1715_initialized[CONFIG_USB_PD_PORT_MAX_COUNT]; - - -static int rt1715_enable_ext_messages(int port, int enable) -{ - return tcpc_update8(port, RT1715_REG_VENDOR_5, - RT1715_REG_VENDOR_5_ENEXTMSG, - enable ? MASK_SET : MASK_CLR); -} - -static int rt1715_tcpci_tcpm_init(int port) -{ - int rv; - /* - * Do not fully reinitialize the registers when leaving low-power mode. - * TODO(b/179234089): Generalize this concept in the tcpm_drv API. - */ - - /* Only do soft-reset on first init. */ - if (!(rt1715_initialized[port])) { - /* RT1715 has a vendor-defined register reset */ - rv = tcpc_update8(port, RT1715_REG_VENDOR_7, - RT1715_REG_VENDOR_7_SOFT_RESET, MASK_SET); - if (rv) - return rv; - rt1715_initialized[port] = true; - msleep(10); - } - - rv = tcpc_update8(port, RT1715_REG_VENDOR_5, - RT1715_REG_VENDOR_5_SHUTDOWN_OFF, MASK_SET); - if (rv) - return rv; - - if (IS_ENABLED(CONFIG_USB_PD_REV30)) - rt1715_enable_ext_messages(port, 1); - - rv = tcpc_write(port, RT1715_REG_I2CRST_CTRL, - (RT1715_REG_I2CRST_CTRL_EN | - RT1715_REG_I2CRST_CTRL_TOUT_200MS)); - if (rv) - return rv; - - /* Unmask interrupt for LPM wakeup */ - rv = tcpc_write(port, RT1715_REG_RT_MASK, RT1715_REG_RT_MASK_M_WAKEUP); - if (rv) - return rv; - - /* - * Set tTCPCFilter (CC debounce time) to 400 us - * (min 250 us, max 500 us). - */ - rv = tcpc_write(port, RT1715_REG_TTCPC_FILTER, - RT1715_REG_TTCPC_FILTER_400US); - if (rv) - return rv; - - rv = tcpc_write(port, RT1715_REG_DRP_TOGGLE_CYCLE, - RT1715_REG_DRP_TOGGLE_CYCLE_76MS); - if (rv) - return rv; - - /* PHY control */ - /* Set PHY control registers to Richtek recommended values */ - rv = tcpc_write(port, RT1715_REG_PHY_CTRL1, - (RT1715_REG_PHY_CTRL1_ENRETRY | - RT1715_REG_PHY_CTRL1_TRANSCNT_7 | - RT1715_REG_PHY_CTRL1_TRXFILTER_125NS)); - if (rv) - return rv; - - /* Set PHY control registers to Richtek recommended values */ - rv = tcpc_write(port, RT1715_REG_PHY_CTRL2, - RT1715_REG_PHY_CTRL2_CDRTHRESH_2_58US); - if (rv) - return rv; - - return tcpci_tcpm_init(port); -} - -/* - * Selects the CC PHY noise filter voltage level according to the current - * CC voltage level. - * - * @param cc_level The CC voltage level for the port's current role - * @return EC_SUCCESS if writes succeed; failure code otherwise - */ -static inline int rt1715_init_cc_params(int port, int cc_level) -{ - int rv, en, sel; - - if (cc_level == TYPEC_CC_VOLT_RP_DEF) { - /* RXCC threshold : 0.55V */ - en = RT1715_REG_BMCIO_RXDZEN_DISABLE; - - sel = RT1715_REG_BMCIO_RXDZSEL_OCCTRL_600MA - | RT1715_REG_BMCIO_RXDZSEL_SEL; - } else { - /* RD threshold : 0.35V & RP threshold : 0.75V */ - en = RT1715_REG_BMCIO_RXDZEN_ENABLE; - - sel = RT1715_REG_BMCIO_RXDZSEL_OCCTRL_600MA - | RT1715_REG_BMCIO_RXDZSEL_SEL; - } - - rv = tcpc_write(port, RT1715_REG_BMCIO_RXDZEN, en); - if (!rv) - rv = tcpc_write(port, RT1715_REG_BMCIO_RXDZSEL, sel); - - return rv; -} - -static int rt1715_get_cc(int port, enum tcpc_cc_voltage_status *cc1, - enum tcpc_cc_voltage_status *cc2) -{ - int rv; - - rv = tcpci_tcpm_get_cc(port, cc1, cc2); - if (rv) - return rv; - - return rt1715_init_cc_params(port, rt1715_polarity[port] ? *cc2 : *cc1); -} - -/* - * See b/179256608#comment26 for explanation. - * Disable 24MHz oscillator and enable LPM. Upon exit from LPM, the LPEN will be - * reset to 0. - * - * The exit condition for LPM is CC status change, and the wakeup interrupt will - * be set. - */ -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER -static int rt1715_enter_low_power_mode(int port) -{ - int regval; - int rv; - - rv = tcpc_read(port, RT1715_REG_PWR, ®val); - if (rv) - return rv; - - regval |= RT1715_REG_PWR_BMCIO_LPEN; - regval &= ~RT1715_REG_PWR_BMCIO_OSCEN; - rv = tcpc_write(port, RT1715_REG_PWR, regval); - if (rv) - return rv; - - return tcpci_enter_low_power_mode(port); -} -#endif - -static int rt1715_set_vconn(int port, int enable) -{ - int rv; - int regval; - - /* - * Auto-idle cannot be used while sourcing Vconn. - * See b/179256608#comment26 for explanation. - */ - rv = tcpc_read(port, RT1715_REG_VENDOR_5, ®val); - if (rv) - return rv; - - if (enable) - regval &= ~RT1715_REG_VENDOR_5_AUTOIDLE_EN; - else - regval |= RT1715_REG_VENDOR_5_AUTOIDLE_EN; - - rv = tcpc_write(port, RT1715_REG_VENDOR_5, regval); - if (rv) - return rv; - - return tcpci_tcpm_set_vconn(port, enable); -} - -static int rt1715_set_polarity(int port, enum tcpc_cc_polarity polarity) -{ - int rv; - enum tcpc_cc_voltage_status cc1, cc2; - - rt1715_polarity[port] = polarity; - - rv = tcpci_tcpm_get_cc(port, &cc1, &cc2); - if (rv) - return rv; - - rv = rt1715_init_cc_params(port, polarity ? cc2 : cc1); - if (rv) - return rv; - - return tcpci_tcpm_set_polarity(port, polarity); -} - -static void rt1715_alert(int port) -{ - /* - * Make sure the wakeup interrupt is cleared. This bit is set on wakeup - * from LPM. See b/179256608#comment16 for explanation. - */ - tcpc_write(port, RT1715_REG_RT_INT, RT1715_REG_RT_INT_WAKEUP); - - tcpci_tcpc_alert(port); -} - -const struct tcpm_drv rt1715_tcpm_drv = { - .init = &rt1715_tcpci_tcpm_init, - .release = &tcpci_tcpm_release, - .get_cc = &rt1715_get_cc, -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - .check_vbus_level = &tcpci_tcpm_check_vbus_level, -#endif - .select_rp_value = &tcpci_tcpm_select_rp_value, - .set_cc = &tcpci_tcpm_set_cc, - .set_polarity = &rt1715_set_polarity, -#ifdef CONFIG_USB_PD_DECODE_SOP - .sop_prime_enable = &tcpci_tcpm_sop_prime_enable, -#endif - .set_vconn = &rt1715_set_vconn, - .set_msg_header = &tcpci_tcpm_set_msg_header, - .set_rx_enable = &tcpci_tcpm_set_rx_enable, - .get_message_raw = &tcpci_tcpm_get_message_raw, - .transmit = &tcpci_tcpm_transmit, - .tcpc_alert = &rt1715_alert, -#ifdef CONFIG_USB_PD_DISCHARGE_TCPC - .tcpc_discharge_vbus = &tcpci_tcpc_discharge_vbus, -#endif - .tcpc_enable_auto_discharge_disconnect = - &tcpci_tcpc_enable_auto_discharge_disconnect, -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - .drp_toggle = &tcpci_tcpc_drp_toggle, -#endif -#ifdef CONFIG_USB_PD_PPC - .set_snk_ctrl = &tcpci_tcpm_set_snk_ctrl, - .set_src_ctrl = &tcpci_tcpm_set_src_ctrl, -#endif - .get_chip_info = &tcpci_get_chip_info, -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER - .enter_low_power_mode = &rt1715_enter_low_power_mode, -#endif - .set_bist_test_mode = &tcpci_set_bist_test_mode, -}; diff --git a/driver/tcpm/rt1715.h b/driver/tcpm/rt1715.h deleted file mode 100644 index dcf2aa28d4..0000000000 --- a/driver/tcpm/rt1715.h +++ /dev/null @@ -1,85 +0,0 @@ -/* Copyright 2021 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. - */ -/* Richtek RT1715 Type-C port controller */ -#ifndef __CROS_EC_USB_PD_TCPM_RT1715_H -#define __CROS_EC_USB_PD_TCPM_RT1715_H - -/* I2C interface */ -#define RT1715_I2C_ADDR_FLAGS 0x4E - -#define RT1715_VENDOR_ID 0x29CF - -#define RT1715_REG_VENDOR_7 0xA0 -#define RT1715_REG_VENDOR_7_SOFT_RESET BIT(0) - -#define RT1715_REG_PHY_CTRL1 0x80 -/* Wait for tReceive before retrying transmit in response to a bad GoodCRC */ -#define RT1715_REG_PHY_CTRL1_ENRETRY BIT(7) -/* - * Bit 6:4 <TRANSCNT>: Consider CC to be idle if there are 7 or fewer BMC - * transients observed in <46.67us> - */ -#define RT1715_REG_PHY_CTRL1_TRANSCNT_7 0x70 -/* - * Bit 1:0 <TRXFilter>: RX filter to make sure the stable received PD message. - * default value is 01b - * The debounce time is (register value + 2) * 41.67ns - */ -#define RT1715_REG_PHY_CTRL1_TRXFILTER_125NS 0x01 -#define RT1715_REG_PHY_CTRL2 0x81 -/* - * Decrease the time that the PHY will wait for a second transition to detect - * a BMC-encoded 1 bit from 2.67 us to 2.25 us. - * Timeout = register value * .04167 us. - */ -#define RT1715_REG_PHY_CTRL2_CDRTHRESH_2_25US 54 -#define RT1715_REG_PHY_CTRL2_CDRTHRESH_2_5US 60 -#define RT1715_REG_PHY_CTRL2_CDRTHRESH_2_58US 62 - -#define RT1715_REG_PWR 0x90 -#define RT1715_REG_PWR_BMCIO_LPEN BIT(3) -#define RT1715_REG_PWR_VBUS_DETEN BIT(1) -#define RT1715_REG_PWR_BMCIO_OSCEN BIT(0) - -#define RT1715_REG_BMCIO_RXDZSEL 0x93 -#define RT1715_REG_BMCIO_RXDZSEL_OCCTRL_600MA BIT(7) -#define RT1715_REG_BMCIO_RXDZSEL_SEL BIT(0) - -#define RT1715_REG_RT_INT 0x98 -#define RT1715_REG_RT_INT_WAKEUP BIT(0) - -#define RT1715_REG_RT_MASK 0x99 -#define RT1715_REG_RT_MASK_M_WAKEUP BIT(0) - -#define RT1715_REG_VENDOR_5 0x9B -#define RT1715_REG_VENDOR_5_SHUTDOWN_OFF BIT(5) -#define RT1715_REG_VENDOR_5_ENEXTMSG BIT(4) -#define RT1715_REG_VENDOR_5_AUTOIDLE_EN BIT(3) - -#define RT1715_REG_I2CRST_CTRL 0x9E -/* I2C reset : (val + 1) * 12.5ms */ -#define RT1715_REG_I2CRST_CTRL_TOUT_200MS 0x0F -#define RT1715_REG_I2CRST_CTRL_TOUT_150MS 0x0B -#define RT1715_REG_I2CRST_CTRL_TOUT_100MS 0x07 -#define RT1715_REG_I2CRST_CTRL_EN BIT(7) - - -#define RT1715_REG_TTCPC_FILTER 0xA1 -#define RT1715_REG_TTCPC_FILTER_400US 0x0F - -#define RT1715_REG_DRP_TOGGLE_CYCLE 0xA2 -/* DRP Duty : (51.2 + 6.4 * val) ms */ -#define RT1715_REG_DRP_TOGGLE_CYCLE_76MS 0x04 - -#define RT1715_REG_DRP_DUTY_CTRL 0xA3 -#define RT1715_REG_DRP_DUTY_CTRL_40PERCENT 400 - -#define RT1715_REG_BMCIO_RXDZEN 0xAF -#define RT1715_REG_BMCIO_RXDZEN_ENABLE 0x01 -#define RT1715_REG_BMCIO_RXDZEN_DISABLE 0x00 - -extern const struct tcpm_drv rt1715_tcpm_drv; - -#endif /* defined(__CROS_EC_USB_PD_TCPM_RT1715_H) */ diff --git a/driver/tcpm/rt1718s.c b/driver/tcpm/rt1718s.c deleted file mode 100644 index 9d5a8895ad..0000000000 --- a/driver/tcpm/rt1718s.c +++ /dev/null @@ -1,561 +0,0 @@ -/* Copyright 2021 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. - */ - -/* - * RT1718S TCPC Driver - */ - -#include "console.h" -#include "driver/tcpm/rt1718s.h" -#include "driver/tcpm/tcpci.h" -#include "driver/tcpm/tcpm.h" -#include "stdint.h" -#include "system.h" -#include "task.h" -#include "timer.h" -#include "usb_mux.h" -#include "usb_pd.h" -#include "util.h" - -#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args) - -#define RT1718S_SW_RESET_DELAY_MS 2 - -/* i2c_write function which won't wake TCPC from low power mode. */ -static int rt1718s_write(int port, int reg, int val, int len) -{ - if (reg > 0xFF) { - return i2c_write_offset16( - tcpc_config[port].i2c_info.port, - tcpc_config[port].i2c_info.addr_flags, - reg, val, len); - } else if (len == 1) { - return tcpc_write(port, reg, val); - } else { - return tcpc_write16(port, reg, val); - } -} - -static int rt1718s_read(int port, int reg, int *val, int len) -{ - if (reg > 0xFF) { - return i2c_read_offset16( - tcpc_config[port].i2c_info.port, - tcpc_config[port].i2c_info.addr_flags, - reg, val, len); - } else if (len == 1) { - return tcpc_read(port, reg, val); - } else { - return tcpc_read16(port, reg, val); - } -} - -int rt1718s_write8(int port, int reg, int val) -{ - return rt1718s_write(port, reg, val, 1); -} - -int rt1718s_read8(int port, int reg, int *val) -{ - return rt1718s_read(port, reg, val, 1); -} - -int rt1718s_update_bits8(int port, int reg, int mask, int val) -{ - int reg_val; - - if (mask == 0xFF) - return rt1718s_write8(port, reg, val); - - RETURN_ERROR(rt1718s_read8(port, reg, ®_val)); - - reg_val &= (~mask); - reg_val |= (mask & val); - return rt1718s_write8(port, reg, reg_val); -} - -int rt1718s_write16(int port, int reg, int val) -{ - return rt1718s_write(port, reg, val, 2); -} - -int rt1718s_read16(int port, int reg, int *val) -{ - return rt1718s_read(port, reg, val, 2); -} - - -static int rt1718s_sw_reset(int port) -{ - int rv; - - rv = rt1718s_update_bits8(port, RT1718S_SYS_CTRL3, - RT1718S_SWRESET_MASK, 0xFF); - - msleep(RT1718S_SW_RESET_DELAY_MS); - - return rv; -} - -/* enable bc 1.2 sink function */ -static int rt1718s_enable_bc12_sink(int port, bool en) -{ - return rt1718s_update_bits8(port, RT1718S_RT2_BC12_SNK_FUNC, - RT1718S_RT2_BC12_SNK_FUNC_BC12_SNK_EN, - en ? 0xFF : 0); -} - -static int rt1718s_set_bc12_sink_spec_ta(int port, bool en) -{ - return rt1718s_update_bits8(port, - RT1718S_RT2_BC12_SNK_FUNC, - RT1718S_RT2_BC12_SNK_FUNC_SPEC_TA_EN, en ? 0xFF : 0); -} - -static int rt1718s_set_bc12_sink_dcdt_sel(int port, uint8_t dcdt_sel) -{ - return rt1718s_update_bits8(port, - RT1718S_RT2_BC12_SNK_FUNC, - RT1718S_RT2_BC12_SNK_FUNC_DCDT_SEL_MASK, dcdt_sel); -} - -static int rt1718s_set_bc12_sink_vlgc_option(int port, bool en) -{ - return rt1718s_update_bits8(port, - RT1718S_RT2_BC12_SNK_FUNC, - RT1718S_RT2_BC12_SNK_FUNC_VLGC_OPT, en ? 0xFF : 0); -} - -static int rt1718s_set_bc12_sink_vport_sel(int port, uint8_t sel) -{ - return rt1718s_update_bits8(port, - RT1718S_RT2_DPDM_CTR1_DPDM_SET, - RT1718S_RT2_DPDM_CTR1_DPDM_SET_DPDM_VSRC_SEL_MASK, sel); -} - -static int rt1718s_set_bc12_sink_wait_vbus(int port, bool en) -{ - return rt1718s_update_bits8(port, - RT1718S_RT2_BC12_SNK_FUNC, - RT1718S_RT2_BC12_SNK_FUNC_BC12_WAIT_VBUS, - en ? 0xFF : 0); -} - -/* - * rt1718s BC12 function initial - */ -static int rt1718s_bc12_init(int port) -{ - /* Enable vendor defined BC12 function */ - RETURN_ERROR(rt1718s_write8(port, RT1718S_RT_MASK6, - RT1718S_RT_MASK6_M_BC12_SNK_DONE | - RT1718S_RT_MASK6_M_BC12_TA_CHG)); - - RETURN_ERROR(rt1718s_write8(port, RT1718S_RT2_SBU_CTRL_01, - RT1718S_RT2_SBU_CTRL_01_DPDM_VIEN | - RT1718S_RT2_SBU_CTRL_01_DM_SWEN | - RT1718S_RT2_SBU_CTRL_01_DP_SWEN)); - - /* Disable 2.7v mode */ - RETURN_ERROR(rt1718s_set_bc12_sink_spec_ta(port, false)); - - /* DCDT select 600ms timeout */ - RETURN_ERROR(rt1718s_set_bc12_sink_dcdt_sel(port, - RT1718S_RT2_BC12_SNK_FUNC_DCDT_SEL_600MS)); - - /* Disable vlgc option */ - RETURN_ERROR(rt1718s_set_bc12_sink_vlgc_option(port, false)); - - /* DPDM voltage selection */ - RETURN_ERROR(rt1718s_set_bc12_sink_vport_sel(port, - RT1718S_RT2_DPDM_CTR1_DPDM_SET_DPDM_VSRC_SEL_0_65V)); - - /* Disable sink wait vbus */ - RETURN_ERROR(rt1718s_set_bc12_sink_wait_vbus(port, false)); - - return EC_SUCCESS; -} - -static int rt1718s_workaround(int port) -{ - int device_id; - - RETURN_ERROR(tcpc_read16(port, RT1718S_DEVICE_ID, &device_id)); - - switch (device_id) { - case RT1718S_DEVICE_ID_ES1: - RETURN_ERROR(rt1718s_update_bits8(port, RT1718S_VCONN_CONTROL_3, - RT1718S_VCONN_CONTROL_3_VCONN_OVP_DEG, - 0xFF)); - /* fallthrough */ - case RT1718S_DEVICE_ID_ES2: - RETURN_ERROR(rt1718s_update_bits8(port, TCPC_REG_FAULT_CTRL, - TCPC_REG_FAULT_CTRL_VBUS_OCP_FAULT_DIS, - 0xFF)); - RETURN_ERROR(rt1718s_update_bits8(port, RT1718S_VCON_CTRL4, - RT1718S_VCON_CTRL4_UVP_CP_EN | - RT1718S_VCON_CTRL4_OVP_CP_EN, - 0)); - RETURN_ERROR(rt1718s_update_bits8(port, RT1718S_VCONN_CONTROL_2, - RT1718S_VCONN_CONTROL_2_OVP_EN_CC1 | - RT1718S_VCONN_CONTROL_2_OVP_EN_CC2, - 0xFF)); - break; - default: - /* do nothing */ - break; - } - - return EC_SUCCESS; -} - -static int rt1718s_init(int port) -{ - static bool need_sw_reset = true; - - if (!system_jumped_late() && need_sw_reset) { - RETURN_ERROR(rt1718s_sw_reset(port)); - need_sw_reset = false; - } - - RETURN_ERROR(rt1718s_bc12_init(port)); - - /* Set VBUS_VOL_SEL to 20V */ - RETURN_ERROR(rt1718s_update_bits8(port, RT1718S_RT2_VBUS_VOL_CTRL, - RT1718S_RT2_VBUS_VOL_CTRL_VOL_SEL, - RT1718S_VBUS_VOL_TO_REG(20))); - - /* Disable FOD function */ - RETURN_ERROR(rt1718s_update_bits8(port, 0xCF, 0x40, 0x00)); - - /* Tcpc connect invalid disabled. Exit shipping mode */ - RETURN_ERROR(rt1718s_update_bits8(port, RT1718S_SYS_CTRL1, - RT1718S_SYS_CTRL1_TCPC_CONN_INVALID, 0x00)); - RETURN_ERROR(rt1718s_update_bits8(port, RT1718S_SYS_CTRL1, - RT1718S_SYS_CTRL1_SHIPPING_OFF, 0xFF)); - - /* Clear alert and fault */ - RETURN_ERROR(rt1718s_write8(port, TCPC_REG_FAULT_STATUS, 0xFF)); - RETURN_ERROR(tcpc_write16(port, TCPC_REG_ALERT, 0xFFFF)); - - RETURN_ERROR(tcpci_tcpm_init(port)); - - RETURN_ERROR(rt1718s_workaround(port)); - /* - * Set vendor defined alert unmasked, this must be done after - * tcpci_tcpm_init. - */ - RETURN_ERROR(tcpc_update16(port, TCPC_REG_ALERT_MASK, - TCPC_REG_ALERT_MASK_VENDOR_DEF, - MASK_SET)); - - RETURN_ERROR(board_rt1718s_init(port)); - - return EC_SUCCESS; -} - -__overridable int board_rt1718s_init(int port) -{ - return EC_SUCCESS; -} - -static enum charge_supplier rt1718s_get_bc12_type(int port) -{ - int data; - - if (rt1718s_read8(port, RT1718S_RT2_BC12_STAT, &data)) - return CHARGE_SUPPLIER_OTHER; - - switch (data & RT1718S_RT2_BC12_STAT_PORT_STATUS_MASK) { - case RT1718S_RT2_BC12_STAT_PORT_STATUS_NONE: - return CHARGE_SUPPLIER_NONE; - case RT1718S_RT2_BC12_STAT_PORT_STATUS_SDP: - return CHARGE_SUPPLIER_BC12_SDP; - case RT1718S_RT2_BC12_STAT_PORT_STATUS_CDP: - return CHARGE_SUPPLIER_BC12_CDP; - case RT1718S_RT2_BC12_STAT_PORT_STATUS_DCP: - return CHARGE_SUPPLIER_BC12_DCP; - } - - return CHARGE_SUPPLIER_OTHER; -} - -static int rt1718s_get_bc12_ilim(enum charge_supplier supplier) -{ - switch (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 void rt1718s_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 != CHARGE_SUPPLIER_NONE) - charge_manager_update_charge(current_bc12_type, port, - NULL); - - if (new_bc12_type != CHARGE_SUPPLIER_NONE) { - struct charge_port_info chg = { - .current = rt1718s_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 rt1718s_bc12_usb_charger_task(const int port) -{ - rt1718s_enable_bc12_sink(port, false); - - while (1) { - uint32_t evt = task_wait_event(-1); - - if (evt & USB_CHG_EVENT_VBUS) { - if (pd_snk_is_vbus_provided(port)) - rt1718s_enable_bc12_sink(port, true); - else - rt1718s_update_charge_manager( - port, CHARGE_SUPPLIER_NONE); - } - - /* detection done, update charge_manager and stop detection */ - if (evt & USB_CHG_EVENT_BC12) { - int type = rt1718s_get_bc12_type(port); - - rt1718s_update_charge_manager( - port, type); - rt1718s_enable_bc12_sink(port, false); - } - } -} - -void rt1718s_vendor_defined_alert(int port) -{ - int rv, value; - - if (IS_ENABLED(CONFIG_USB_PD_FRS_PPC) && - IS_ENABLED(CONFIG_USBC_PPC_RT1718S)) { - int int1; - - rv = rt1718s_read8(port, RT1718S_RT_INT1, &int1); - if (rv) - return; - rv = rt1718s_write8(port, RT1718S_RT_INT1, int1); - if (rv) - return; - - if ((int1 & RT1718S_RT_INT1_INT_RX_FRS)) { - pd_got_frs_signal(port); - - tcpc_write16(port, TCPC_REG_ALERT, - TCPC_REG_ALERT_VENDOR_DEF); - /* ignore other interrupts for faster frs handling */ - return; - } - } - - /* Process BC12 alert */ - rv = rt1718s_read8(port, RT1718S_RT_INT6, &value); - if (rv) - return; - - /* clear BC12 alert */ - rv = rt1718s_write8(port, RT1718S_RT_INT6, value); - if (rv) - return; - - /* check snk done */ - if (value & RT1718S_RT_INT6_INT_BC12_SNK_DONE) - task_set_event(USB_CHG_PORT_TO_TASK_ID(port), - USB_CHG_EVENT_BC12); - - /* clear the alerts from rt1718s_workaround() */ - rv = rt1718s_write8(port, RT1718S_RT_INT2, 0xFF); - if (rv) - return; - /* ES1 workaround: disable Vconn discharge */ - rv = rt1718s_update_bits8(port, RT1718S_SYS_CTRL2, - RT1718S_SYS_CTRL2_VCONN_DISCHARGE_EN, - 0); - if (rv) - return; - - tcpc_write16(port, TCPC_REG_ALERT, TCPC_REG_ALERT_VENDOR_DEF); -} - -static void rt1718s_alert(int port) -{ - int alert; - - tcpc_read16(port, TCPC_REG_ALERT, &alert); - if (alert & TCPC_REG_ALERT_VENDOR_DEF) - rt1718s_vendor_defined_alert(port); - - if (alert & ~TCPC_REG_ALERT_VENDOR_DEF) - tcpci_tcpc_alert(port); -} - -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER -static int rt1718s_enter_low_power_mode(int port) -{ - /* enter low power mode */ - RETURN_ERROR(rt1718s_update_bits8(port, RT1718S_SYS_CTRL2, - RT1718S_SYS_CTRL2_LPWR_EN, 0xFF)); - RETURN_ERROR(rt1718s_update_bits8(port, RT1718S_SYS_CTRL2, - RT1718S_SYS_CTRL2_BMCIO_OSC_EN, 0)); - - /* disable DP/DM/SBU swtiches */ - RETURN_ERROR(rt1718s_write8(port, RT1718S_RT2_SBU_CTRL_01, 0)); - - return tcpci_enter_low_power_mode(port); -} -#endif - -int rt1718s_get_adc(int port, enum rt1718s_adc_channel channel, int *adc_val) -{ - static struct mutex adc_lock; - int rv; - const int max_wait_times = 30; - - if (in_interrupt_context()) { - CPRINTS("Err: use ADC in IRQ"); - return EC_ERROR_INVAL; - } - - mutex_lock(&adc_lock); - - /* Start ADC conversation */ - rv = rt1718s_write16(port, RT1718S_ADC_CTRL_01, BIT(channel)); - if (rv) - goto out; - - /* - * The expected conversion time is 85.3us * number of enabled channels. - * Polling for 3ms should be long enough. - */ - for (int i = 0; i < max_wait_times; i++) { - int adc_done; - - usleep(100); - rv = rt1718s_read8(port, RT1718S_RT_INT6, &adc_done); - if (rv) - goto out; - if (adc_done & RT1718S_RT_INT6_INT_ADC_DONE) - break; - if (i == max_wait_times - 1) { - CPRINTS("conversion fail channel=%d", channel); - rv = EC_ERROR_TIMEOUT; - goto out; - } - } - - /* Read ADC data */ - rv = rt1718s_read16(port, RT1718S_ADC_CHX_VOL_L(channel), adc_val); - if (rv) - goto out; - - /* - * The resolution of VBUS1 ADC is 12.5mV, - * other channels are 4mV. - */ - if (channel == RT1718S_ADC_VBUS1) - *adc_val = *adc_val * 125 / 10; - else - *adc_val *= 4; - -out: - /* Cleanup: disable adc and clear interrupt. Error ignored. */ - rt1718s_write16(port, RT1718S_ADC_CTRL_01, 0); - rt1718s_write8(port, RT1718S_RT_INT6, RT1718S_RT_INT6_INT_ADC_DONE); - - mutex_unlock(&adc_lock); - return rv; -} - -void rt1718s_gpio_set_flags(int port, enum rt1718s_gpio signal, uint32_t flags) -{ - int val = 0; - - if (!(flags & GPIO_OPEN_DRAIN)) - val |= RT1718S_GPIO_CTRL_OD_N; - if (flags & GPIO_PULL_UP) - val |= RT1718S_GPIO_CTRL_PU; - if (flags & GPIO_PULL_DOWN) - val |= RT1718S_GPIO_CTRL_PD; - if (flags & GPIO_HIGH) - val |= RT1718S_GPIO_CTRL_O; - if (flags & GPIO_OUTPUT) - val |= RT1718S_GPIO_CTRL_OE; - - rt1718s_write8(port, RT1718S_GPIO_CTRL(signal), val); -} - -void rt1718s_gpio_set_level(int port, enum rt1718s_gpio signal, int value) -{ - rt1718s_update_bits8(port, RT1718S_GPIO_CTRL(signal), - RT1718S_GPIO_CTRL_O, - value ? 0xFF : 0); -} - -int rt1718s_gpio_get_level(int port, enum rt1718s_gpio signal) -{ - int val; - - rt1718s_read8(port, RT1718S_GPIO_CTRL(signal), &val); - return !!(val & RT1718S_GPIO_CTRL_I); -} - -/* RT1718S is a TCPCI compatible port controller */ -const struct tcpm_drv rt1718s_tcpm_drv = { - .init = &rt1718s_init, - .release = &tcpci_tcpm_release, - .get_cc = &tcpci_tcpm_get_cc, -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - .check_vbus_level = &tcpci_tcpm_check_vbus_level, -#endif - .select_rp_value = &tcpci_tcpm_select_rp_value, - .set_cc = &tcpci_tcpm_set_cc, - .set_polarity = &tcpci_tcpm_set_polarity, -#ifdef CONFIG_USB_PD_DECODE_SOP - .sop_prime_enable = &tcpci_tcpm_sop_prime_enable, -#endif - .set_vconn = &tcpci_tcpm_set_vconn, - .set_msg_header = &tcpci_tcpm_set_msg_header, - .set_rx_enable = &tcpci_tcpm_set_rx_enable, - .get_message_raw = &tcpci_tcpm_get_message_raw, - .transmit = &tcpci_tcpm_transmit, - .tcpc_alert = &rt1718s_alert, -#ifdef CONFIG_USB_PD_DISCHARGE_TCPC - .tcpc_discharge_vbus = &tcpci_tcpc_discharge_vbus, -#endif -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - .drp_toggle = &tcpci_tcpc_drp_toggle, -#endif - .get_chip_info = &tcpci_get_chip_info, -#ifdef CONFIG_USB_PD_PPC - .set_snk_ctrl = &tcpci_tcpm_set_snk_ctrl, - .set_src_ctrl = &tcpci_tcpm_set_src_ctrl, -#endif -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER - .enter_low_power_mode = &rt1718s_enter_low_power_mode, -#endif -}; - -const struct bc12_drv rt1718s_bc12_drv = { - .usb_charger_task = rt1718s_bc12_usb_charger_task, -}; diff --git a/driver/tcpm/rt1718s.h b/driver/tcpm/rt1718s.h deleted file mode 100644 index 07c3ed3f82..0000000000 --- a/driver/tcpm/rt1718s.h +++ /dev/null @@ -1,245 +0,0 @@ -/* Copyright 2021 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. - */ -#ifndef __CROS_EC_USB_PD_TCPM_RT1718S_H -#define __CROS_EC_USB_PD_TCPM_RT1718S_H - -#include "util.h" -#include "usb_charge.h" -#include "usb_pd_tcpm.h" - -/* RT1718S Private RegMap */ -#define RT1718S_I2C_ADDR_FLAGS 0x43 - -#define RT1718S_VID 0x29CF -#define RT1718S_PID 0x1718 - -#define RT1718S_DEVICE_ID 0x04 -#define RT1718S_DEVICE_ID_ES1 0x4511 -#define RT1718S_DEVICE_ID_ES2 0x4513 - -#define RT1718S_PHYCTRL1 0x80 -#define RT1718S_PHYCTRL2 0x81 -#define RT1718S_PHYCTRL3 0x82 -#define RT1718S_PHYCTRL7 0x86 -#define RT1718S_VCON_CTRL1 0x8A -#define RT1718S_VCON_CTRL3 0x8C -#define RT1718S_SYS_CTRL1 0x8F -#define RT1718S_SYS_CTRL1_TCPC_CONN_INVALID BIT(6) -#define RT1718S_SYS_CTRL1_SHIPPING_OFF BIT(5) -#define RT1718S_SYS_CTRL2 0x90 -#define RT1718S_SYS_CTRL2_BMCIO_OSC_EN BIT(0) -#define RT1718S_SYS_CTRL2_LPWR_EN BIT(3) - -#define RT1718S_VCONN_CONTROL_2 0x8B -#define RT1718S_VCONN_CONTROL_2_OVP_EN_CC1 BIT(7) -#define RT1718S_VCONN_CONTROL_2_OVP_EN_CC2 BIT(6) -#define RT1718S_VCONN_CONTROL_3 0x8C -#define RT1718S_VCONN_CONTROL_3_VCONN_OVP_DEG BIT(1) - -#define RT1718S_SYS_CTRL2 0x90 -#define RT1718S_SYS_CTRL2_VCONN_DISCHARGE_EN BIT(5) - -#define RT1718S_RT_MASK1 0x91 -#define RT1718S_RT_MASK1_M_VBUS_FRS_LOW BIT(7) -#define RT1718S_RT_MASK1_M_RX_FRS BIT(6) -#define RT1718S_RT_MASK2 0x92 -#define RT1718S_RT_MASK3 0x93 -#define RT1718S_RT_MASK4 0x94 -#define RT1718S_RT_MASK5 0x95 -#define RT1718S_RT_MASK6 0x96 -#define RT1718S_RT_MASK6_M_BC12_SNK_DONE BIT(7) -#define RT1718S_RT_MASK6_M_HVDCP_CHK_DONE BIT(6) -#define RT1718S_RT_MASK6_M_BC12_TA_CHG BIT(5) -#define RT1718S_RT_MASK7 0x97 - -#define RT1718S_RT_INT1 0x98 -#define RT1718S_RT_INT1_INT_VBUS_FRS_LOW BIT(7) -#define RT1718S_RT_INT1_INT_RX_FRS BIT(6) -#define RT1718S_RT_INT2 0x99 -#define RT1718S_RT_INT6 0x9D -#define RT1718S_RT_INT6_INT_BC12_SNK_DONE BIT(7) -#define RT1718S_RT_INT6_INT_HVDCP_CHK_DONE BIT(6) -#define RT1718S_RT_INT6_INT_BC12_TA_CHG BIT(5) -#define RT1718S_RT_INT6_INT_ADC_DONE BIT(0) - -#define RT1718S_RT_ST6 0xA4 -#define RT1718S_RT_ST6_BC12_SNK_DONE BIT(7) -#define RT1718S_RT_ST6_HVDCP_CHK_DONE BIT(6) -#define RT1718S_RT_ST6_BC12_TA_CHG BIT(5) - -#define RT1718S_PHYCTRL9 0xAC - -#define RT1718S_SYS_CTRL3 0xB0 -#define RT1718S_TCPC_CTRL1 0xB1 -#define RT1718S_TCPC_CTRL2 0xB2 -#define RT1718S_TCPC_CTRL3 0xB3 -#define RT1718S_SWRESET_MASK BIT(0) -#define RT1718S_TCPC_CTRL4 0xB4 -#define RT1718S_SYS_CTRL4 0xB8 -#define RT1718S_WATCHDOG_CTRL 0xBE -#define RT1718S_I2C_RST_CTRL 0xBF - -#define RT1718S_HILO_CTRL9 0xC8 -#define RT1718S_SHILED_CTRL1 0xCA -#define RT1718S_FRS_CTRL1 0xCB -#define RT1718S_FRS_CTRL1_FRSWAPRX_MASK 0xF0 -#define RT1718S_FRS_CTRL2 0xCC -#define RT1718S_FRS_CTRL2_RX_FRS_EN BIT(6) -#define RT1718S_FRS_CTRL2_FR_VBUS_SELECT BIT(4) -#define RT1718S_FRS_CTRL2_VBUS_FRS_EN BIT(3) -#define RT1718S_FRS_CTRL3 0xCE -#define RT1718S_FRS_CTRL3_FRS_RX_WAIT_GPIO2 BIT(3) -#define RT1718S_FRS_CTRL3_FRS_RX_WAIT_GPIO1 BIT(2) - -#define RT1718S_DIS_SRC_VBUS_CTRL 0xE0 -#define RT1718S_ENA_SRC_VBUS_CTRL 0xE1 -#define RT1718S_FAULT_OC1_VBUS_CTRL 0xE3 -#define RT1718S_GPIO1_VBUS_CTRL 0xEA -#define RT1718S_GPIO1_VBUS_CTRL_FRS_RX_VBUS BIT(6) -#define RT1718S_GPIO2_VBUS_CTRL 0xEB -#define RT1718S_GPIO2_VBUS_CTRL_FRS_RX_VBUS BIT(6) -#define RT1718S_VBUS_CTRL_EN 0xEC -#define RT1718S_VBUS_CTRL_EN_GPIO2_VBUS_PATH_EN BIT(7) -#define RT1718S_VBUS_CTRL_EN_GPIO1_VBUS_PATH_EN BIT(6) - -#define RT1718S_GPIO_CTRL(n) (0xED + (n)) -#define RT1718S_GPIO_CTRL_PU BIT(5) -#define RT1718S_GPIO_CTRL_PD BIT(4) -#define RT1718S_GPIO_CTRL_OD_N BIT(3) -#define RT1718S_GPIO_CTRL_OE BIT(2) -#define RT1718S_GPIO_CTRL_O BIT(1) -#define RT1718S_GPIO_CTRL_I BIT(0) - -#define RT1718S_UNLOCK_PW_2 0xF0 -#define RT1718S_UNLOCK_PW_1 0xF1 - -#define RT1718S_RT2_SYS_CTRL5 0xF210 - -#define RT1718S_VBUS_VOL_TO_REG(_vol) (CLAMP(_vol, 5, 20) - 5) -#define RT1718S_VBUS_PCT_TO_REG(_pct) (CLAMP(_pct, 5, 20) \ - / 5 - 1) -#define RT1718S_RT2_VBUS_VOL_CTRL 0xF213 -#define RT1718S_RT2_VBUS_VOL_CTRL_OVP_SEL (BIT(5) | BIT(4)) -#define RT1718S_RT2_VBUS_VOL_CTRL_VOL_SEL 0x0F - -#define RT1718S_VCON_CTRL4 0xF211 -#define RT1718S_VCON_CTRL4_UVP_CP_EN BIT(5) -#define RT1718S_VCON_CTRL4_OVP_CP_EN BIT(4) - -#define RT1718S_RT2_VBUS_OCRC_EN 0xF214 -#define RT1718S_RT2_VBUS_OCRC_EN_VBUS_OCP1_EN BIT(0) -#define RT1718S_RT2_VBUS_OCP_CTRL1 0xF216 -#define RT1718S_RT2_VBUS_OCP_CTRL4 0xF219 - -#define RT1718S_RT2_SBU_CTRL_01 0xF23A -#define RT1718S_RT2_SBU_CTRL_01_SBU_VIEN BIT(7) -#define RT1718S_RT2_SBU_CTRL_01_DPDM_VIEN BIT(6) -#define RT1718S_RT2_SBU_CTRL_01_SBU2_SWEN BIT(3) -#define RT1718S_RT2_SBU_CTRL_01_SBU1_SWEN BIT(2) -#define RT1718S_RT2_SBU_CTRL_01_DM_SWEN BIT(1) -#define RT1718S_RT2_SBU_CTRL_01_DP_SWEN BIT(0) - -#define RT1718S_RT2_BC12_SNK_FUNC 0xF260 -#define RT1718S_RT2_BC12_SNK_FUNC_BC12_SNK_EN BIT(7) -#define RT1718S_RT2_BC12_SNK_FUNC_SPEC_TA_EN BIT(6) -#define RT1718S_RT2_BC12_SNK_FUNC_DCDT_SEL_MASK 0x30 -#define RT1718S_RT2_BC12_SNK_FUNC_DCDT_SEL_DISABLE 0x00 -#define RT1718S_RT2_BC12_SNK_FUNC_DCDT_SEL_300MS 0x10 -#define RT1718S_RT2_BC12_SNK_FUNC_DCDT_SEL_600MS 0x20 -#define RT1718S_RT2_BC12_SNK_FUNC_DCDT_SEL_WAIT_DATA 0x30 -#define RT1718S_RT2_BC12_SNK_FUNC_VLGC_OPT BIT(3) -#define RT1718S_RT2_BC12_SNK_FUNC_VPORT_SEL BIT(2) -#define RT1718S_RT2_BC12_SNK_FUNC_BC12_WAIT_VBUS BIT(1) - -#define RT1718S_RT2_BC12_STAT 0xF261 -#define RT1718S_RT2_BC12_STAT_DCDT BIT(4) -#define RT1718S_RT2_BC12_STAT_PORT_STATUS_MASK 0x0F -#define RT1718S_RT2_BC12_STAT_PORT_STATUS_NONE 0x00 -#define RT1718S_RT2_BC12_STAT_PORT_STATUS_SDP 0x0D -#define RT1718S_RT2_BC12_STAT_PORT_STATUS_CDP 0x0E -#define RT1718S_RT2_BC12_STAT_PORT_STATUS_DCP 0x0F - - -#define RT1718S_RT2_DPDM_CTR1_DPDM_SET 0xF263 -#define RT1718S_RT2_DPDM_CTR1_DPDM_SET_DPDM_VSRC_SEL_MASK 0x03 -#define RT1718S_RT2_DPDM_CTR1_DPDM_SET_DPDM_VSRC_SEL_0_55V 0x00 -#define RT1718S_RT2_DPDM_CTR1_DPDM_SET_DPDM_VSRC_SEL_0_60V 0x01 -#define RT1718S_RT2_DPDM_CTR1_DPDM_SET_DPDM_VSRC_SEL_0_65V 0x02 -#define RT1718S_RT2_DPDM_CTR1_DPDM_SET_DPDM_VSRC_SEL_0_70V 0x03 - -#define RT1718S_RT2_BC12_SRC_FUNC 0xF26D -#define RT1718S_RT2_BC12_SRC_FUNC_BC12_SRC_EN BIT(7) -#define RT1718S_RT2_BC12_SRC_FUNC_SRC_MODE_SEL_MASK 0x70 -#define RT1718S_RT2_BC12_SRC_FUNC_SRC_MODE_SEL_BC12_SDP 0x00 -#define RT1718S_RT2_BC12_SRC_FUNC_SRC_MODE_SEL_BC12_CDP 0x10 -#define RT1718S_RT2_BC12_SRC_FUNC_SRC_MODE_SEL_BC12_DCP 0x20 -#define RT1718S_RT2_BC12_SRC_FUNC_WAIT_VBUS_ON BIT(0) - -#define RT1718S_ADC_CTRL_01 0xF2A0 -#define RT1718S_ADC_CTRL_02 0xF2A1 -#define RT1718S_ADC_CHX_VOL_L(ch) (0xF2A6 + (ch) * 2) -#define RT1718S_ADC_CHX_VOL_H(ch) (0xF2A7 + (ch) * 2) - -extern const struct tcpm_drv rt1718s_tcpm_drv; -extern const struct bc12_drv rt1718s_bc12_drv; - -int rt1718s_write8(int port, int reg, int val); -int rt1718s_read8(int port, int reg, int *val); -int rt1718s_update_bits8(int port, int reg, int mask, int val); -int rt1718s_write16(int port, int reg, int val); -int rt1718s_read16(int port, int reg, int *val); -__override_proto int board_rt1718s_init(int port); - -enum rt1718s_adc_channel { - RT1718S_ADC_VBUS1 = 0, - RT1718S_ADC_VBUS2, - RT1718S_ADC_VDC, - RT1718S_ADC_VBUS_CURRENT, - RT1718S_ADC_CC1, - RT1718S_ADC_CC2, - RT1718S_ADC_SBU1, - RT1718S_ADC_SBU2, - RT1718S_ADC_DP, - RT1718S_ADC_DM, - RT1718S_ADC_CH10, - RT1718S_ADC_CH11, -}; - -int rt1718s_get_adc(int port, enum rt1718s_adc_channel channel, int *adc_val); - -enum rt1718s_gpio { - RT1718S_GPIO1 = 0, - RT1718S_GPIO2, - RT1718S_GPIO3, -}; - -/** - * Set flags for GPIO - * - * @param port rt1718s I2C port - * @param signal gpio pin name in enum rt1718s_gpio - * @param flags GPIO_* flags defined in include/gpio.h - */ -void rt1718s_gpio_set_flags(int port, enum rt1718s_gpio signal, uint32_t flags); - -/** - * Set the value of a signal - * - * @param port rt1718s I2C port - * @param signal gpio pin name in enum rt1718s_gpio - * @param value New value for signal (0 = low, non-zero = high) - */ -void rt1718s_gpio_set_level(int port, enum rt1718s_gpio signal, int value); - -/** - * Get the current value of a signal. - * - * @param port rt1718s I2C port - * @param signal gpio pin name in enum rt1718s_gpio - * @return 0 if low, 1 if high. - */ -int rt1718s_gpio_get_level(int port, enum rt1718s_gpio signal); - -#endif /* __CROS_EC_USB_PD_TCPM_MT6370_H */ diff --git a/driver/tcpm/stm32gx.c b/driver/tcpm/stm32gx.c deleted file mode 100644 index 359c7c1108..0000000000 --- a/driver/tcpm/stm32gx.c +++ /dev/null @@ -1,186 +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. - */ - -/* TCPM for STM32Gx UCPD module */ - -#include "chip/stm32/ucpd-stm32gx.h" -#include "common.h" -#include "config.h" -#include "console.h" -#include "registers.h" -#include "stm32gx.h" -#include "system.h" -#include "task.h" -#include "tcpm/tcpci.h" -#include "timer.h" -#include "util.h" -#include "usb_pd.h" -#include "usb_pd_tcpm.h" -#include "hooks.h" - -/* - * STM32G4 UCPD peripheral does not have the ability to detect VBUS, but - * CONFIG_USB_PD_VBUS_DETECT_TCPC maybe still be defined for another port on the - * same board which uses a TCPC that does have this feature. Therefore, this - * config option is not considered an error. - */ -#if defined(CONFIG_USB_PD_TCPC_LOW_POWER) -#error "Unsupported config options of Stm32gx PD driver" -#endif - -#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) -#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) - -/* Wait time for vconn power switch to turn off. */ -#ifndef PD_STM32GX_VCONN_TURN_OFF_DELAY_US -#define PD_STM32GX_VCONN_TURN_OFF_DELAY_US 500 -#endif - -static int cached_rp[CONFIG_USB_PD_PORT_MAX_COUNT]; - - -static int stm32gx_tcpm_get_message_raw(int port, uint32_t *buf, int *head) -{ - return stm32gx_ucpd_get_message_raw(port, buf, head); -} - -static int stm32gx_tcpm_init(int port) -{ - return stm32gx_ucpd_init(port); -} - -static int stm32gx_tcpm_release(int port) -{ - return stm32gx_ucpd_release(port); -} - -static int stm32gx_tcpm_get_cc(int port, enum tcpc_cc_voltage_status *cc1, - enum tcpc_cc_voltage_status *cc2) -{ - /* Get cc_state value for each CC line */ - stm32gx_ucpd_get_cc(port, cc1, cc2); - - return EC_SUCCESS; -} - -static int stm32gx_tcpm_select_rp_value(int port, int rp_sel) -{ - cached_rp[port] = rp_sel; - - return EC_SUCCESS; -} - -static int stm32gx_tcpm_set_cc(int port, int pull) -{ - return stm32gx_ucpd_set_cc(port, pull, cached_rp[port]); -} - -static int stm32gx_tcpm_set_polarity(int port, enum tcpc_cc_polarity polarity) -{ - return stm32gx_ucpd_set_polarity(port, polarity); -} - -static int stm32gx_tcpm_set_vconn(int port, int enable) -{ - stm32gx_ucpd_vconn_disc_rp(port, enable); - - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) - stm32gx_ucpd_sop_prime_enable(port, enable); - - return EC_SUCCESS; -} - -static int stm32gx_tcpm_set_msg_header(int port, int power_role, int data_role) -{ - return stm32gx_ucpd_set_msg_header(port, power_role, data_role); -} - -static int stm32gx_tcpm_set_rx_enable(int port, int enable) -{ - return stm32gx_ucpd_set_rx_enable(port, enable); -} - -static int stm32gx_tcpm_transmit(int port, - enum tcpci_msg_type type, - uint16_t header, - const uint32_t *data) -{ - return stm32gx_ucpd_transmit(port, type, header, data); -} - -static int stm32gx_tcpm_sop_prime_enable(int port, bool enable) -{ - return stm32gx_ucpd_sop_prime_enable(port, enable); -} - - -static int stm32gx_tcpm_get_chip_info(int port, int live, - struct ec_response_pd_chip_info_v1 *chip_info) -{ - return stm32gx_ucpd_get_chip_info(port, live, chip_info); -} - -static void stm32gx_tcpm_sw_reset(void) -{ - /* - * TODO(b/167601672): Not sure if this hook is required for UCPD as - * opposed to TCPCI compliant TCPC. Leaving this a placeholder so I - * don't forget to pull this back in, if required. - */ -} -DECLARE_HOOK(HOOK_USB_PD_DISCONNECT, stm32gx_tcpm_sw_reset, HOOK_PRIO_DEFAULT); - -static int stm32gx_tcpm_reset_bist_type_2(int port) -{ - /* - * The UCPD peripheral must be disabled, then enabled, to recover from - * starting BIST type-2 mode. Call the init method to accomplish - * this. Then, need to send a hard reset to port partner. - */ - stm32gx_ucpd_init(port); - pd_execute_hard_reset(port); - task_set_event(PD_PORT_TO_TASK_ID(port), TASK_EVENT_WAKE); - - return EC_SUCCESS; -} - -enum ec_error_list stm32gx_tcpm_set_bist_test_mode(const int port, - const bool enable) -{ - return stm32gx_ucpd_set_bist_test_mode(port, enable); -} - -bool stm32gx_tcpm_check_vbus_level(int port, enum vbus_level level) -{ - /* - * UCPD peripheral can't detect VBUS, so always return 0. Any port which - * uses the stm32g4 UCPD peripheral for its TCPC would also have a PPC - * that will handle VBUS detection. However, there may be products which - * don't have a PPC on some ports that will rely on a TCPC to do VBUS - * detection. - */ - return 0; -} - -const struct tcpm_drv stm32gx_tcpm_drv = { - .init = &stm32gx_tcpm_init, - .release = &stm32gx_tcpm_release, - .get_cc = &stm32gx_tcpm_get_cc, - .check_vbus_level = &stm32gx_tcpm_check_vbus_level, - .select_rp_value = &stm32gx_tcpm_select_rp_value, - .set_cc = &stm32gx_tcpm_set_cc, - .set_polarity = &stm32gx_tcpm_set_polarity, -#ifdef CONFIG_USB_PD_DECODE_SOP - .sop_prime_enable = &stm32gx_tcpm_sop_prime_enable, -#endif - .set_vconn = &stm32gx_tcpm_set_vconn, - .set_msg_header = &stm32gx_tcpm_set_msg_header, - .set_rx_enable = &stm32gx_tcpm_set_rx_enable, - .get_message_raw = &stm32gx_tcpm_get_message_raw, - .transmit = &stm32gx_tcpm_transmit, - .get_chip_info = &stm32gx_tcpm_get_chip_info, - .reset_bist_type_2 = &stm32gx_tcpm_reset_bist_type_2, - .set_bist_test_mode = &stm32gx_tcpm_set_bist_test_mode, -}; diff --git a/driver/tcpm/stm32gx.h b/driver/tcpm/stm32gx.h deleted file mode 100644 index de6a803d52..0000000000 --- a/driver/tcpm/stm32gx.h +++ /dev/null @@ -1,14 +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. - */ - -/* USB Power delivery port management */ -#ifndef __CROS_EC_DRIVER_TCPM_STM32GX_H -#define __CROS_EC_DRIVER_TCPM_STM32GX_H - - -extern const struct tcpm_drv stm32gx_tcpm_drv; - - -#endif /* __CROS_EC_DRIVER_TCPM_STM32GX_H */ diff --git a/driver/tcpm/stub.c b/driver/tcpm/stub.c deleted file mode 100644 index 863a88c044..0000000000 --- a/driver/tcpm/stub.c +++ /dev/null @@ -1,159 +0,0 @@ -/* 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. - */ - -/* TCPM for MCU also running TCPC */ - -#include "task.h" -#include "tcpm/tcpci.h" -#include "tcpm/tcpm.h" -#include "usb_pd.h" -#include "usb_pd_tcpc.h" -#include "usb_pd_tcpm.h" - -static int init_alert_mask(int port) -{ - uint16_t mask; - int rv; - - /* - * Create mask of alert events that will cause the TCPC to - * signal the TCPM via the Alert# gpio line. - */ - mask = TCPC_REG_ALERT_TX_SUCCESS | TCPC_REG_ALERT_TX_FAILED | - TCPC_REG_ALERT_TX_DISCARDED | TCPC_REG_ALERT_RX_STATUS | - TCPC_REG_ALERT_RX_HARD_RST | TCPC_REG_ALERT_CC_STATUS; - /* Set the alert mask in TCPC */ - rv = tcpc_alert_mask_set(port, mask); - - return rv; -} - -static int init_power_status_mask(int port) -{ - return tcpc_set_power_status_mask(port, 0); -} - -int tcpm_init(int port) -{ - int rv; - - tcpc_init(port); - rv = init_alert_mask(port); - if (rv) - return rv; - - return init_power_status_mask(port); -} - -int tcpm_get_cc(int port, enum tcpc_cc_voltage_status *cc1, - enum tcpc_cc_voltage_status *cc2) -{ - return tcpc_get_cc(port, cc1, cc2); -} - -int tcpm_select_rp_value(int port, int rp) -{ - return tcpc_select_rp_value(port, rp); -} - -int tcpm_set_cc(int port, int pull) -{ - return tcpc_set_cc(port, pull); -} - -int tcpm_set_polarity(int port, enum tcpc_cc_polarity polarity) -{ - return tcpc_set_polarity(port, polarity_rm_dts(polarity)); -} - -int tcpm_set_vconn(int port, int enable) -{ - return tcpc_set_vconn(port, enable); -} - -int tcpm_set_msg_header(int port, int power_role, int data_role) -{ - return tcpc_set_msg_header(port, power_role, data_role); -} - -static int tcpm_alert_status(int port, int *alert) -{ - /* Read TCPC Alert register */ - return tcpc_alert_status(port, alert); -} - -int tcpm_set_rx_enable(int port, int enable) -{ - return tcpc_set_rx_enable(port, enable); -} - -void tcpm_enable_auto_discharge_disconnect(int port, int enable) -{ -} - -int tcpm_has_pending_message(int port) -{ - return !rx_buf_is_empty(port); -} - -int tcpm_dequeue_message(int port, uint32_t *payload, int *head) -{ - int ret = tcpc_get_message(port, payload, head); - - /* Read complete, clear RX status alert bit */ - tcpc_alert_status_clear(port, TCPC_REG_ALERT_RX_STATUS); - - return ret; -} - -void tcpm_clear_pending_messages(int port) -{ - rx_buf_clear(port); -} - -int tcpm_transmit(int port, enum tcpci_msg_type type, uint16_t header, - const uint32_t *data) -{ - return tcpc_transmit(port, type, header, data); -} - -void tcpc_alert(int port) -{ - int status; - - /* Read the Alert register from the TCPC */ - tcpm_alert_status(port, &status); - - /* - * Clear alert status for everything except RX_STATUS, which shouldn't - * be cleared until we have successfully retrieved message. - */ - if (status & ~TCPC_REG_ALERT_RX_STATUS) - tcpc_alert_status_clear(port, - status & ~TCPC_REG_ALERT_RX_STATUS); - - if (status & TCPC_REG_ALERT_CC_STATUS) { - /* CC status changed, wake task */ - task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_CC); - } - if (status & TCPC_REG_ALERT_RX_STATUS) { - /* - * message received. since TCPC is compiled in, we - * already woke the PD task up from the phy layer via - * pd_rx_event(), so we don't need to wake it again. - */ - } - if (status & TCPC_REG_ALERT_RX_HARD_RST) { - /* hard reset received */ - task_set_event(PD_PORT_TO_TASK_ID(port), - PD_EVENT_RX_HARD_RESET); - } - if (status & TCPC_REG_ALERT_TX_COMPLETE) { - /* transmit complete */ - pd_transmit_complete(port, status & TCPC_REG_ALERT_TX_SUCCESS ? - TCPC_TX_COMPLETE_SUCCESS : - TCPC_TX_COMPLETE_FAILED); - } -} diff --git a/driver/tcpm/tcpci.c b/driver/tcpm/tcpci.c deleted file mode 100644 index 1e08e0967d..0000000000 --- a/driver/tcpm/tcpci.c +++ /dev/null @@ -1,1838 +0,0 @@ -/* 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. - */ - -/* Type-C port manager */ - -#include "atomic.h" -#include "anx74xx.h" -#include "compile_time_macros.h" -#include "console.h" -#include "ec_commands.h" -#include "hooks.h" -#include "i2c.h" -#include "ps8xxx.h" -#include "task.h" -#include "tcpm/tcpci.h" -#include "tcpm/tcpm.h" -#include "timer.h" -#include "usb_charge.h" -#include "usb_common.h" -#include "usb_mux.h" -#include "usb_pd.h" -#include "usb_pd_flags.h" -#include "usb_pd_tcpc.h" -#include "usb_pd_tcpm.h" -#include "util.h" - -#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) -#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) - -STATIC_IF(CONFIG_USB_PD_DECODE_SOP) - bool sop_prime_en[CONFIG_USB_PD_PORT_MAX_COUNT]; -STATIC_IF(CONFIG_USB_PD_DECODE_SOP) - int rx_en[CONFIG_USB_PD_PORT_MAX_COUNT]; - -#define TCPC_FLAGS_VSAFE0V(_flags) \ - ((_flags & TCPC_FLAGS_TCPCI_REV2_0) && \ - !(_flags & TCPC_FLAGS_TCPCI_REV2_0_NO_VSAFE0V)) - -/**************************************************************************** - * TCPCI DEBUG Helpers - */ - -/* TCPCI FAULT-0x01 is an invalid I2C operation was performed. This tends - * to have to do with the state of registers and the last write operation. - * Defining DEBUG_I2C_FAULT_LAST_WRITE_OP will track the write operations, - * excluding XFER and BlockWrites, in an attempt to give clues as to what - * was written to the TCPCI that caused the issue. - */ -#undef DEBUG_I2C_FAULT_LAST_WRITE_OP - -struct i2c_wrt_op { - int addr; - int reg; - int val; - int mask; -}; -STATIC_IF(DEBUG_I2C_FAULT_LAST_WRITE_OP) - struct i2c_wrt_op last_write_op[CONFIG_USB_PD_PORT_MAX_COUNT]; - -/* - * AutoDischargeDisconnect has caused a number of issues with the - * feature not being correctly enabled/disabled. Defining - * DEBUG_AUTO_DISCHARGE_DISCONNECT will output a line for each enable - * and disable to help better understand any AutoDischargeDisconnect - * issues. - */ -#undef DEBUG_AUTO_DISCHARGE_DISCONNECT - -/* - * ForcedDischarge debug to help coordinate with AutoDischarge. - * Defining DEBUG_FORCED_DISCHARGE will output a line for each enable - * and disable to help better understand any Discharge issues. - */ -#undef DEBUG_FORCED_DISCHARGE - -/* - * Seeing the CC Status and ROLE Control registers as well as the - * CC that is being determined from this information can be - * helpful. Defining DEBUG_GET_CC will output a line that gives - * this useful information - */ -#undef DEBUG_GET_CC - -struct get_cc_values { - int cc1; - int cc2; - int cc_sts; - int role; -}; -STATIC_IF(DEBUG_GET_CC) - struct get_cc_values last_get_cc[CONFIG_USB_PD_PORT_MAX_COUNT]; - -/* - * Seeing RoleCtrl updates can help determine why GetCC is not - * working as it should be. - */ -#undef DEBUG_ROLE_CTRL_UPDATES - -/****************************************************************************/ - -/* - * Last reported VBus Level - * - * BIT(VBUS_SAFE0V) will indicate if in SAFE0V - * BIT(VBUS_PRESENT) will indicate if in PRESENT in the TCPCI POWER_STATUS - * - * Note that VBUS_REMOVED cannot be distinguished from !VBUS_PRESENT with - * this interface, but the trigger thresholds for Vbus Present should allow the - * same bit to be used safely for both. - * - * TODO(b/149530538): Some TCPCs may be able to implement - * VBUS_SINK_DISCONNECT_THRESHOLD to support vSinkDisconnectPD - */ -static int tcpc_vbus[CONFIG_USB_PD_PORT_MAX_COUNT]; - -/* Cached RP role values */ -static int cached_rp[CONFIG_USB_PD_PORT_MAX_COUNT]; - -/* Cache our Device Capabilities at init for later reference */ -static int dev_cap_1[CONFIG_USB_PD_PORT_MAX_COUNT]; - -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER -int tcpc_addr_write(int port, int i2c_addr, int reg, int val) -{ - int rv; - - pd_wait_exit_low_power(port); - - if (IS_ENABLED(DEBUG_I2C_FAULT_LAST_WRITE_OP)) { - last_write_op[port].addr = i2c_addr; - last_write_op[port].reg = reg; - last_write_op[port].val = val & 0xFF; - last_write_op[port].mask = 0; - } - - rv = i2c_write8(tcpc_config[port].i2c_info.port, - i2c_addr, reg, val); - - pd_device_accessed(port); - return rv; -} - -int tcpc_addr_write16(int port, int i2c_addr, int reg, int val) -{ - int rv; - - pd_wait_exit_low_power(port); - - if (IS_ENABLED(DEBUG_I2C_FAULT_LAST_WRITE_OP)) { - last_write_op[port].addr = i2c_addr; - last_write_op[port].reg = reg; - last_write_op[port].val = val & 0xFFFF; - last_write_op[port].mask = 0; - } - - rv = i2c_write16(tcpc_config[port].i2c_info.port, - i2c_addr, reg, val); - - pd_device_accessed(port); - return rv; -} - -int tcpc_addr_read(int port, int i2c_addr, int reg, int *val) -{ - int rv; - - pd_wait_exit_low_power(port); - - rv = i2c_read8(tcpc_config[port].i2c_info.port, - i2c_addr, reg, val); - - pd_device_accessed(port); - return rv; -} - -int tcpc_addr_read16(int port, int i2c_addr, int reg, int *val) -{ - pd_wait_exit_low_power(port); - - return tcpc_addr_read16_no_lpm_exit(port, i2c_addr, reg, val); -} - -int tcpc_addr_read16_no_lpm_exit(int port, int i2c_addr, int reg, int *val) -{ - int rv; - - rv = i2c_read16(tcpc_config[port].i2c_info.port, - i2c_addr, reg, val); - - pd_device_accessed(port); - return rv; -} - -int tcpc_read_block(int port, int reg, uint8_t *in, int size) -{ - int rv; - - pd_wait_exit_low_power(port); - - rv = i2c_read_block(tcpc_config[port].i2c_info.port, - tcpc_config[port].i2c_info.addr_flags, - reg, in, size); - - pd_device_accessed(port); - return rv; -} - -int tcpc_write_block(int port, int reg, const uint8_t *out, int size) -{ - int rv; - - pd_wait_exit_low_power(port); - - rv = i2c_write_block(tcpc_config[port].i2c_info.port, - tcpc_config[port].i2c_info.addr_flags, - reg, out, size); - - pd_device_accessed(port); - return rv; -} - -int tcpc_xfer(int port, const uint8_t *out, int out_size, - uint8_t *in, int in_size) -{ - int rv; - /* Dispatching to tcpc_xfer_unlocked reduces code size growth. */ - tcpc_lock(port, 1); - rv = tcpc_xfer_unlocked(port, out, out_size, in, in_size, - I2C_XFER_SINGLE); - tcpc_lock(port, 0); - return rv; -} - -int tcpc_xfer_unlocked(int port, const uint8_t *out, int out_size, - uint8_t *in, int in_size, int flags) -{ - int rv; - - pd_wait_exit_low_power(port); - - rv = i2c_xfer_unlocked(tcpc_config[port].i2c_info.port, - tcpc_config[port].i2c_info.addr_flags, - out, out_size, in, in_size, flags); - - pd_device_accessed(port); - return rv; -} - -int tcpc_update8(int port, int reg, - uint8_t mask, - enum mask_update_action action) -{ - int rv; - const int i2c_addr = tcpc_config[port].i2c_info.addr_flags; - - pd_wait_exit_low_power(port); - - if (IS_ENABLED(DEBUG_I2C_FAULT_LAST_WRITE_OP)) { - last_write_op[port].addr = i2c_addr; - last_write_op[port].reg = reg; - last_write_op[port].val = 0; - last_write_op[port].mask = (mask & 0xFF) | (action << 16); - } - - rv = i2c_update8(tcpc_config[port].i2c_info.port, - i2c_addr, reg, mask, action); - - pd_device_accessed(port); - return rv; -} - -int tcpc_update16(int port, int reg, - uint16_t mask, - enum mask_update_action action) -{ - int rv; - const int i2c_addr = tcpc_config[port].i2c_info.addr_flags; - - pd_wait_exit_low_power(port); - - if (IS_ENABLED(DEBUG_I2C_FAULT_LAST_WRITE_OP)) { - last_write_op[port].addr = i2c_addr; - last_write_op[port].reg = reg; - last_write_op[port].val = 0; - last_write_op[port].mask = (mask & 0xFFFF) | (action << 16); - } - - rv = i2c_update16(tcpc_config[port].i2c_info.port, - i2c_addr, reg, mask, action); - - pd_device_accessed(port); - return rv; -} - -#endif /* CONFIG_USB_PD_TCPC_LOW_POWER */ - -/* - * TCPCI maintains and uses cached values for the RP and - * last used PULL values. Since TCPC drivers are allowed - * to use some of the TCPCI functionality, these global - * cached values need to be maintained in case part of the - * used TCPCI functionality relies on these values - */ -void tcpci_set_cached_rp(int port, int rp) -{ - cached_rp[port] = rp; -} - -int tcpci_get_cached_rp(int port) -{ - return cached_rp[port]; -} - -static int init_alert_mask(int port) -{ - int rv; - uint16_t mask; - - /* - * Create mask of alert events that will cause the TCPC to - * signal the TCPM via the Alert# gpio line. - */ - if (get_usb_pd_vbus_detect() == USB_PD_VBUS_DETECT_TCPC) { - mask = TCPC_REG_ALERT_TX_SUCCESS | TCPC_REG_ALERT_TX_FAILED | - TCPC_REG_ALERT_TX_DISCARDED | TCPC_REG_ALERT_RX_STATUS | - TCPC_REG_ALERT_RX_HARD_RST | TCPC_REG_ALERT_CC_STATUS | - TCPC_REG_ALERT_FAULT - | TCPC_REG_ALERT_POWER_STATUS - ; - } else { - mask = TCPC_REG_ALERT_TX_SUCCESS | TCPC_REG_ALERT_TX_FAILED | - TCPC_REG_ALERT_TX_DISCARDED | TCPC_REG_ALERT_RX_STATUS | - TCPC_REG_ALERT_RX_HARD_RST | TCPC_REG_ALERT_CC_STATUS | - TCPC_REG_ALERT_FAULT - ; - } - - /* TCPCI Rev2 includes SAFE0V alerts */ - if (TCPC_FLAGS_VSAFE0V(tcpc_config[port].flags)) - mask |= TCPC_REG_ALERT_EXT_STATUS; - - if (IS_ENABLED(CONFIG_USB_PD_FRS_TCPC)) - mask |= TCPC_REG_ALERT_ALERT_EXT; - - /* Set the alert mask in TCPC */ - rv = tcpc_write16(port, TCPC_REG_ALERT_MASK, mask); - - if (IS_ENABLED(CONFIG_USB_PD_FRS_TCPC)) { - if (rv) - return rv; - - /* Sink FRS allowed */ - mask = TCPC_REG_ALERT_EXT_SNK_FRS; - rv = tcpc_write(port, TCPC_REG_ALERT_EXTENDED_MASK, mask); - } - return rv; -} - -static int clear_alert_mask(int port) -{ - return tcpc_write16(port, TCPC_REG_ALERT_MASK, 0); -} - -static int init_power_status_mask(int port) -{ - uint8_t mask; - int rv; - - if (get_usb_pd_vbus_detect() == USB_PD_VBUS_DETECT_TCPC) - mask = TCPC_REG_POWER_STATUS_VBUS_PRES; - else - mask = 0; - - rv = tcpc_write(port, TCPC_REG_POWER_STATUS_MASK , mask); - - return rv; -} - -static int clear_power_status_mask(int port) -{ - return tcpc_write(port, TCPC_REG_POWER_STATUS_MASK, 0); -} - -static int tcpci_tcpm_get_power_status(int port, int *status) -{ - return tcpc_read(port, TCPC_REG_POWER_STATUS, status); -} - -int tcpci_tcpm_select_rp_value(int port, int rp) -{ - /* Keep track of current RP value */ - tcpci_set_cached_rp(port, rp); - - return EC_SUCCESS; -} - -void tcpci_tcpc_discharge_vbus(int port, int enable) -{ - if (IS_ENABLED(DEBUG_FORCED_DISCHARGE)) - CPRINTS("C%d: ForceDischarge %sABLED", - port, enable ? "EN" : "DIS"); - - tcpc_update8(port, - TCPC_REG_POWER_CTRL, - TCPC_REG_POWER_CTRL_FORCE_DISCHARGE, - (enable) ? MASK_SET : MASK_CLR); -} - -/* - * Auto Discharge Disconnect is supposed to be enabled when we - * are connected and disabled after we are disconnected and - * VBus is at SafeV0 - */ -void tcpci_tcpc_enable_auto_discharge_disconnect(int port, int enable) -{ - if (IS_ENABLED(DEBUG_AUTO_DISCHARGE_DISCONNECT)) - CPRINTS("C%d: AutoDischargeDisconnect %sABLED", - port, enable ? "EN" : "DIS"); - - tcpc_update8(port, - TCPC_REG_POWER_CTRL, - TCPC_REG_POWER_CTRL_AUTO_DISCHARGE_DISCONNECT, - (enable) ? MASK_SET : MASK_CLR); -} - -int tcpci_tcpc_debug_accessory(int port, bool enable) -{ - return tcpc_update8(port, TCPC_REG_CONFIG_STD_OUTPUT, - TCPC_REG_CONFIG_STD_OUTPUT_DBG_ACC_CONN_N, - enable ? MASK_CLR : MASK_SET); -} - -int tcpci_tcpm_get_cc(int port, enum tcpc_cc_voltage_status *cc1, - enum tcpc_cc_voltage_status *cc2) -{ - int role; - int status; - int cc1_present_rd, cc2_present_rd; - int rv; - - /* errors will return CC as open */ - *cc1 = TYPEC_CC_VOLT_OPEN; - *cc2 = TYPEC_CC_VOLT_OPEN; - - /* Get the ROLE CONTROL and CC STATUS values */ - rv = tcpc_read(port, TCPC_REG_ROLE_CTRL, &role); - if (rv) - return rv; - - rv = tcpc_read(port, TCPC_REG_CC_STATUS, &status); - if (rv) - return rv; - - /* Get the current CC values from the CC STATUS */ - *cc1 = TCPC_REG_CC_STATUS_CC1(status); - *cc2 = TCPC_REG_CC_STATUS_CC2(status); - - /* Determine if we are presenting Rd */ - cc1_present_rd = 0; - cc2_present_rd = 0; - if (role & TCPC_REG_ROLE_CTRL_DRP_MASK) { - /* - * We are doing DRP. We will use the CC STATUS - * ConnectResult to determine if we are presenting - * Rd or Rp. - */ - int term; - - term = TCPC_REG_CC_STATUS_TERM(status); - - if (*cc1 != TYPEC_CC_VOLT_OPEN) - cc1_present_rd = term; - if (*cc2 != TYPEC_CC_VOLT_OPEN) - cc2_present_rd = term; - } else { - /* - * We are not doing DRP. We will use the ROLE CONTROL - * CC values to determine if we are presenting Rd or Rp. - */ - int role_cc1, role_cc2; - - role_cc1 = TCPC_REG_ROLE_CTRL_CC1(role); - role_cc2 = TCPC_REG_ROLE_CTRL_CC2(role); - - if (*cc1 != TYPEC_CC_VOLT_OPEN) - cc1_present_rd = !!(role_cc1 == TYPEC_CC_RD); - if (*cc2 != TYPEC_CC_VOLT_OPEN) - cc2_present_rd = !!(role_cc2 == TYPEC_CC_RD); - } - *cc1 |= cc1_present_rd << 2; - *cc2 |= cc2_present_rd << 2; - - if (IS_ENABLED(DEBUG_GET_CC) && - (last_get_cc[port].cc1 != *cc1 || - last_get_cc[port].cc2 != *cc2 || - last_get_cc[port].cc_sts != status || - last_get_cc[port].role != role)) { - - CPRINTS("C%d: GET_CC cc1=%d cc2=%d cc_sts=0x%X role=0x%X", - port, *cc1, *cc2, status, role); - - last_get_cc[port].cc1 = *cc1; - last_get_cc[port].cc2 = *cc2; - last_get_cc[port].cc_sts = status; - last_get_cc[port].role = role; - } - return rv; -} - -int tcpci_tcpm_set_cc(int port, int pull) -{ - int role = TCPC_REG_ROLE_CTRL_SET(TYPEC_NO_DRP, - tcpci_get_cached_rp(port), - pull, pull); - - if (IS_ENABLED(DEBUG_ROLE_CTRL_UPDATES)) - CPRINTS("C%d: SET_CC pull=%d role=0x%X", port, pull, role); - - return tcpc_write(port, TCPC_REG_ROLE_CTRL, role); -} - -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE -int tcpci_set_role_ctrl(int port, enum tcpc_drp drp, enum tcpc_rp_value rp, - enum tcpc_cc_pull pull) -{ - int role = TCPC_REG_ROLE_CTRL_SET(drp, rp, pull, pull); - - if (IS_ENABLED(DEBUG_ROLE_CTRL_UPDATES)) - CPRINTS("C%d: SET_ROLE_CTRL drp=%d rp=%d pull=%d role=0x%X", - port, drp, rp, pull, role); - - return tcpc_write(port, TCPC_REG_ROLE_CTRL, role); -} - -int tcpci_tcpc_drp_toggle(int port) -{ - int rv; - enum tcpc_cc_pull pull; - - /* - * Set auto drp toggle - * - * Set RC.DRP=1b (DRP) - * Set RC.RpValue=00b (smallest Rp to save power) - * Set RC.CC1=(Rp) or (Rd) - * Set RC.CC2=(Rp) or (Rd) - * - * TCPCI r1 wants both lines to be set to Rd - * TCPCI r2 wants both lines to be set to Rp - * - * Set the Rp Value to be the minimal to save power - */ - pull = (tcpc_config[port].flags & TCPC_FLAGS_TCPCI_REV2_0) - ? TYPEC_CC_RP : TYPEC_CC_RD; - - rv = tcpci_set_role_ctrl(port, TYPEC_DRP, TYPEC_RP_USB, pull); - if (rv) - return rv; - - /* Set up to catch LOOK4CONNECTION alerts */ - rv = tcpc_update8(port, - TCPC_REG_TCPC_CTRL, - TCPC_REG_TCPC_CTRL_EN_LOOK4CONNECTION_ALERT, - MASK_SET); - if (rv) - return rv; - - /* Set Look4Connection command */ - rv = tcpc_write(port, TCPC_REG_COMMAND, - TCPC_REG_COMMAND_LOOK4CONNECTION); - - return rv; -} -#endif - -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER -int tcpci_enter_low_power_mode(int port) -{ - return tcpc_write(port, TCPC_REG_COMMAND, TCPC_REG_COMMAND_I2CIDLE); -} -#endif - -int tcpci_tcpm_set_polarity(int port, enum tcpc_cc_polarity polarity) -{ - return tcpc_update8(port, - TCPC_REG_TCPC_CTRL, - TCPC_REG_TCPC_CTRL_SET(1), - polarity_rm_dts(polarity) - ? MASK_SET : MASK_CLR); -} - -#ifdef CONFIG_USB_PD_PPC -bool tcpci_tcpm_get_snk_ctrl(int port) -{ - int rv; - int pwr_sts; - - rv = tcpci_tcpm_get_power_status(port, &pwr_sts); - - return rv == EC_SUCCESS && - pwr_sts & TCPC_REG_POWER_STATUS_SINKING_VBUS; -} - -int tcpci_tcpm_set_snk_ctrl(int port, int enable) -{ - int cmd = enable ? TCPC_REG_COMMAND_SNK_CTRL_HIGH : - TCPC_REG_COMMAND_SNK_CTRL_LOW; - - return tcpc_write(port, TCPC_REG_COMMAND, cmd); -} - -bool tcpci_tcpm_get_src_ctrl(int port) -{ - int rv; - int pwr_sts; - - rv = tcpci_tcpm_get_power_status(port, &pwr_sts); - - return rv == EC_SUCCESS && - pwr_sts & TCPC_REG_POWER_STATUS_SOURCING_VBUS; -} - -int tcpci_tcpm_set_src_ctrl(int port, int enable) -{ - int cmd = enable ? TCPC_REG_COMMAND_SRC_CTRL_HIGH : - TCPC_REG_COMMAND_SRC_CTRL_LOW; - - return tcpc_write(port, TCPC_REG_COMMAND, cmd); -} -#endif - -__maybe_unused int tcpci_tcpm_sop_prime_enable(int port, bool enable) -{ - /* save SOP'/SOP'' enable state */ - sop_prime_en[port] = enable; - - if (rx_en[port]) { - int detect_sop_en = TCPC_REG_RX_DETECT_SOP_HRST_MASK; - - if (enable) { - detect_sop_en = - TCPC_REG_RX_DETECT_SOP_SOPP_SOPPP_HRST_MASK; - } - - return tcpc_write(port, TCPC_REG_RX_DETECT, detect_sop_en); - } - - return EC_SUCCESS; -} - -int tcpci_tcpm_set_vconn(int port, int enable) -{ - int reg, rv; - - rv = tcpc_read(port, TCPC_REG_POWER_CTRL, ®); - if (rv) - return rv; - - reg &= ~TCPC_REG_POWER_CTRL_VCONN(1); - reg |= TCPC_REG_POWER_CTRL_VCONN(enable); - - /* - * Add delay of writing TCPC_REG_POWER_CTRL makes - * CC status being judged correctly when disable VCONN. - * This may be a PS8XXX firmware issue, Parade is still trying. - * https://partnerissuetracker.corp.google.com/issues/185202064 - */ - if (!enable) - msleep(PS8XXX_VCONN_TURN_OFF_DELAY_US); - - return tcpc_write(port, TCPC_REG_POWER_CTRL, reg); -} - -int tcpci_tcpm_set_msg_header(int port, int power_role, int data_role) -{ - return tcpc_write(port, TCPC_REG_MSG_HDR_INFO, - TCPC_REG_MSG_HDR_INFO_SET(data_role, power_role)); -} - -static int tcpm_alert_status(int port, int *alert) -{ - /* Read TCPC Alert register */ - return tcpc_read16(port, TCPC_REG_ALERT, alert); -} - -static int tcpm_alert_ext_status(int port, int *alert_ext) -{ - /* Read TCPC Extended Alert register */ - return tcpc_read(port, TCPC_REG_ALERT_EXT, alert_ext); -} - -static int tcpm_ext_status(int port, int *ext_status) -{ - /* Read TCPC Extended Status register */ - return tcpc_read(port, TCPC_REG_EXT_STATUS, ext_status); -} - -int tcpci_tcpm_set_rx_enable(int port, int enable) -{ - int detect_sop_en = 0; - - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) { - /* save rx_on */ - rx_en[port] = enable; - } - - - if (enable) { - detect_sop_en = TCPC_REG_RX_DETECT_SOP_HRST_MASK; - - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP) && - sop_prime_en[port]) { - /* - * Only the VCONN Source is allowed to communicate - * with the Cable Plugs. - */ - detect_sop_en = - TCPC_REG_RX_DETECT_SOP_SOPP_SOPPP_HRST_MASK; - } - } - - /* If enable, then set RX detect for SOP and HRST */ - return tcpc_write(port, TCPC_REG_RX_DETECT, detect_sop_en); -} - -#ifdef CONFIG_USB_PD_FRS_TCPC -int tcpci_tcpc_fast_role_swap_enable(int port, int enable) -{ - return tcpc_update8(port, - TCPC_REG_POWER_CTRL, - TCPC_REG_POWER_CTRL_FRS_ENABLE, - (enable) ? MASK_SET : MASK_CLR); -} -#endif - -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC -bool tcpci_tcpm_check_vbus_level(int port, enum vbus_level level) -{ - if (level == VBUS_SAFE0V) - return !!(tcpc_vbus[port] & BIT(VBUS_SAFE0V)); - else if (level == VBUS_PRESENT) - return !!(tcpc_vbus[port] & BIT(VBUS_PRESENT)); - else - return !(tcpc_vbus[port] & BIT(VBUS_PRESENT)); -} -#endif - -struct cached_tcpm_message { - uint32_t header; - uint32_t payload[7]; -}; - -static int tcpci_rev2_0_tcpm_get_message_raw(int port, uint32_t *payload, - int *head) -{ - int rv = 0, cnt, reg = TCPC_REG_RX_BUFFER; - int frm; - uint8_t tmp[2]; - /* - * Register 0x30 is Readable Byte Count, Buffer frame type, and RX buf - * byte X. - */ - tcpc_lock(port, 1); - rv = tcpc_xfer_unlocked(port, (uint8_t *)®, 1, tmp, 2, - I2C_XFER_START); - if (rv) { - rv = EC_ERROR_UNKNOWN; - goto clear; - } - cnt = tmp[0]; - frm = tmp[1]; - - /* - * READABLE_BYTE_COUNT includes 3 bytes for frame type and header, and - * may be 0 if the TCPC saw a disconnect before the message read - */ - cnt -= 3; - if ((cnt < 0) || - (cnt > member_size(struct cached_tcpm_message, payload))) { - /* Continue to send the stop bit with the header read */ - rv = EC_ERROR_UNKNOWN; - cnt = 0; - } - - /* The next two bytes are the header */ - rv |= tcpc_xfer_unlocked(port, NULL, 0, (uint8_t *)head, 2, - cnt ? 0 : I2C_XFER_STOP); - - /* Encode message address in bits 31 to 28 */ - *head &= 0x0000ffff; - *head |= PD_HEADER_SOP(frm); - - /* Execute read and I2C_XFER_STOP, even if header read failed */ - if (cnt > 0) { - tcpc_xfer_unlocked(port, NULL, 0, (uint8_t *)payload, cnt, - I2C_XFER_STOP); - } - -clear: - tcpc_lock(port, 0); - /* Read complete, clear RX status alert bit */ - tcpc_write16(port, TCPC_REG_ALERT, TCPC_REG_ALERT_RX_STATUS); - - if (rv) - return EC_ERROR_UNKNOWN; - - return EC_SUCCESS; -} - -static int tcpci_rev1_0_tcpm_get_message_raw(int port, uint32_t *payload, - int *head) -{ - int rv, cnt, reg = TCPC_REG_RX_DATA; - int frm; - - rv = tcpc_read(port, TCPC_REG_RX_BYTE_CNT, &cnt); - - /* RX_BYTE_CNT includes 3 bytes for frame type and header */ - if (rv != EC_SUCCESS || cnt < 3) { - rv = EC_ERROR_UNKNOWN; - goto clear; - } - cnt -= 3; - if (cnt > member_size(struct cached_tcpm_message, payload)) { - rv = EC_ERROR_UNKNOWN; - goto clear; - } - - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) { - rv = tcpc_read(port, TCPC_REG_RX_BUF_FRAME_TYPE, &frm); - if (rv != EC_SUCCESS) { - rv = EC_ERROR_UNKNOWN; - goto clear; - } - } - - rv = tcpc_read16(port, TCPC_REG_RX_HDR, (int *)head); - - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) { - /* Encode message address in bits 31 to 28 */ - *head &= 0x0000ffff; - *head |= PD_HEADER_SOP(frm); - } - - if (rv == EC_SUCCESS && cnt > 0) { - tcpc_read_block(port, reg, (uint8_t *)payload, cnt); - } - -clear: - /* Read complete, clear RX status alert bit */ - tcpc_write16(port, TCPC_REG_ALERT, TCPC_REG_ALERT_RX_STATUS); - - return rv; -} - -int tcpci_tcpm_get_message_raw(int port, uint32_t *payload, int *head) -{ - if (tcpc_config[port].flags & TCPC_FLAGS_TCPCI_REV2_0) - return tcpci_rev2_0_tcpm_get_message_raw(port, payload, head); - - return tcpci_rev1_0_tcpm_get_message_raw(port, payload, head); -} - -/* Cache depth needs to be power of 2 */ -/* TODO: Keep track of the high water mark */ -#define CACHE_DEPTH BIT(3) -#define CACHE_DEPTH_MASK (CACHE_DEPTH - 1) - -struct queue { - /* - * Head points to the index of the first empty slot to put a new RX - * message. Must be masked before used in lookup. - */ - uint32_t head; - /* - * Tail points to the index of the first message for the PD task to - * consume. Must be masked before used in lookup. - */ - uint32_t tail; - struct cached_tcpm_message buffer[CACHE_DEPTH]; -}; -static struct queue cached_messages[CONFIG_USB_PD_PORT_MAX_COUNT]; - -/* Note this method can be called from an interrupt context. */ -int tcpm_enqueue_message(const int port) -{ - int rv; - struct queue *const q = &cached_messages[port]; - struct cached_tcpm_message *const head = - &q->buffer[q->head & CACHE_DEPTH_MASK]; - - if (q->head - q->tail == CACHE_DEPTH) { - CPRINTS("C%d RX EC Buffer full!", port); - return EC_ERROR_OVERFLOW; - } - - /* Blank any old message, just in case. */ - memset(head, 0, sizeof(*head)); - /* Call the raw driver without caching */ - rv = tcpc_config[port].drv->get_message_raw(port, head->payload, - &head->header); - if (rv) { - CPRINTS("C%d: Could not retrieve RX message (%d)", port, rv); - return rv; - } - - /* Increment atomically to ensure get_message_raw happens-before */ - atomic_add(&q->head, 1); - - /* Wake PD task up so it can process incoming RX messages */ - task_set_event(PD_PORT_TO_TASK_ID(port), TASK_EVENT_WAKE); - - return EC_SUCCESS; -} - -int tcpm_has_pending_message(const int port) -{ - const struct queue *const q = &cached_messages[port]; - - return q->head != q->tail; -} - -int tcpm_dequeue_message(const int port, uint32_t *const payload, - int *const header) -{ - struct queue *const q = &cached_messages[port]; - struct cached_tcpm_message *const tail = - &q->buffer[q->tail & CACHE_DEPTH_MASK]; - - if (!tcpm_has_pending_message(port)) { - CPRINTS("C%d No message in RX buffer!", port); - return EC_ERROR_BUSY; - } - - /* Copy cache data in to parameters */ - *header = tail->header; - memcpy(payload, tail->payload, sizeof(tail->payload)); - - /* Increment atomically to ensure memcpy happens-before */ - atomic_add(&q->tail, 1); - - return EC_SUCCESS; -} - -void tcpm_clear_pending_messages(int port) -{ - struct queue *const q = &cached_messages[port]; - - q->tail = q->head; -} - -int tcpci_tcpm_transmit(int port, enum tcpci_msg_type type, - uint16_t header, const uint32_t *data) -{ - int reg = TCPC_REG_TX_DATA; - int rv, cnt = 4*PD_HEADER_CNT(header); - - /* If not SOP* transmission, just write to the transmit register */ - if (type >= NUM_SOP_STAR_TYPES) { - /* - * Per TCPCI spec, do not specify retry (although the TCPC - * should ignore retry field for these 3 types). - */ - return tcpc_write(port, TCPC_REG_TRANSMIT, - TCPC_REG_TRANSMIT_SET_WITHOUT_RETRY(type)); - } - - if (tcpc_config[port].flags & TCPC_FLAGS_TCPCI_REV2_0) { - /* - * In TCPCI Rev 2.0, TX_BYTE_CNT and TX_BUF_BYTE_X are the same - * register. - */ - reg = TCPC_REG_TX_BUFFER; - /* TX_BYTE_CNT includes extra bytes for message header */ - cnt += sizeof(header); - tcpc_lock(port, 1); - rv = tcpc_xfer_unlocked(port, (uint8_t *)®, 1, NULL, 0, - I2C_XFER_START); - rv |= tcpc_xfer_unlocked(port, (uint8_t *)&cnt, 1, NULL, 0, 0); - if (cnt > sizeof(header)) { - rv |= tcpc_xfer_unlocked(port, (uint8_t *)&header, - sizeof(header), NULL, 0, 0); - rv |= tcpc_xfer_unlocked(port, (uint8_t *)data, - cnt-sizeof(header), NULL, 0, - I2C_XFER_STOP); - } else { - rv |= tcpc_xfer_unlocked(port, (uint8_t *)&header, - sizeof(header), NULL, 0, I2C_XFER_STOP); - } - tcpc_lock(port, 0); - - /* If tcpc write fails, return error */ - if (rv) - return rv; - } else { - /* TX_BYTE_CNT includes extra bytes for message header */ - rv = tcpc_write(port, TCPC_REG_TX_BYTE_CNT, - cnt + sizeof(header)); - - rv |= tcpc_write16(port, TCPC_REG_TX_HDR, header); - - /* If tcpc write fails, return error */ - if (rv) - return rv; - - if (cnt > 0) { - rv = tcpc_write_block(port, reg, (const uint8_t *)data, - cnt); - - /* If tcpc write fails, return error */ - if (rv) - return rv; - } - } - - /* - * We always retry in TCPC hardware since the TCPM is too slow to - * respond within tRetry (~195 usec). - * - * The retry count used is dependent on the maximum PD revision - * supported at build time. - */ - return tcpc_write(port, TCPC_REG_TRANSMIT, - TCPC_REG_TRANSMIT_SET_WITH_RETRY( - pd_get_retry_count(port, type), type)); -} - -/* - * Returns true if TCPC has reset based on reading mask registers. - */ -static int register_mask_reset(int port) -{ - int mask; - - mask = 0; - tcpc_read16(port, TCPC_REG_ALERT_MASK, &mask); - if (mask == TCPC_REG_ALERT_MASK_ALL) - return 1; - - mask = 0; - tcpc_read(port, TCPC_REG_POWER_STATUS_MASK, &mask); - if (mask == TCPC_REG_POWER_STATUS_MASK_ALL) - return 1; - - return 0; -} - -static int tcpci_get_fault(int port, int *fault) -{ - return tcpc_read(port, TCPC_REG_FAULT_STATUS, fault); -} - -static int tcpci_handle_fault(int port, int fault) -{ - int rv = EC_SUCCESS; - - CPRINTS("C%d FAULT 0x%02X detected", port, fault); - - if (IS_ENABLED(DEBUG_I2C_FAULT_LAST_WRITE_OP) && - fault & TCPC_REG_FAULT_STATUS_I2C_INTERFACE_ERR) { - if (last_write_op[port].mask == 0) - CPRINTS("C%d I2C WR 0x%02X 0x%02X value=0x%X", - port, - last_write_op[port].addr, - last_write_op[port].reg, - last_write_op[port].val); - else - CPRINTS("C%d I2C UP 0x%02X 0x%02X op=%d mask=0x%X", - port, - last_write_op[port].addr, - last_write_op[port].reg, - last_write_op[port].mask >> 16, - last_write_op[port].mask & 0xFFFF); - } - - /* Report overcurrent to the OCP module if enabled */ - if ((dev_cap_1[port] & TCPC_REG_DEV_CAP_1_VBUS_OCP_REPORTING) && - IS_ENABLED(CONFIG_USBC_OCP) && - (fault & TCPC_REG_FAULT_STATUS_VBUS_OVER_CURRENT)) - pd_handle_overcurrent(port); - - if (tcpc_config[port].drv->handle_fault) - rv = tcpc_config[port].drv->handle_fault(port, fault); - - return rv; -} - -enum ec_error_list tcpci_set_bist_test_mode(const int port, - const bool enable) -{ - int rv; - - rv = tcpc_update8(port, TCPC_REG_TCPC_CTRL, - TCPC_REG_TCPC_CTRL_BIST_TEST_MODE, - enable ? MASK_SET : MASK_CLR); - rv |= tcpc_update16(port, TCPC_REG_ALERT_MASK, - TCPC_REG_ALERT_RX_STATUS, enable ? MASK_CLR : MASK_SET); - return rv; -} - -static int tcpci_clear_fault(int port, int fault) -{ - int rv; - - rv = tcpc_write(port, TCPC_REG_FAULT_STATUS, fault); - if (rv) - return rv; - - return tcpc_write16(port, TCPC_REG_ALERT, TCPC_REG_ALERT_FAULT); -} - -static void tcpci_check_vbus_changed(int port, int alert, uint32_t *pd_event) -{ - /* - * Check for VBus change - */ - /* TCPCI Rev2 includes Safe0V detection */ - if (TCPC_FLAGS_VSAFE0V(tcpc_config[port].flags) && - (alert & TCPC_REG_ALERT_EXT_STATUS)) { - int ext_status = 0; - - /* Determine if Safe0V was detected */ - tcpm_ext_status(port, &ext_status); - if (ext_status & TCPC_REG_EXT_STATUS_SAFE0V) - /* Safe0V=1 and Present=0 */ - tcpc_vbus[port] = BIT(VBUS_SAFE0V); - } - - if (alert & TCPC_REG_ALERT_POWER_STATUS) { - int pwr_status = 0; - - /* Determine reason for power status change */ - tcpci_tcpm_get_power_status(port, &pwr_status); - if (pwr_status & TCPC_REG_POWER_STATUS_VBUS_PRES) - /* Safe0V=0 and Present=1 */ - tcpc_vbus[port] = BIT(VBUS_PRESENT); - else if (TCPC_FLAGS_VSAFE0V(tcpc_config[port].flags)) - /* TCPCI Rev2 detects Safe0V, so Present=0 */ - tcpc_vbus[port] &= ~BIT(VBUS_PRESENT); - else { - /* - * TCPCI Rev1 can not detect Safe0V, so treat this - * like a Safe0V detection. - * - * Safe0V=1 and Present=0 - */ - tcpc_vbus[port] = BIT(VBUS_SAFE0V); - } - - if ((get_usb_pd_vbus_detect() == USB_PD_VBUS_DETECT_TCPC) && - IS_ENABLED(CONFIG_USB_CHARGER)) { - /* Update charge manager with new VBUS state */ - usb_charger_vbus_change(port, - !!(tcpc_vbus[port] & BIT(VBUS_PRESENT))); - - if (pd_event) - *pd_event |= TASK_EVENT_WAKE; - } - } -} - -/* - * Don't let the TCPC try to pull from the RX buffer forever. We typical only - * have 1 or 2 messages waiting. - */ -#define MAX_ALLOW_FAILED_RX_READS 10 - -void tcpci_tcpc_alert(int port) -{ - int alert = 0; - int alert_ext = 0; - int failed_attempts; - uint32_t pd_event = 0; - int retval = 0; - - /* Read the Alert register from the TCPC */ - if (tcpm_alert_status(port, &alert)) { - CPRINTS("C%d: Failed to read alert register", port); - return; - } - - /* Get Extended Alert register if needed */ - if (alert & TCPC_REG_ALERT_ALERT_EXT) - tcpm_alert_ext_status(port, &alert_ext); - - /* Clear any pending faults */ - if (alert & TCPC_REG_ALERT_FAULT) { - int fault; - - if (tcpci_get_fault(port, &fault) == EC_SUCCESS && - fault != 0 && - tcpci_handle_fault(port, fault) == EC_SUCCESS && - tcpci_clear_fault(port, fault) == EC_SUCCESS) - CPRINTS("C%d FAULT 0x%02X handled", port, fault); - } - - /* - * Check for TX complete first b/c PD state machine waits on TX - * completion events. This will send an event to the PD tasks - * immediately - */ - if (alert & TCPC_REG_ALERT_TX_COMPLETE) - pd_transmit_complete(port, alert & TCPC_REG_ALERT_TX_SUCCESS ? - TCPC_TX_COMPLETE_SUCCESS : - TCPC_TX_COMPLETE_FAILED); - - /* Pull all RX messages from TCPC into EC memory */ - failed_attempts = 0; - while (alert & TCPC_REG_ALERT_RX_STATUS) { - retval = tcpm_enqueue_message(port); - if (retval) - ++failed_attempts; - if (tcpm_alert_status(port, &alert)) - ++failed_attempts; - - - /* - * EC RX FIFO is full. Deassert ALERT# line to exit interrupt - * handler by discarding pending message from TCPC RX FIFO. - */ - if (retval == EC_ERROR_OVERFLOW) { - CPRINTS("C%d: PD RX OVF!", port); - tcpc_write16(port, TCPC_REG_ALERT, - TCPC_REG_ALERT_RX_STATUS | - TCPC_REG_ALERT_RX_BUF_OVF); - } - - /* Ensure we don't loop endlessly */ - if (failed_attempts >= MAX_ALLOW_FAILED_RX_READS) { - CPRINTS("C%d Cannot consume RX buffer after %d failed attempts!", - port, failed_attempts); - /* - * The port is in a bad state, we don't want to consume - * all EC resources so suspend the port for a little - * while. - */ - pd_set_suspend(port, 1); - pd_deferred_resume(port); - return; - } - } - - /* - * Clear all pending alert bits. Ext first because ALERT.AlertExtended - * is set if any bit of ALERT_EXTENDED is set. - */ - if (alert_ext) - tcpc_write(port, TCPC_REG_ALERT_EXT, alert_ext); - if (alert) - tcpc_write16(port, TCPC_REG_ALERT, alert); - - if (alert & TCPC_REG_ALERT_CC_STATUS) { - if (IS_ENABLED(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE)) { - enum tcpc_cc_voltage_status cc1; - enum tcpc_cc_voltage_status cc2; - - /* - * Some TCPCs generate CC Alerts when - * drp auto toggle is active and nothing - * is connected to the port. So, get the - * CC line status and only generate a - * PD_EVENT_CC if something is connected. - */ - tcpci_tcpm_get_cc(port, &cc1, &cc2); - if (cc1 != TYPEC_CC_VOLT_OPEN || - cc2 != TYPEC_CC_VOLT_OPEN) - /* CC status cchanged, wake task */ - pd_event |= PD_EVENT_CC; - } else { - /* CC status changed, wake task */ - pd_event |= PD_EVENT_CC; - } - } - - tcpci_check_vbus_changed(port, alert, &pd_event); - - /* Check for Hard Reset received */ - if (alert & TCPC_REG_ALERT_RX_HARD_RST) { - /* hard reset received */ - CPRINTS("C%d Hard Reset received", port); - pd_event |= PD_EVENT_RX_HARD_RESET; - } - - /* USB TCPCI Spec R2 V1.1 Section 4.7.3 Step 2 - * - * The TCPC asserts both ALERT.TransmitSOP*MessageSuccessful and - * ALERT.TransmitSOP*MessageFailed regardless of the outcome of the - * transmission and asserts the Alert# pin. - */ - if (alert & TCPC_REG_ALERT_TX_SUCCESS && - alert & TCPC_REG_ALERT_TX_FAILED) - CPRINTS("C%d Hard Reset sent", port); - - if (IS_ENABLED(CONFIG_USB_PD_FRS_TCPC) - && (alert_ext & TCPC_REG_ALERT_EXT_SNK_FRS)) - pd_got_frs_signal(port); - - /* - * Check registers to see if we can tell that the TCPC has reset. If - * so, perform a tcpc_init. - */ - if (register_mask_reset(port)) - pd_event |= PD_EVENT_TCPC_RESET; - - /* - * Wait until all possible TCPC accesses in this function are complete - * prior to setting events and/or waking the pd task. When the PD - * task is woken and runs (which will happen during I2C transactions in - * this function), the pd task may put the TCPC into low power mode and - * the next I2C transaction to the TCPC will cause it to wake again. - */ - if (pd_event) - task_set_event(PD_PORT_TO_TASK_ID(port), pd_event); -} - -/* - * This call will wake up the TCPC if it is in low power mode upon accessing the - * i2c bus (but the pd state machine should put it back into low power mode). - * - * Once it's called, the chip info will be stored in cache, which can be - * accessed by tcpm_get_chip_info without worrying about chip states. - */ -int tcpci_get_chip_info(int port, int live, - struct ec_response_pd_chip_info_v1 *chip_info) -{ - static struct ec_response_pd_chip_info_v1 - cached_info[CONFIG_USB_PD_PORT_MAX_COUNT]; - struct ec_response_pd_chip_info_v1 *i; - int error; - int val; - - if (port >= board_get_usb_pd_port_count()) - return EC_ERROR_INVAL; - - i = &cached_info[port]; - - - /* If already cached && live data is not asked, return cached value */ - if (i->vendor_id && !live) { - /* - * If chip_info is NULL, chip info will be stored in cache and - * can be read later by another call. - */ - if (chip_info) - memcpy(chip_info, i, sizeof(*i)); - - return EC_SUCCESS; - } - - error = tcpc_read16(port, TCPC_REG_VENDOR_ID, &val); - if (error) - return error; - i->vendor_id = val; - - error = tcpc_read16(port, TCPC_REG_PRODUCT_ID, &val); - if (error) - return error; - i->product_id = val; - - error = tcpc_read16(port, TCPC_REG_BCD_DEV, &val); - if (error) - return error; - i->device_id = val; - - /* - * This varies chip to chip; more specific driver code is expected to - * override this value if it can. - */ - i->fw_version_number = -1; - - /* Copy the cached value to return if chip_info is not NULL */ - if (chip_info) - memcpy(chip_info, i, sizeof(*i)); - - return EC_SUCCESS; -} - -/* - * Dissociate from the TCPC. - */ - -int tcpci_tcpm_release(int port) -{ - int error; - - error = clear_alert_mask(port); - if (error) - return error; - error = clear_power_status_mask(port); - if (error) - return error; - /* Clear pending interrupts */ - error = tcpc_write16(port, TCPC_REG_ALERT, 0xffff); - if (error) - return error; - - return EC_SUCCESS; -} - -/* - * On TCPC i2c failure, make 30 tries (at least 300ms) before giving up - * in order to allow the TCPC time to boot / reset. - */ -#define TCPM_INIT_TRIES 30 - -int tcpci_tcpm_init(int port) -{ - int error; - int power_status; - int tries = TCPM_INIT_TRIES; - - if (port >= board_get_usb_pd_port_count()) - return EC_ERROR_INVAL; - - while (1) { - error = tcpci_tcpm_get_power_status(port, &power_status); - /* - * If read succeeds and the uninitialized bit is clear, then - * initialization is complete, clear all alert bits and write - * the initial alert mask. - */ - if (!error && !(power_status & TCPC_REG_POWER_STATUS_UNINIT)) - break; - if (--tries <= 0) - return error ? error : EC_ERROR_TIMEOUT; - msleep(10); - } - - /* - * For TCPCI Rev 2.0, unless the TCPM sets - * TCPC_CONTROL.EnableLooking4ConnectionAlert bit, TCPC by default masks - * Alert assertion when CC_STATUS.Looking4Connection changes state. - */ - if (tcpc_config[port].flags & TCPC_FLAGS_TCPCI_REV2_0) { - error = tcpc_update8(port, TCPC_REG_TCPC_CTRL, - TCPC_REG_TCPC_CTRL_EN_LOOK4CONNECTION_ALERT, - MASK_SET); - if (error) - CPRINTS("C%d: Failed to init TCPC_CTRL!", port); - } - - /* - * Handle and clear any alerts, since we might be coming out of low - * power mode in response to an alert interrupt from the TCPC. - */ - tcpc_alert(port); - /* Initialize power_status_mask */ - init_power_status_mask(port); - - if (TCPC_FLAGS_VSAFE0V(tcpc_config[port].flags)) { - int ext_status = 0; - - /* Read Extended Status register */ - tcpm_ext_status(port, &ext_status); - /* Initial level, set appropriately */ - if (power_status & TCPC_REG_POWER_STATUS_VBUS_PRES) - tcpc_vbus[port] = BIT(VBUS_PRESENT); - else if (ext_status & TCPC_REG_EXT_STATUS_SAFE0V) - tcpc_vbus[port] = BIT(VBUS_SAFE0V); - else - tcpc_vbus[port] = 0; - } else { - /* Initial level, set appropriately */ - tcpc_vbus[port] = (power_status & - TCPC_REG_POWER_STATUS_VBUS_PRES) - ? BIT(VBUS_PRESENT) - : BIT(VBUS_SAFE0V); - } - - /* - * Force an update to the VBUS status in case the TCPC doesn't send a - * power status changed interrupt later. - */ - tcpci_check_vbus_changed(port, - TCPC_REG_ALERT_POWER_STATUS | TCPC_REG_ALERT_EXT_STATUS, - NULL); - - error = init_alert_mask(port); - if (error) - return error; - - /* Read chip info here when we know the chip is awake. */ - tcpm_get_chip_info(port, 1, NULL); - - /* Cache our device capabilities for future reference */ - tcpc_read16(port, TCPC_REG_DEV_CAP_1, &dev_cap_1[port]); - - return EC_SUCCESS; -} - -#ifdef CONFIG_USB_PD_TCPM_MUX - -/* - * When the TCPC/MUX device is only used for the MUX, we need to initialize it - * via mux init because tcpc_init won't run for the device. This is borrowed - * from tcpc_init. - */ -int tcpci_tcpm_mux_init(const struct usb_mux *me) -{ - int error; - int power_status; - int tries = TCPM_INIT_TRIES; - - /* If this MUX is also the TCPC, then skip init */ - if (!(me->flags & USB_MUX_FLAG_NOT_TCPC)) - return EC_SUCCESS; - - /* Wait for the device to exit low power state */ - while (1) { - error = mux_read(me, TCPC_REG_POWER_STATUS, &power_status); - /* - * If read succeeds and the uninitialized bit is clear, then - * initialization is complete. - */ - if (!error && !(power_status & TCPC_REG_POWER_STATUS_UNINIT)) - break; - if (--tries <= 0) - return error ? error : EC_ERROR_TIMEOUT; - msleep(10); - } - - /* Turn off all alerts and acknowledge any pending IRQ */ - error = mux_write16(me, TCPC_REG_ALERT_MASK, 0); - error |= mux_write16(me, TCPC_REG_ALERT, 0xffff); - - return error ? EC_ERROR_UNKNOWN : EC_SUCCESS; -} - -int tcpci_tcpm_mux_enter_low_power(const struct usb_mux *me) -{ - /* If this MUX is also the TCPC, then skip low power */ - if (!(me->flags & USB_MUX_FLAG_NOT_TCPC)) - return EC_SUCCESS; - - return mux_write(me, TCPC_REG_COMMAND, TCPC_REG_COMMAND_I2CIDLE); -} - -int tcpci_tcpm_mux_set(const struct usb_mux *me, mux_state_t mux_state, - bool *ack_required) -{ - int rv; - int reg = 0; - - /* This driver does not use host command ACKs */ - *ack_required = false; - - /* Parameter is port only */ - rv = mux_read(me, TCPC_REG_CONFIG_STD_OUTPUT, ®); - if (rv != EC_SUCCESS) - return rv; - - reg &= ~(TCPC_REG_CONFIG_STD_OUTPUT_MUX_MASK | - TCPC_REG_CONFIG_STD_OUTPUT_CONNECTOR_FLIPPED); - if (mux_state & USB_PD_MUX_USB_ENABLED) - reg |= TCPC_REG_CONFIG_STD_OUTPUT_MUX_USB; - if (mux_state & USB_PD_MUX_DP_ENABLED) - reg |= TCPC_REG_CONFIG_STD_OUTPUT_MUX_DP; - if (mux_state & USB_PD_MUX_POLARITY_INVERTED) - reg |= TCPC_REG_CONFIG_STD_OUTPUT_CONNECTOR_FLIPPED; - - /* Parameter is port only */ - return mux_write(me, TCPC_REG_CONFIG_STD_OUTPUT, reg); -} - -/* Reads control register and updates mux_state accordingly */ -int tcpci_tcpm_mux_get(const struct usb_mux *me, mux_state_t *mux_state) -{ - int rv; - int reg = 0; - - *mux_state = 0; - - /* Parameter is port only */ - rv = mux_read(me, TCPC_REG_CONFIG_STD_OUTPUT, ®); - if (rv != EC_SUCCESS) - return rv; - - if (reg & TCPC_REG_CONFIG_STD_OUTPUT_MUX_USB) - *mux_state |= USB_PD_MUX_USB_ENABLED; - if (reg & TCPC_REG_CONFIG_STD_OUTPUT_MUX_DP) - *mux_state |= USB_PD_MUX_DP_ENABLED; - if (reg & TCPC_REG_CONFIG_STD_OUTPUT_CONNECTOR_FLIPPED) - *mux_state |= USB_PD_MUX_POLARITY_INVERTED; - - return EC_SUCCESS; -} - -const struct usb_mux_driver tcpci_tcpm_usb_mux_driver = { - .init = &tcpci_tcpm_mux_init, - .set = &tcpci_tcpm_mux_set, - .get = &tcpci_tcpm_mux_get, - .enter_low_power_mode = &tcpci_tcpm_mux_enter_low_power, -}; - -#endif /* CONFIG_USB_PD_TCPM_MUX */ - -#ifdef CONFIG_CMD_TCPC_DUMP -static const struct tcpc_reg_dump_map tcpc_regs[] = { - { - .addr = TCPC_REG_VENDOR_ID, - .name = "VENDOR_ID", - .size = 2, - }, - { - .addr = TCPC_REG_PRODUCT_ID, - .name = "PRODUCT_ID", - .size = 2, - }, - { - .addr = TCPC_REG_BCD_DEV, - .name = "BCD_DEV", - .size = 2, - }, - { - .addr = TCPC_REG_TC_REV, - .name = "TC_REV", - .size = 2, - }, - { - .addr = TCPC_REG_PD_REV, - .name = "PD_REV", - .size = 2, - }, - { - .addr = TCPC_REG_PD_INT_REV, - .name = "PD_INT_REV", - .size = 2, - }, - { - .addr = TCPC_REG_ALERT, - .name = "ALERT", - .size = 2, - }, - { - .addr = TCPC_REG_ALERT_MASK, - .name = "ALERT_MASK", - .size = 2, - }, - { - .addr = TCPC_REG_POWER_STATUS_MASK, - .name = "POWER_STATUS_MASK", - .size = 1, - }, - { - .addr = TCPC_REG_FAULT_STATUS_MASK, - .name = "FAULT_STATUS_MASK", - .size = 1, - }, - { - .addr = TCPC_REG_EXT_STATUS_MASK, - .name = "EXT_STATUS_MASK", - .size = 1 - }, - { - .addr = TCPC_REG_ALERT_EXTENDED_MASK, - .name = "ALERT_EXTENDED_MASK", - .size = 1, - }, - { - .addr = TCPC_REG_CONFIG_STD_OUTPUT, - .name = "CONFIG_STD_OUTPUT", - .size = 1, - }, - { - .addr = TCPC_REG_TCPC_CTRL, - .name = "TCPC_CTRL", - .size = 1, - }, - { - .addr = TCPC_REG_ROLE_CTRL, - .name = "ROLE_CTRL", - .size = 1, - }, - { - .addr = TCPC_REG_FAULT_CTRL, - .name = "FAULT_CTRL", - .size = 1, - }, - { - .addr = TCPC_REG_POWER_CTRL, - .name = "POWER_CTRL", - .size = 1, - }, - { - .addr = TCPC_REG_CC_STATUS, - .name = "CC_STATUS", - .size = 1, - }, - { - .addr = TCPC_REG_POWER_STATUS, - .name = "POWER_STATUS", - .size = 1, - }, - { - .addr = TCPC_REG_FAULT_STATUS, - .name = "FAULT_STATUS", - .size = 1, - }, - { - .addr = TCPC_REG_EXT_STATUS, - .name = "EXT_STATUS", - .size = 1, - }, - { - .addr = TCPC_REG_ALERT_EXT, - .name = "ALERT_EXT", - .size = 1, - }, - { - .addr = TCPC_REG_DEV_CAP_1, - .name = "DEV_CAP_1", - .size = 2, - }, - { - .addr = TCPC_REG_DEV_CAP_2, - .name = "DEV_CAP_2", - .size = 2, - }, - { - .addr = TCPC_REG_STD_INPUT_CAP, - .name = "STD_INPUT_CAP", - .size = 1, - }, - { - .addr = TCPC_REG_STD_OUTPUT_CAP, - .name = "STD_OUTPUT_CAP", - .size = 1, - }, - { - .addr = TCPC_REG_CONFIG_EXT_1, - .name = "CONFIG_EXT_1", - .size = 1, - }, - { - .addr = TCPC_REG_MSG_HDR_INFO, - .name = "MSG_HDR_INFO", - .size = 1, - }, - { - .addr = TCPC_REG_RX_DETECT, - .name = "RX_DETECT", - .size = 1, - }, - { - .addr = TCPC_REG_RX_BYTE_CNT, - .name = "RX_BYTE_CNT", - .size = 1, - }, - { - .addr = TCPC_REG_RX_BUF_FRAME_TYPE, - .name = "RX_BUF_FRAME_TYPE", - .size = 1, - }, - { - .addr = TCPC_REG_TRANSMIT, - .name = "TRANSMIT", - .size = 1, - }, - { - .addr = TCPC_REG_VBUS_VOLTAGE, - .name = "VBUS_VOLTAGE", - .size = 2, - }, - { - .addr = TCPC_REG_VBUS_SINK_DISCONNECT_THRESH, - .name = "VBUS_SINK_DISCONNECT_THRESH", - .size = 2, - }, - { - .addr = TCPC_REG_VBUS_STOP_DISCHARGE_THRESH, - .name = "VBUS_STOP_DISCHARGE_THRESH", - .size = 2, - }, - { - .addr = TCPC_REG_VBUS_VOLTAGE_ALARM_HI_CFG, - .name = "VBUS_VOLTAGE_ALARM_HI_CFG", - .size = 2, - }, - { - .addr = TCPC_REG_VBUS_VOLTAGE_ALARM_LO_CFG, - .name = "VBUS_VOLTAGE_ALARM_LO_CFG", - .size = 2, - }, -}; - -/* - * Dump standard TCPC registers. - */ -void tcpc_dump_std_registers(int port) -{ - tcpc_dump_registers(port, tcpc_regs, ARRAY_SIZE(tcpc_regs)); -} -#endif - -const struct tcpm_drv tcpci_tcpm_drv = { - .init = &tcpci_tcpm_init, - .release = &tcpci_tcpm_release, - .get_cc = &tcpci_tcpm_get_cc, -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - .check_vbus_level = &tcpci_tcpm_check_vbus_level, -#endif - .select_rp_value = &tcpci_tcpm_select_rp_value, - .set_cc = &tcpci_tcpm_set_cc, - .set_polarity = &tcpci_tcpm_set_polarity, -#ifdef CONFIG_USB_PD_DECODE_SOP - .sop_prime_enable = &tcpci_tcpm_sop_prime_enable, -#endif - .set_vconn = &tcpci_tcpm_set_vconn, - .set_msg_header = &tcpci_tcpm_set_msg_header, - .set_rx_enable = &tcpci_tcpm_set_rx_enable, - .get_message_raw = &tcpci_tcpm_get_message_raw, - .transmit = &tcpci_tcpm_transmit, - .tcpc_alert = &tcpci_tcpc_alert, -#ifdef CONFIG_USB_PD_DISCHARGE_TCPC - .tcpc_discharge_vbus = &tcpci_tcpc_discharge_vbus, -#endif - .tcpc_enable_auto_discharge_disconnect = - &tcpci_tcpc_enable_auto_discharge_disconnect, -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - .drp_toggle = &tcpci_tcpc_drp_toggle, -#endif - .get_chip_info = &tcpci_get_chip_info, -#ifdef CONFIG_USB_PD_PPC - .get_snk_ctrl = &tcpci_tcpm_get_snk_ctrl, - .set_snk_ctrl = &tcpci_tcpm_set_snk_ctrl, - .get_src_ctrl = &tcpci_tcpm_get_src_ctrl, - .set_src_ctrl = &tcpci_tcpm_set_src_ctrl, -#endif -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER - .enter_low_power_mode = &tcpci_enter_low_power_mode, -#endif - .set_bist_test_mode = &tcpci_set_bist_test_mode, -#ifdef CONFIG_CMD_TCPC_DUMP - .dump_registers = &tcpc_dump_std_registers, -#endif -}; diff --git a/driver/tcpm/tusb422.c b/driver/tcpm/tusb422.c deleted file mode 100644 index f2a4ec2fb3..0000000000 --- a/driver/tcpm/tusb422.c +++ /dev/null @@ -1,195 +0,0 @@ -/* Copyright 2018 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. - */ - -/* Type-C port manager for TI TUSB422 Port Controller */ - -#include "common.h" -#include "tusb422.h" -#include "tcpm/tcpci.h" -#include "tcpm/tcpm.h" -#include "timer.h" -#include "usb_pd.h" - -#ifndef CONFIG_USB_PD_TCPM_TCPCI -#error "TUSB422 is using a standard TCPCI interface" -#error "Please upgrade your board configuration" - -#endif - -#if defined(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE) && \ - !defined(CONFIG_USB_PD_TCPC_LOW_POWER) -#error "TUSB422 driver requires CONFIG_USB_PD_TCPC_LOW_POWER if " \ - "CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE is enabled" -#endif - -#if defined(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE) && \ - defined(CONFIG_USB_PD_DISCHARGE_TCPC) -#error "TUSB422 must disable TCPC discharge to support enabling Auto " \ - "Discharge Disconnect all the time." -#endif - -enum tusb422_reg_addr { - TUSB422_REG_VBUS_AND_VCONN_CONTROL = 0x98, -}; - -enum vbus_and_vconn_control_mask { - INT_VCONNDIS_DISABLE = BIT(1), - INT_VBUSDIS_DISABLE = BIT(2), -}; - -/* The TUSB422 cannot drive an FRS GPIO, but can detect FRS */ -static int tusb422_set_frs_enable(int port, int enable) -{ - return tcpc_update8(port, TUSB422_REG_PHY_BMC_RX_CTRL, - TUSB422_REG_PHY_BMC_RX_CTRL_FRS_RX_EN, - enable ? MASK_SET : MASK_CLR); -} - -static int tusb422_tcpci_tcpm_init(int port) -{ - int rv; - - /* - * Do not perform TCPC soft reset while waking from Low Power Mode, - * because it makes DRP incapable of looking for connection correctly - * (see b/176986511) and probably breaks firmware_PDTrySrc test - * (see b/179234089). - * - * TODO(b/179234089): Consider implementing function that performs - * only necessary things when leaving Low Power Mode, so we can perform - * TCPC soft reset here. - */ - - rv = tcpci_tcpm_init(port); - if (rv) - return rv; - - if (IS_ENABLED(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE)) { - /* - * When dual role auto toggle is enabled, the TUSB422 needs - * auto discharge disconnect enabled so that the CC state - * is detected correctly. - * Without this, the CC lines get stuck in the SRC.Open state - * after updating the ROLE Control register on a device connect. - */ - tusb422_tcpm_drv.tcpc_enable_auto_discharge_disconnect(port, 1); - - /* - * Disable internal VBUS discharge. AutoDischargeDisconnect must - * generally remain enabled to keep TUSB422 in active mode. - * However, this will interfere with FRS by default by - * discharging at inappropriate times. Mitigate this by - * disabling internal VBUS discharge. The TUSB422 must rely on - * external VBUS discharge. See TUSB422 datasheet, 7.4.2 Active - * Mode. - */ - tcpc_write(port, TUSB422_REG_VBUS_AND_VCONN_CONTROL, - INT_VBUSDIS_DISABLE); - } - if (IS_ENABLED(CONFIG_USB_PD_FRS_TCPC)) { - /* Disable FRS detection, and enable the FRS detection alert */ - tusb422_set_frs_enable(port, 0); - tcpc_update16(port, TCPC_REG_ALERT_MASK, - TCPC_REG_ALERT_MASK_VENDOR_DEF, MASK_SET); - tcpc_update8(port, TUSB422_REG_VENDOR_INTERRUPTS_MASK, - TUSB422_REG_VENDOR_INTERRUPTS_MASK_FRS_RX, - MASK_SET); - } - /* - * VBUS detection is supposed to be enabled by default, however the - * TUSB422 has this disabled following reset. - */ - /* Enable VBUS detection */ - return tcpc_write16(port, TCPC_REG_COMMAND, - TCPC_REG_COMMAND_ENABLE_VBUS_DETECT); -} - -static int tusb422_tcpm_set_cc(int port, int pull) -{ - /* - * Enable AutoDischargeDisconnect to keep TUSB422 in active mode through - * this transition. Note that the configuration keeps the TCPC from - * actually discharging VBUS in this case. - */ - if (IS_ENABLED(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE)) - tusb422_tcpm_drv.tcpc_enable_auto_discharge_disconnect(port, 1); - - return tcpci_tcpm_set_cc(port, pull); -} - -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE -static int tusb422_tcpc_drp_toggle(int port) -{ - /* - * The TUSB422 requires auto discharge disconnect to be enabled for - * active mode (not unattached) operation. Make sure it is disabled - * before enabling DRP toggling. - * - * USB Type-C Port Controller Interface Specification revision 2.0, - * Figure 4-21 Source Disconnect and Figure 4-22 Sink Disconnect - */ - tusb422_tcpm_drv.tcpc_enable_auto_discharge_disconnect(port, 0); - - return tcpci_tcpc_drp_toggle(port); -} -#endif - -static void tusb422_tcpci_tcpc_alert(int port) -{ - if (IS_ENABLED(CONFIG_USB_PD_FRS_TCPC)) { - int regval; - - /* FRS detection is a vendor defined alert */ - tcpc_read(port, TUSB422_REG_VENDOR_INTERRUPTS_STATUS, ®val); - if (regval & TUSB422_REG_VENDOR_INTERRUPTS_STATUS_FRS_RX) { - tusb422_set_frs_enable(port, 0); - tcpc_write(port, TUSB422_REG_VENDOR_INTERRUPTS_STATUS, - regval); - pd_got_frs_signal(port); - } - } - tcpci_tcpc_alert(port); -} - -const struct tcpm_drv tusb422_tcpm_drv = { - .init = &tusb422_tcpci_tcpm_init, - .release = &tcpci_tcpm_release, - .get_cc = &tcpci_tcpm_get_cc, -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - .check_vbus_level = &tcpci_tcpm_check_vbus_level, -#endif - .select_rp_value = &tcpci_tcpm_select_rp_value, - .set_cc = &tusb422_tcpm_set_cc, - .set_polarity = &tcpci_tcpm_set_polarity, -#ifdef CONFIG_USB_PD_DECODE_SOP - .sop_prime_enable = &tcpci_tcpm_sop_prime_enable, -#endif - .set_vconn = &tcpci_tcpm_set_vconn, - .set_msg_header = &tcpci_tcpm_set_msg_header, - .set_rx_enable = &tcpci_tcpm_set_rx_enable, - .get_message_raw = &tcpci_tcpm_get_message_raw, - .transmit = &tcpci_tcpm_transmit, - .tcpc_alert = &tusb422_tcpci_tcpc_alert, -#ifdef CONFIG_USB_PD_DISCHARGE_TCPC - .tcpc_discharge_vbus = &tcpci_tcpc_discharge_vbus, -#endif - .tcpc_enable_auto_discharge_disconnect = - &tcpci_tcpc_enable_auto_discharge_disconnect, -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - .drp_toggle = &tusb422_tcpc_drp_toggle, -#endif -#ifdef CONFIG_USB_PD_PPC - .set_snk_ctrl = &tcpci_tcpm_set_snk_ctrl, - .set_src_ctrl = &tcpci_tcpm_set_src_ctrl, -#endif - .get_chip_info = &tcpci_get_chip_info, -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER - .enter_low_power_mode = &tcpci_enter_low_power_mode, -#endif - .set_bist_test_mode = &tcpci_set_bist_test_mode, -#ifdef CONFIG_USB_PD_FRS_TCPC - .set_frs_enable = &tusb422_set_frs_enable, -#endif -}; diff --git a/driver/tcpm/tusb422.h b/driver/tcpm/tusb422.h deleted file mode 100644 index f39939b184..0000000000 --- a/driver/tcpm/tusb422.h +++ /dev/null @@ -1,22 +0,0 @@ -/* Copyright 2018 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. - */ - -/* TI TUSB422 Type-C port controller */ - -#ifndef __CROS_EC_USB_PD_TCPM_TUSB422_H -#define __CROS_EC_USB_PD_TCPM_TUSB422_H - -#include "driver/tcpm/tusb422_public.h" - -#define TUSB422_REG_VENDOR_INTERRUPTS_STATUS 0x90 -#define TUSB422_REG_VENDOR_INTERRUPTS_STATUS_FRS_RX BIT(0) - -#define TUSB422_REG_VENDOR_INTERRUPTS_MASK 0x92 -#define TUSB422_REG_VENDOR_INTERRUPTS_MASK_FRS_RX BIT(0) - -#define TUSB422_REG_PHY_BMC_RX_CTRL 0x96 -#define TUSB422_REG_PHY_BMC_RX_CTRL_FRS_RX_EN BIT(3) - -#endif /* defined(__CROS_EC_USB_PD_TCPM_TUSB422_H) */ diff --git a/driver/temp_sensor/adt7481.c b/driver/temp_sensor/adt7481.c deleted file mode 100644 index cbd32e5cd5..0000000000 --- a/driver/temp_sensor/adt7481.c +++ /dev/null @@ -1,352 +0,0 @@ -/* Copyright 2017 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. - */ - -/* ADT7481 temperature sensor module for Chrome EC */ - -#include "common.h" -#include "console.h" -#include "adt7481.h" -#include "gpio.h" -#include "i2c.h" -#include "hooks.h" -#include "util.h" - -static int temp_val_local; -static int temp_val_remote1; -static int temp_val_remote2; -static uint8_t is_sensor_shutdown; - -/** - * Determine whether the sensor is powered. - * - * @return non-zero the adt7481 sensor is powered. - */ -static int has_power(void) -{ -#ifdef CONFIG_TEMP_SENSOR_POWER_GPIO - return gpio_get_level(CONFIG_TEMP_SENSOR_POWER_GPIO); -#else - return !is_sensor_shutdown; -#endif -} - -static int raw_read8(const int offset, int *data_ptr) -{ - return i2c_read8(I2C_PORT_THERMAL, ADT7481_I2C_ADDR_FLAGS, - offset, data_ptr); -} - -static int raw_write8(const int offset, int data) -{ - return i2c_write8(I2C_PORT_THERMAL, ADT7481_I2C_ADDR_FLAGS, - offset, data); -} - -static int get_temp(const int offset, int *temp_ptr) -{ - int rv; - int temp_raw = 0; - - rv = raw_read8(offset, &temp_raw); - if (rv < 0) - return rv; - - *temp_ptr = (int)(int8_t)temp_raw; - return EC_SUCCESS; -} - -#ifdef CONFIG_CMD_TEMP_SENSOR -static int adt7481_set_temp(const int offset, int temp) -{ - if (temp < -127 || temp > 127) - return EC_ERROR_INVAL; - - return raw_write8(offset, (uint8_t)temp); -} -#endif - -int adt7481_get_val(int idx, int *temp_ptr) -{ - if (!has_power()) - return EC_ERROR_NOT_POWERED; - - switch (idx) { - case ADT7481_IDX_LOCAL: - *temp_ptr = temp_val_local; - break; - case ADT7481_IDX_REMOTE1: - *temp_ptr = temp_val_remote1; - break; - case ADT7481_IDX_REMOTE2: - *temp_ptr = temp_val_remote2; - break; - default: - return EC_ERROR_UNKNOWN; - } - - return EC_SUCCESS; -} - -static int adt7481_shutdown(uint8_t want_shutdown) -{ - int ret, value; - - if (want_shutdown == is_sensor_shutdown) - return EC_SUCCESS; - - ret = raw_read8(ADT7481_CONFIGURATION1_R, &value); - if (ret < 0) { - ccprintf("ERROR: Temp sensor I2C read8 error.\n"); - return ret; - } - - if (want_shutdown && !(value & ADT7481_CONFIG1_RUN_L)) { - /* adt7481 is running, and want it to shutdown */ - /* CONFIG REG1 BIT6: 0=Run, 1=Shutdown */ - /* shut it down */ - value |= ADT7481_CONFIG1_RUN_L; - ret = raw_write8(ADT7481_CONFIGURATION1_R, value); - } else if (!want_shutdown && (value & ADT7481_CONFIG1_RUN_L)) { - /* adt7481 is shutdown, and want turn it on */ - value &= ~ADT7481_CONFIG1_RUN_L; - ret = raw_write8(ADT7481_CONFIGURATION1_R, value); - } - /* else, the current setting is exactly what you want */ - - is_sensor_shutdown = want_shutdown; - return ret; -} - -static int adt7481_set_therm_mode(void) -{ - int ret = 0; - int data = 0; - - ret = raw_read8(ADT7481_CONFIGURATION1_R, &data); - if (ret) - return EC_ERROR_UNKNOWN; - - data |= ADT7481_CONFIG1_MODE; - ret = raw_write8(ADT7481_CONFIGURATION1_W, data); - if (ret) - return EC_ERROR_UNKNOWN; - - return EC_SUCCESS; -} - -int adt7481_set_therm_limit(int channel, int limit_c, int hysteresis) -{ - int ret = 0; - int reg = 0; - - if (channel >= ADT7481_CHANNEL_COUNT) - return EC_ERROR_INVAL; - - if (hysteresis > ADT7481_HYSTERESIS_HIGH_LIMIT || - hysteresis < ADT7481_HYSTERESIS_LOW_LIMIT) - return EC_ERROR_INVAL; - - /* hysteresis must be less than high limit */ - if (hysteresis > limit_c) - return EC_ERROR_INVAL; - - if (adt7481_set_therm_mode() != EC_SUCCESS) - return EC_ERROR_UNKNOWN; - - switch (channel) { - case ADT7481_CHANNEL_LOCAL: - reg = ADT7481_LOCAL_HIGH_LIMIT_W; - break; - case ADT7481_CHANNEL_REMOTE1: - reg = ADT7481_REMOTE1_HIGH_LIMIT_W; - break; - case ADT7481_CHANNEL_REMOTE2: - reg = ADT7481_REMOTE2_HIGH_LIMIT; - break; - } - - ret = raw_write8(reg, limit_c); - if (ret) - return EC_ERROR_UNKNOWN; - - ret = raw_write8(ADT7481_THERM_HYSTERESIS, hysteresis); - if (ret) - return EC_ERROR_UNKNOWN; - - return EC_SUCCESS; -} - -static void adt7481_temp_sensor_poll(void) -{ - int temp_c; - - if (!has_power()) - return; - - if (get_temp(ADT7481_LOCAL, &temp_c) == EC_SUCCESS) - temp_val_local = C_TO_K(temp_c); - - if (get_temp(ADT7481_REMOTE1, &temp_c) == EC_SUCCESS) - temp_val_remote1 = C_TO_K(temp_c); - - if (get_temp(ADT7481_REMOTE2, &temp_c) == EC_SUCCESS) - temp_val_remote2 = C_TO_K(temp_c); -} -DECLARE_HOOK(HOOK_SECOND, adt7481_temp_sensor_poll, HOOK_PRIO_TEMP_SENSOR); - -#ifdef CONFIG_CMD_TEMP_SENSOR -static void print_temps( - const char *name, - const int adt7481_temp_reg, - const int adt7481_therm_limit_reg, - const int adt7481_high_limit_reg, - const int adt7481_low_limit_reg) -{ - int value; - - if (!has_power()) { - ccprintf(" ADT7481 is shutdown\n"); - return; - } - - ccprintf("%s:\n", name); - - if (get_temp(adt7481_temp_reg, &value) == EC_SUCCESS) - ccprintf(" Temp %3dC\n", value); - - if (get_temp(adt7481_therm_limit_reg, &value) == EC_SUCCESS) - ccprintf(" Therm Trip %3dC\n", value); - - if (get_temp(adt7481_high_limit_reg, &value) == EC_SUCCESS) - ccprintf(" High Alarm %3dC\n", value); - - if (get_temp(adt7481_low_limit_reg, &value) == EC_SUCCESS) - ccprintf(" Low Alarm %3dC\n", value); -} - -static int print_status(void) -{ - int value; - - print_temps("Local", ADT7481_LOCAL, - ADT7481_LOCAL_THERM_LIMIT, - ADT7481_LOCAL_HIGH_LIMIT_R, - ADT7481_LOCAL_LOW_LIMIT_R); - - print_temps("Remote1", ADT7481_REMOTE1, - ADT7481_REMOTE1_THERM_LIMIT, - ADT7481_REMOTE1_HIGH_LIMIT_R, - ADT7481_REMOTE1_LOW_LIMIT_R); - - print_temps("Remote2", ADT7481_REMOTE2, - ADT7481_REMOTE2_THERM_LIMIT, - ADT7481_REMOTE2_HIGH_LIMIT, - ADT7481_REMOTE2_LOW_LIMIT); - - ccprintf("\n"); - - if (raw_read8(ADT7481_STATUS1_R, &value) == EC_SUCCESS) - ccprintf("STATUS1: %pb\n", BINARY_VALUE(value, 8)); - - if (raw_read8(ADT7481_STATUS2_R, &value) == EC_SUCCESS) - ccprintf("STATUS2: %pb\n", BINARY_VALUE(value, 8)); - - if (raw_read8(ADT7481_CONFIGURATION1_R, &value) == EC_SUCCESS) - ccprintf("CONFIG1: %pb\n", BINARY_VALUE(value, 8)); - - if (raw_read8(ADT7481_CONFIGURATION2, &value) == EC_SUCCESS) - ccprintf("CONFIG2: %pb\n", BINARY_VALUE(value, 8)); - - return EC_SUCCESS; -} - -static int command_adt7481(int argc, char **argv) -{ - char *command; - char *e; - char *power; - int data; - int offset; - int rv; - - /* handle "power" command before checking the power status. */ - if ((argc == 3) && !strcasecmp(argv[1], "power")) { - power = argv[2]; - if (!strncasecmp(power, "on", sizeof("on"))) { - rv = adt7481_set_power(ADT7481_POWER_ON); - if (!rv) - print_status(); - } else if (!strncasecmp(power, "off", sizeof("off"))) - rv = adt7481_set_power(ADT7481_POWER_OFF); - else - return EC_ERROR_PARAM2; - ccprintf("Set ADT7481 %s\n", power); - return rv; - } - - if (!has_power()) { - ccprintf("ERROR: Temp sensor not powered.\n"); - return EC_ERROR_NOT_POWERED; - } - - /* If no args just print status */ - if (argc == 1) - return print_status(); - - if (argc < 3) - return EC_ERROR_PARAM_COUNT; - - command = argv[1]; - offset = strtoi(argv[2], &e, 0); - if (*e || offset < 0 || offset > 255) - return EC_ERROR_PARAM2; - - if (!strcasecmp(command, "getbyte")) { - rv = raw_read8(offset, &data); - if (rv < 0) - return rv; - ccprintf("Byte at offset 0x%02x is %pb\n", - offset, BINARY_VALUE(data, 8)); - return rv; - } - - /* Remaining commands are "adt7481 set-command offset data" */ - if (argc != 4) - return EC_ERROR_PARAM_COUNT; - - data = strtoi(argv[3], &e, 0); - if (*e) - return EC_ERROR_PARAM3; - - if (!strcasecmp(command, "settemp")) { - ccprintf("Setting 0x%02x to %dC\n", offset, data); - rv = adt7481_set_temp(offset, data); - } else if (!strcasecmp(command, "setbyte")) { - ccprintf("Setting 0x%02x to 0x%02x\n", offset, data); - rv = raw_write8(offset, data); - } else - return EC_ERROR_PARAM1; - - return rv; -} -DECLARE_CONSOLE_COMMAND(adt7481, command_adt7481, - "[settemp|setbyte <offset> <value>] or [getbyte <offset>] or" - "[power <on|off>]. " - "Temps in Celsius.", - "Print tmp432 temp sensor status or set parameters."); -#endif - -int adt7481_set_power(enum adt7481_power_state power_on) -{ -#ifndef CONFIG_TEMP_SENSOR_POWER_GPIO - uint8_t shutdown = (power_on == ADT7481_POWER_OFF) ? 1 : 0; - - return adt7481_shutdown(shutdown); -#else - gpio_set_level(CONFIG_TEMP_SENSOR_POWER_GPIO, power_on); - return EC_SUCCESS; -#endif -} - diff --git a/driver/temp_sensor/adt7481.h b/driver/temp_sensor/adt7481.h deleted file mode 100644 index 78541a0a3b..0000000000 --- a/driver/temp_sensor/adt7481.h +++ /dev/null @@ -1,178 +0,0 @@ -/* Copyright 2017 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. - */ - -/* ADT7481 temperature sensor module for Chrome EC */ - -#ifndef __CROS_EC_ADT7481_H -#define __CROS_EC_ADT7481_H - -#define ADT7481_I2C_ADDR_FLAGS 0x4B - -#define ADT7481_IDX_LOCAL 0 -#define ADT7481_IDX_REMOTE1 1 -#define ADT7481_IDX_REMOTE2 2 - -/* Chip-specific registers */ -#define ADT7481_LOCAL 0x00 -#define ADT7481_REMOTE1 0x01 -#define ADT7481_STATUS1_R 0x02 -#define ADT7481_CONFIGURATION1_R 0x03 -#define ADT7481_CONVERSION_RATE_R 0x04 -#define ADT7481_LOCAL_HIGH_LIMIT_R 0x05 -#define ADT7481_LOCAL_LOW_LIMIT_R 0x06 -#define ADT7481_REMOTE1_HIGH_LIMIT_R 0x07 -#define ADT7481_REMOTE1_LOW_LIMIT_R 0x08 -#define ADT7481_CONFIGURATION1_W 0x09 -#define ADT7481_CONVERSION_RATE_W 0x0a -#define ADT7481_LOCAL_HIGH_LIMIT_W 0x0b -#define ADT7481_LOCAL_LOW_LIMIT_W 0x0c -#define ADT7481_REMOTE1_HIGH_LIMIT_W 0x0d -#define ADT7481_REMOTE1_LOW_LIMIT_W 0x0e -#define ADT7481_ONESHOT_W 0x0f -#define ADT7481_REMOTE1_EXTD_R 0x10 -#define ADT7481_REMOTE1_OFFSET 0x11 -#define ADT7481_REMOTE1_OFFSET_EXTD 0x12 -#define ADT7481_REMOTE1_HIGH_LIMIT_EXTD 0x13 -#define ADT7481_REMOTE1_LOW_LIMIT_EXTD 0x14 -#define ADT7481_REMOTE1_THERM_LIMIT 0x19 -#define ADT7481_LOCAL_THERM_LIMIT 0x20 -#define ADT7481_THERM_HYSTERESIS 0x21 -#define ADT7481_CONSECUTIVE_ALERT 0x22 -#define ADT7481_STATUS2_R 0x23 -#define ADT7481_CONFIGURATION2 0x24 -#define ADT7481_REMOTE2 0x30 -#define ADT7481_REMOTE2_HIGH_LIMIT 0x31 -#define ADT7481_REMOTE2_LOW_LIMIT 0x32 -#define ADT7481_REMOTE2_EXTD_R 0x33 -#define ADT7481_REMOTE2_OFFSET 0x34 -#define ADT7481_REMOTE2_OFFSET_EXTD 0x35 -#define ADT7481_REMOTE2_HIGH_LIMIT_EXTD 0x36 -#define ADT7481_REMOTE2_LOW_LIMIT_EXTD 0x37 -#define ADT7481_REMOTE2_THERM_LIMIT 0x39 -#define ADT7481_DEVICE_ID 0x3d -#define ADT7481_MANUFACTURER_ID 0x3e - -/* Config1 register bits */ -#define ADT7481_CONFIG1_REMOTE1_ALERT_MASK BIT(0) -#define ADT7481_CONFIG1_REMOTE2_ALERT_MASK BIT(1) -#define ADT7481_CONFIG1_TEMP_RANGE BIT(2) -#define ADT7481_CONFIG1_SEL_REMOTE2 BIT(3) -/* ADT7481_CONFIG1_MODE bit is use to enable THERM mode */ -#define ADT7481_CONFIG1_MODE BIT(5) -#define ADT7481_CONFIG1_RUN_L BIT(6) -/* mask all alerts on ALERT# pin */ -#define ADT7481_CONFIG1_ALERT_MASK_L BIT(7) - -/* Config2 register bits */ -#define ADT7481_CONFIG2_LOCK BIT(7) - -/* Conversion Rate/Channel Select Register */ -#define ADT7481_CONV_RATE_MASK (0x0f) -#define ADT7481_CONV_RATE_16S (0x00) -#define ADT7481_CONV_RATE_8S (0x01) -#define ADT7481_CONV_RATE_4S (0x02) -#define ADT7481_CONV_RATE_2S (0x03) -#define ADT7481_CONV_RATE_1S (0x04) -#define ADT7481_CONV_RATE_500MS (0x05) -#define ADT7481_CONV_RATE_250MS (0x06) -#define ADT7481_CONV_RATE_125MS (0x07) -#define ADT7481_CONV_RATE_62500US (0x08) -#define ADT7481_CONV_RATE_31250US (0x09) -#define ADT7481_CONV_RATE_15500US (0x0a) -/* continuous mode 73 ms averaging */ -#define ADT7481_CONV_RATE_73MS_AVE (0x0b) -#define ADT7481_CONV_CHAN_SELECT_MASK (0x30) -#define ADT7481_CONV_CHAN_SEL_ROUND_ROBIN (0 << 4) -#define ADT7481_CONV_CHAN_SEL_LOCAL BIT(4) -#define ADT7481_CONV_CHAN_SEL_REMOTE1 (2 << 4) -#define ADT7481_CONV_CHAN_SEL_REMOTE2 (3 << 4) -#define ADT7481_CONV_AVERAGING_L BIT(7) - - -/* Status1 register bits */ -#define ADT7481_STATUS1_LOCAL_THERM_ALARM BIT(0) -#define ADT7481_STATUS1_REMOTE1_THERM_ALARM BIT(1) -#define ADT7481_STATUS1_REMOTE1_OPEN BIT(2) -#define ADT7481_STATUS1_REMOTE1_LOW_ALARM BIT(3) -#define ADT7481_STATUS1_REMOTE1_HIGH_ALARM BIT(4) -#define ADT7481_STATUS1_LOCAL_LOW_ALARM BIT(5) -#define ADT7481_STATUS1_LOCAL_HIGH_ALARM BIT(6) -#define ADT7481_STATUS1_BUSY BIT(7) - -/* Status2 register bits */ -#define ADT7481_STATUS2_ALERT BIT(0) -#define ADT7481_STATUS2_REMOTE2_THERM_ALARM BIT(1) -#define ADT7481_STATUS2_REMOTE2_OPEN BIT(2) -#define ADT7481_STATUS2_REMOTE2_LOW_ALARM BIT(3) -#define ADT7481_STATUS2_REMOTE2_HIGH_ALARM BIT(4) - -/* Consecutive Alert register */ -#define ADT7481_CONSEC_MASK (0xf) -#define ADT7481_CONSEC_1 (0x0) -#define ADT7481_CONSEC_2 (0x2) -#define ADT7481_CONSEC_3 (0x6) -#define ADT7481_CONSEC_4 (0xe) -#define ADT7481_CONSEC_EN_SCL_TIMEOUT BIT(5) -#define ADT7481_CONSEC_EN_SDA_TIMEOUT BIT(6) -#define ADT7481_CONSEC_MASK_LOCAL_ALERT BIT(7) - - -/* Limits */ -#define ADT7481_HYSTERESIS_HIGH_LIMIT 255 -#define ADT7481_HYSTERESIS_LOW_LIMIT 0 - -enum adt7481_power_state { - ADT7481_POWER_OFF = 0, - ADT7481_POWER_ON, - ADT7481_POWER_COUNT -}; - -enum adt7481_channel_id { - ADT7481_CHANNEL_LOCAL, - ADT7481_CHANNEL_REMOTE1, - ADT7481_CHANNEL_REMOTE2, - - ADT7481_CHANNEL_COUNT -}; - -/** - * Get the last polled value of a sensor. - * - * @param idx Index to read. Idx indicates whether to read die - * temperature or external temperature. - * @param temp_ptr Destination for temperature in K. - * - * @return EC_SUCCESS if successful, non-zero if error. - */ -int adt7481_get_val(int idx, int *temp_ptr); - -/** - * Power control function of ADT7481 temperature sensor. - * - * @param power_on ADT7481_POWER_ON: turn ADT7481 sensor on. - * ADT7481_POWER_OFF: shut ADT7481 sensor down. - * - * @return EC_SUCCESS if successful, non-zero if error. - */ -int adt7481_set_power(enum adt7481_power_state power_on); - -/* - * Set ADT7481 ALERT#/THERM2# pin to THERM mode, and give a limit - * for a specific channel. - * - * @param channel specific a channel - * - * @param limit_c High limit temperature, default: 85C - * - * @param hysteresis Hysteresis temperature, default: 10C - * All channels share the same hysteresis - * - * In THERM mode, ALERT# pin will trigger(Low) by itself when any - * channel's temperature is greater( >= )than channel's limit_c, - * and release(High) by itself when channel's temperature is lower - * than (limit_c - hysteresis) - */ -int adt7481_set_therm_limit(int channel, int limit_c, int hysteresis); -#endif /* __CROS_EC_ADT7481_H */ diff --git a/driver/temp_sensor/amd_r19me4070.c b/driver/temp_sensor/amd_r19me4070.c deleted file mode 100644 index b331a1a3eb..0000000000 --- a/driver/temp_sensor/amd_r19me4070.c +++ /dev/null @@ -1,90 +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. - */ - -/* R19ME4070 temperature sensor module for Chrome EC */ - -#include "chipset.h" -#include "common.h" -#include "console.h" -#include "hooks.h" -#include "i2c.h" -#include "amd_r19me4070.h" -#include "power.h" - -#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args) - -/* GPU I2C address */ -#define GPU_ADDR_FLAGS 0x0041 - -#define GPU_INIT_OFFSET 0x01 -#define GPU_TEMPERATURE_OFFSET 0x03 - -static int initialized; -/* - * Tell SMBus we want to read 4 Byte from register offset(0x01665A) - */ -static const uint8_t gpu_init_write_value[5] = { - 0x04, 0x0F, 0x01, 0x66, 0x5A, -}; - -static void gpu_init_temp_sensor(void) -{ - int rv; - rv = i2c_write_block(I2C_PORT_GPU, GPU_ADDR_FLAGS, GPU_INIT_OFFSET, - gpu_init_write_value, - ARRAY_SIZE(gpu_init_write_value)); - if (rv == EC_SUCCESS) { - initialized = 1; - return; - } - CPRINTS("init GPU fail"); -} - -/* INIT GPU first before read the GPU's die tmeperature. */ -int get_temp_R19ME4070(int idx, int *temp_ptr) -{ - uint8_t reg[5]; - int rv; - - /* - * We shouldn't read the GPU temperature when the state - * is not in S0, because GPU is enabled in S0. - */ - if ((power_get_state()) != POWER_S0) { - *temp_ptr = C_TO_K(0); - return EC_ERROR_BUSY; - } - /* if no INIT GPU, must init it first and wait 1 sec. */ - if (!initialized) { - gpu_init_temp_sensor(); - *temp_ptr = C_TO_K(0); - return EC_ERROR_BUSY; - } - rv = i2c_read_block(I2C_PORT_GPU, GPU_ADDR_FLAGS, - GPU_TEMPERATURE_OFFSET, reg, ARRAY_SIZE(reg)); - if (rv) { - CPRINTS("read GPU Temperature fail"); - *temp_ptr = C_TO_K(0); - return rv; - } - /* - * The register is four bytes, bit[17:9] represents the GPU temperature. - * 0x000 : 0 ゚C - * 0x001 : 1 ゚C - * 0x002 : 2 ゚C - * ... - * 0x1FF : 511 ゚C - * ------------------------------- - * reg[4] = bit0 - bit7 - * reg[3] = bit8 - bit15 - * reg[2] = bit16 - bit23 - * reg[1] = bit24 - bit31 - * reg[0] = 0x04 - */ - *temp_ptr = C_TO_K(reg[3] >> 1); - - return EC_SUCCESS; -} diff --git a/driver/temp_sensor/amd_r19me4070.h b/driver/temp_sensor/amd_r19me4070.h deleted file mode 100644 index d3c7977ba5..0000000000 --- a/driver/temp_sensor/amd_r19me4070.h +++ /dev/null @@ -1,20 +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. - */ - -/* GPU R19ME4070 configuration */ - -#ifndef __CROS_EC_R19ME4070_H -#define __CROS_EC_R19ME4070_H - -/* GPU features */ -#define R19ME4070_LOCAL 0 - -/* - * get GPU temperature value and move to *tem_ptr - * One second trigger ,Use I2C read GPU's Die temperature. - */ -int get_temp_R19ME4070(int idx, int *temp_ptr); - -#endif /* __CROS_EC_AMD_R19ME4070_H */ diff --git a/driver/temp_sensor/bd99992gw.c b/driver/temp_sensor/bd99992gw.c deleted file mode 100644 index e66642224c..0000000000 --- a/driver/temp_sensor/bd99992gw.c +++ /dev/null @@ -1,182 +0,0 @@ -/* 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. - */ - -/* - * BD99992GW PMIC temperature sensor module for Chrome EC. - * Note that ADC / temperature sensor registers are only active while - * the PMIC is in S0. - */ - -#include "bd99992gw.h" -#include "chipset.h" -#include "common.h" -#include "console.h" -#include "gpio.h" -#include "hooks.h" -#include "i2c.h" -#include "temp_sensor.h" -#include "temp_sensor/thermistor.h" -#include "timer.h" -#include "util.h" - -/* Console output macros */ -#define CPUTS(outstr) cputs(CC_THERMAL, outstr) -#define CPRINTS(format, args...) cprints(CC_THERMAL, format, ## args) - -/* List of active channels, ordered by pointer register */ -static enum bd99992gw_adc_channel - active_channels[BD99992GW_ADC_POINTER_REG_COUNT]; - -/* - * Use 27ms as the period between ADC conversions, as we will typically be - * sampling temperature sensors every second, and 27ms is the longest - * supported period. - */ -#define ADC_LOOP_PERIOD BD99992GW_ADC1CNTL1_SLP27MS - -static int raw_read8(const int offset, int *data_ptr) -{ - int ret; - ret = i2c_read8(I2C_PORT_THERMAL, BD99992GW_I2C_ADDR_FLAGS, - offset, data_ptr); - if (ret != EC_SUCCESS) - CPRINTS("bd99992gw read fail %d", ret); - return ret; -} - -static int raw_write8(const int offset, int data) -{ - int ret; - ret = i2c_write8(I2C_PORT_THERMAL, BD99992GW_I2C_ADDR_FLAGS, - offset, data); - if (ret != EC_SUCCESS) - CPRINTS("bd99992gw write fail %d", ret); - return ret; -} - -static void bd99992gw_init(void) -{ - int i; - int active_channel_count = 0; - uint8_t pointer_reg = BD99992GW_REG_ADC1ADDR0; - - /* Mark active channels from the board temp sensor table */ - for (i = 0; i < TEMP_SENSOR_COUNT; ++i) - if (temp_sensors[i].read == bd99992gw_get_val) - active_channels[active_channel_count++] = - temp_sensors[i].idx; - - /* Make sure we don't have too many active channels. */ - ASSERT(active_channel_count <= ARRAY_SIZE(active_channels)); - - /* Mark the first unused channel so we know where to stop searching */ - if (active_channel_count != ARRAY_SIZE(active_channels)) - active_channels[active_channel_count] = - BD99992GW_ADC_CHANNEL_NONE; - - /* Now write pointer regs with channel to monitor */ - for (i = 0; i < active_channel_count; ++i) - /* Write stop bit on last channel */ - if (raw_write8(pointer_reg + i, active_channels[i] | - ((i == active_channel_count - 1) ? - BD99992GW_ADC1ADDR_STOP : 0))) - return; - - /* Enable ADC interrupts */ - if (raw_write8(BD99992GW_REG_MADC1INT, 0xf & ~BD99992GW_MADC1INT_RND)) - return; - if (raw_write8(BD99992GW_REG_IRQLVL1MSK, BD99992GW_IRQLVL1MSK_MADC)) - return; - - /* Enable ADC sequencing */ - if (raw_write8(BD99992GW_REG_ADC1CNTL2, BD99992GW_ADC1CNTL2_ADCTHERM)) - return; - - /* Start round-robin conversions at 27ms period */ - raw_write8(BD99992GW_REG_ADC1CNTL1, ADC_LOOP_PERIOD | - BD99992GW_ADC1CNTL1_ADEN | BD99992GW_ADC1CNTL1_ADSTRT); -} -/* - * Some regs only work in S0, so we must initialize on AP startup in - * addition to INIT. - */ -DECLARE_HOOK(HOOK_INIT, bd99992gw_init, HOOK_PRIO_DEFAULT); -DECLARE_HOOK(HOOK_CHIPSET_RESUME, bd99992gw_init, HOOK_PRIO_DEFAULT); - -/* Convert ADC result to temperature in celsius */ -static int bd99992gw_get_temp(uint16_t adc) -{ -#ifdef CONFIG_THERMISTOR_NCP15WB - return ncp15wb_calculate_temp(adc); -#else -#error "Unknown thermistor for bd99992gw" - return 0; -#endif -} - -/* Get temperature from requested sensor */ -int bd99992gw_get_val(int idx, int *temp_ptr) -{ - uint16_t adc; - int i, read, ret; - enum bd99992gw_adc_channel channel; - - /* ADC unit is only functional in S0 */ - if (!chipset_in_state(CHIPSET_STATE_ON)) - return EC_ERROR_NOT_POWERED; - - /* Find requested channel */ - for (i = 0; i < ARRAY_SIZE(active_channels); ++i) { - channel = active_channels[i]; - if (channel == idx || - channel == BD99992GW_ADC_CHANNEL_NONE) - break; - } - - /* Make sure we found it */ - if (i == ARRAY_SIZE(active_channels) || - active_channels[i] != idx) { - CPRINTS("Bad ADC channel %d", idx); - return EC_ERROR_INVAL; - } - - /* Pause conversions */ - ret = raw_write8(0x80, - ADC_LOOP_PERIOD | - BD99992GW_ADC1CNTL1_ADEN | - BD99992GW_ADC1CNTL1_ADSTRT | - BD99992GW_ADC1CNTL1_ADPAUSE); - if (ret) - return ret; - - /* Read 10-bit ADC result */ - ret = raw_read8(BD99992GW_REG_ADC1DATA0L + 2 * i, &read); - if (ret) - return ret; - adc = read; - ret = raw_read8(BD99992GW_REG_ADC1DATA0H + 2 * i, &read); - if (ret) - return ret; - adc |= read << 2; - - /* Convert temperature to C / K */ - *temp_ptr = C_TO_K(bd99992gw_get_temp(adc)); - - /* Clear interrupts */ - ret = raw_write8(BD99992GW_REG_ADC1INT, BD99992GW_ADC1INT_RND); - if (ret) - return ret; - ret = raw_write8(BD99992GW_REG_IRQLVL1, BD99992GW_IRQLVL1_ADC); - if (ret) - return ret; - - /* Resume conversions */ - ret = raw_write8(BD99992GW_REG_ADC1CNTL1, ADC_LOOP_PERIOD | - BD99992GW_ADC1CNTL1_ADEN | BD99992GW_ADC1CNTL1_ADSTRT); - if (ret) - return ret; - - return EC_SUCCESS; -} diff --git a/driver/temp_sensor/bd99992gw.h b/driver/temp_sensor/bd99992gw.h deleted file mode 100644 index c461012c45..0000000000 --- a/driver/temp_sensor/bd99992gw.h +++ /dev/null @@ -1,90 +0,0 @@ -/* 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. - */ - -/* G781 temperature sensor module for Chrome EC */ - -#ifndef __CROS_EC_TEMP_SENSOR_BD99992GW_H -#define __CROS_EC_TEMP_SENSOR_BD99992GW_H - -#define BD99992GW_I2C_ADDR_FLAGS 0x30 - -/* ADC channels */ -enum bd99992gw_adc_channel { - BD99992GW_ADC_CHANNEL_NONE = -1, - BD99992GW_ADC_CHANNEL_BATTERY = 0, - BD99992GW_ADC_CHANNEL_AC = 1, - BD99992GW_ADC_CHANNEL_SYSTHERM0 = 2, - BD99992GW_ADC_CHANNEL_SYSTHERM1 = 3, - BD99992GW_ADC_CHANNEL_SYSTHERM2 = 4, - BD99992GW_ADC_CHANNEL_SYSTHERM3 = 5, - BD99992GW_ADC_CHANNEL_DIE_TEMP = 6, - BD99992GW_ADC_CHANNEL_VDC = 7, - BD99992GW_ADC_CHANNEL_COUNT = 8, -}; - -/* Registers */ -#define BD99992GW_REG_IRQLVL1 0x02 -#define BD99992GW_IRQLVL1_ADC BIT(1) /* ADC IRQ asserted */ - -#define BD99992GW_REG_ADC1INT 0x03 -#define BD99992GW_ADC1INT_RND BIT(0) /* RR cycle completed */ - -#define BD99992GW_REG_MADC1INT 0x0a -#define BD99992GW_MADC1INT_RND BIT(0) /* RR cycle mask */ - -#define BD99992GW_REG_IRQLVL1MSK 0x13 -#define BD99992GW_IRQLVL1MSK_MADC BIT(1) /* ADC IRQ mask */ - -#define BD99992GW_REG_ADC1CNTL1 0x80 -#define BD99992GW_ADC1CNTL1_SLP27MS (0x6 << 3) /* 27ms between pass */ -#define BD99992GW_ADC1CNTL1_NOLOOP (0x7 << 3) /* Single loop pass only */ -#define BD99992GW_ADC1CNTL1_ADPAUSE BIT(2) /* ADC pause */ -#define BD99992GW_ADC1CNTL1_ADSTRT BIT(1) /* ADC start */ -#define BD99992GW_ADC1CNTL1_ADEN BIT(0) /* ADC enable */ - -#define BD99992GW_REG_ADC1CNTL2 0x81 -#define BD99992GW_ADC1CNTL2_ADCTHERM BIT(0) /* Enable ADC sequencing */ - - /* ADC1 Pointer file regs - assign to proper bd99992gw_adc_channel */ -#define BD99992GW_ADC_POINTER_REG_COUNT 8 -#define BD99992GW_REG_ADC1ADDR0 0x82 -#define BD99992GW_REG_ADC1ADDR1 0x83 -#define BD99992GW_REG_ADC1ADDR2 0x84 -#define BD99992GW_REG_ADC1ADDR3 0x85 -#define BD99992GW_REG_ADC1ADDR4 0x86 -#define BD99992GW_REG_ADC1ADDR5 0x87 -#define BD99992GW_REG_ADC1ADDR6 0x88 -#define BD99992GW_REG_ADC1ADDR7 0x89 -#define BD99992GW_ADC1ADDR_STOP BIT(3) /* Last conversion channel */ - -/* Result registers */ -#define BD99992GW_REG_ADC1DATA0L 0x95 -#define BD99992GW_REG_ADC1DATA0H 0x96 -#define BD99992GW_REG_ADC1DATA1L 0x97 -#define BD99992GW_REG_ADC1DATA1H 0x98 -#define BD99992GW_REG_ADC1DATA2L 0x99 -#define BD99992GW_REG_ADC1DATA2H 0x9a -#define BD99992GW_REG_ADC1DATA3L 0x9b -#define BD99992GW_REG_ADC1DATA3H 0x9c -#define BD99992GW_REG_ADC1DATA4L 0x9d -#define BD99992GW_REG_ADC1DATA4H 0x9e -#define BD99992GW_REG_ADC1DATA5L 0x9f -#define BD99992GW_REG_ADC1DATA5H 0xa0 -#define BD99992GW_REG_ADC1DATA6L 0xa1 -#define BD99992GW_REG_ADC1DATA6H 0xa2 -#define BD99992GW_REG_ADC1DATA7L 0xa3 -#define BD99992GW_REG_ADC1DATA7H 0xa4 - -/** - * Get the latest value from the sensor. - * - * @param idx ADC channel to read. - * @param temp_ptr Destination for temperature in K. - * - * @return EC_SUCCESS if successful, non-zero if error. - */ -int bd99992gw_get_val(int idx, int *temp_ptr); - -#endif /* __CROS_EC_TEMP_SENSOR_BD99992GW_H */ diff --git a/driver/temp_sensor/ec_adc.c b/driver/temp_sensor/ec_adc.c deleted file mode 100644 index 196d191e47..0000000000 --- a/driver/temp_sensor/ec_adc.c +++ /dev/null @@ -1,56 +0,0 @@ -/* 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. - */ - -/* EC_ADC driver for Chrome EC */ - -#include "adc.h" -#include "common.h" -#include "console.h" -#include "ec_adc.h" -#include "temp_sensor/thermistor.h" -#include "util.h" - -/* Get temperature from requested sensor */ -static int get_temp(int idx, int *temp_ptr) -{ - int temp_raw = 0; - - /* Read 10-bit ADC result */ - temp_raw = adc_read_channel(idx); - - if (temp_raw == ADC_READ_ERROR) - return EC_ERROR_UNKNOWN; - - /* TODO : Need modification here if the result is not 10-bit */ - - /* If there is no thermistor calculation function. - * 1. Add adjusting function like thermistor_ncp15wb.c - * 2. Place function here with ifdef - * 3. define it on board.h - */ -#ifdef CONFIG_THERMISTOR_NCP15WB - *temp_ptr = ncp15wb_calculate_temp((uint16_t) temp_raw); -#else -#error "Unknown thermistor for ec_adc" - return EC_ERROR_UNKNOWN; -#endif - - return EC_SUCCESS; -} - -int ec_adc_get_val(int idx, int *temp_ptr) -{ - int ret; - int temp_c; - - if(idx < 0 || idx >= ADC_CH_COUNT) - return EC_ERROR_INVAL; - - ret = get_temp(idx, &temp_c); - if (ret == EC_SUCCESS) - *temp_ptr = C_TO_K(temp_c); - - return ret; -} diff --git a/driver/temp_sensor/ec_adc.h b/driver/temp_sensor/ec_adc.h deleted file mode 100644 index 8ff213e95d..0000000000 --- a/driver/temp_sensor/ec_adc.h +++ /dev/null @@ -1,24 +0,0 @@ -/* 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. - */ - -/* ec_adc which uses adc and thermistors module for Chrome EC - * Some EC has it's own ADC modules, define here EC's max ADC channels. - * We can consider every channel as a thermal sensor. - */ - -#ifndef __CROS_EC_TEMP_SENSOR_EC_ADC_H -#define __CROS_EC_TEMP_SENSOR_EC_ADC_H - -/** - * Get the latest value from the sensor. - * - * @param idx ADC channel to read. - * @param temp_ptr Destination for temperature in K. - * - * @return EC_SUCCESS if successful, non-zero if error. - */ -int ec_adc_get_val(int idx, int *temp_ptr); - -#endif /* __CROS_EC_TEMP_SENSOR_EC_ADC_H */ diff --git a/driver/temp_sensor/f75303.c b/driver/temp_sensor/f75303.c deleted file mode 100644 index 6b8895a252..0000000000 --- a/driver/temp_sensor/f75303.c +++ /dev/null @@ -1,93 +0,0 @@ -/* Copyright 2018 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. - */ - -/* F75303 temperature sensor module for Chrome EC */ - -#include "common.h" -#include "f75303.h" -#include "i2c.h" -#include "hooks.h" -#include "util.h" -#include "console.h" - -static int temps[F75303_IDX_COUNT]; -static int8_t fake_temp[F75303_IDX_COUNT] = {-1, -1, -1}; - -/** - * Read 8 bits register from temp sensor. - */ -static int raw_read8(const int offset, int *data) -{ - return i2c_read8(I2C_PORT_THERMAL, F75303_I2C_ADDR_FLAGS, - offset, data); -} - -static int get_temp(const int offset, int *temp) -{ - int rv; - int temp_raw = 0; - - rv = raw_read8(offset, &temp_raw); - if (rv != 0) - return rv; - - *temp = C_TO_K(temp_raw); - return EC_SUCCESS; -} - -int f75303_get_val(int idx, int *temp) -{ - if (idx < 0 || F75303_IDX_COUNT <= idx) - return EC_ERROR_INVAL; - - if (fake_temp[idx] != -1) { - *temp = C_TO_K(fake_temp[idx]); - return EC_SUCCESS; - } - - *temp = temps[idx]; - return EC_SUCCESS; -} - -static void f75303_sensor_poll(void) -{ - get_temp(F75303_TEMP_LOCAL, &temps[F75303_IDX_LOCAL]); - get_temp(F75303_TEMP_REMOTE1, &temps[F75303_IDX_REMOTE1]); - get_temp(F75303_TEMP_REMOTE2, &temps[F75303_IDX_REMOTE2]); -} -DECLARE_HOOK(HOOK_SECOND, f75303_sensor_poll, HOOK_PRIO_TEMP_SENSOR); - -static int f75303_set_fake_temp(int argc, char **argv) -{ - int index; - int value; - char *e; - - if (argc != 3) - return EC_ERROR_PARAM_COUNT; - - index = strtoi(argv[1], &e, 0); - if ((*e) || (index < 0) || (index >= F75303_IDX_COUNT)) - return EC_ERROR_PARAM1; - - if (!strcasecmp(argv[2], "off")) { - fake_temp[index] = -1; - ccprintf("Turn off fake temp mode for sensor %u.\n", index); - return EC_SUCCESS; - } - - value = strtoi(argv[2], &e, 0); - - if ((*e) || (value < 0) || (value > 100)) - return EC_ERROR_PARAM2; - - fake_temp[index] = value; - ccprintf("Force sensor %u = %uC.\n", index, value); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(f75303, f75303_set_fake_temp, - "<index> <value>|off", - "Set fake temperature of sensor f75303."); diff --git a/driver/temp_sensor/f75303.h b/driver/temp_sensor/f75303.h deleted file mode 100644 index bdfd2624f0..0000000000 --- a/driver/temp_sensor/f75303.h +++ /dev/null @@ -1,40 +0,0 @@ -/* Copyright 2018 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. - */ - -/* F75303 temperature sensor module for Chrome EC */ - -#ifndef __CROS_EC_F75303_H -#define __CROS_EC_F75303_H - -#ifdef BOARD_MUSHU -#define F75303_I2C_ADDR_FLAGS 0x4D -#else -#define F75303_I2C_ADDR_FLAGS 0x4C -#endif - -enum f75303_index { - F75303_IDX_LOCAL = 0, - F75303_IDX_REMOTE1, - F75303_IDX_REMOTE2, - F75303_IDX_COUNT, -}; - -/* F75303 register */ -#define F75303_TEMP_LOCAL 0x00 -#define F75303_TEMP_REMOTE1 0x01 -#define F75303_TEMP_REMOTE2 0x23 - -/** - * Get the last polled value of a sensor. - * - * @param idx Index to read. Idx indicates whether to read die - * temperature or external temperature. - * @param temp Destination for temperature in K. - * - * @return EC_SUCCESS if successful, non-zero if error. - */ -int f75303_get_val(int idx, int *temp); - -#endif /* __CROS_EC_F75303_H */ diff --git a/driver/temp_sensor/g753.c b/driver/temp_sensor/g753.c deleted file mode 100644 index 857263c161..0000000000 --- a/driver/temp_sensor/g753.c +++ /dev/null @@ -1,192 +0,0 @@ -/* Copyright 2019 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. - */ - -/* G753 temperature sensor module for Chrome EC */ - -#include "common.h" -#include "console.h" -#include "g753.h" -#include "gpio.h" -#include "i2c.h" -#include "hooks.h" -#include "util.h" - -static int temp_val_local; - -/** - * Determine whether the sensor is powered. - * - * @return non-zero the g753 sensor is powered. - */ -static int has_power(void) -{ -#ifdef CONFIG_TEMP_SENSOR_POWER_GPIO - return gpio_get_level(CONFIG_TEMP_SENSOR_POWER_GPIO); -#else - return 1; -#endif -} - -static int raw_read8(const int offset, int *data_ptr) -{ - return i2c_read8(I2C_PORT_THERMAL, G753_I2C_ADDR_FLAGS, - offset, data_ptr); -} - -#ifdef CONFIG_CMD_TEMP_SENSOR -static int raw_write8(const int offset, int data) -{ - return i2c_write8(I2C_PORT_THERMAL, G753_I2C_ADDR_FLAGS, - offset, data); -} -#endif - -static int get_temp(const int offset, int *temp_ptr) -{ - int rv; - int temp_raw = 0; - - rv = raw_read8(offset, &temp_raw); - if (rv < 0) - return rv; - - *temp_ptr = (int)(int8_t)temp_raw; - return EC_SUCCESS; -} - -#ifdef CONFIG_CMD_TEMP_SENSOR -static int set_temp(const int offset, int temp) -{ - if (temp < -127 || temp > 127) - return EC_ERROR_INVAL; - - return raw_write8(offset, (uint8_t)temp); -} -#endif - -int g753_get_val(int idx, int *temp_ptr) -{ - if (!has_power()) - return EC_ERROR_NOT_POWERED; - - switch (idx) { - case G753_IDX_INTERNAL: - *temp_ptr = temp_val_local; - break; - default: - return EC_ERROR_UNKNOWN; - } - - return EC_SUCCESS; -} - -static void temp_sensor_poll(void) -{ - if (!has_power()) - return; - - get_temp(G753_TEMP_LOCAL, &temp_val_local); - temp_val_local = C_TO_K(temp_val_local); -} -DECLARE_HOOK(HOOK_SECOND, temp_sensor_poll, HOOK_PRIO_TEMP_SENSOR); - -#ifdef CONFIG_CMD_TEMP_SENSOR -static void print_temps(const char *name, - const int temp_reg, - const int high_limit_reg) -{ - int value; - - ccprintf("%s:\n", name); - - if (get_temp(temp_reg, &value) == EC_SUCCESS) - ccprintf(" Temp: %3dC\n", value); - - if (get_temp(high_limit_reg, &value) == EC_SUCCESS) - ccprintf(" High Alarm: %3dC\n", value); - -} - -static int print_status(void) -{ - int value; - - if (!has_power()) { - ccprintf("ERROR: Temp sensor not powered.\n"); - return EC_ERROR_NOT_POWERED; - } - - print_temps("Local", G753_TEMP_LOCAL, - G753_LOCAL_TEMP_HIGH_LIMIT_R); - - ccprintf("\n"); - - if (raw_read8(G753_STATUS, &value) == EC_SUCCESS) - ccprintf("STATUS: %pb\n", BINARY_VALUE(value, 8)); - - if (raw_read8(G753_CONFIGURATION_R, &value) == EC_SUCCESS) - ccprintf("CONFIG: %pb\n", BINARY_VALUE(value, 8)); - - return EC_SUCCESS; -} - -static int command_g753(int argc, char **argv) -{ - char *command; - char *e; - int data; - int offset; - int rv; - - if (!has_power()) { - ccprintf("ERROR: Temp sensor not powered.\n"); - return EC_ERROR_NOT_POWERED; - } - - /* If no args just print status */ - if (argc == 1) - return print_status(); - - if (argc < 3) - return EC_ERROR_PARAM_COUNT; - - command = argv[1]; - offset = strtoi(argv[2], &e, 0); - if (*e || offset < 0 || offset > 255) - return EC_ERROR_PARAM2; - - if (!strcasecmp(command, "getbyte")) { - rv = raw_read8(offset, &data); - if (rv < 0) - return rv; - ccprintf("Byte at offset 0x%02x is %pb\n", - offset, BINARY_VALUE(data, 8)); - return rv; - } - - /* Remaining commands are of the form "g753 set-command offset data" */ - if (argc != 4) - return EC_ERROR_PARAM_COUNT; - - data = strtoi(argv[3], &e, 0); - if (*e) - return EC_ERROR_PARAM3; - - if (!strcasecmp(command, "settemp")) { - ccprintf("Setting 0x%02x to %dC\n", offset, data); - rv = set_temp(offset, data); - } else if (!strcasecmp(command, "setbyte")) { - ccprintf("Setting 0x%02x to 0x%02x\n", offset, data); - rv = raw_write8(offset, data); - } else - return EC_ERROR_PARAM1; - - return rv; -} -DECLARE_CONSOLE_COMMAND(g753, command_g753, - "[settemp|setbyte <offset> <value>] or [getbyte <offset>]. " - "Temps in Celsius.", - "Print g753 temp sensor status or set parameters."); -#endif diff --git a/driver/temp_sensor/g753.h b/driver/temp_sensor/g753.h deleted file mode 100644 index 04c412bfbb..0000000000 --- a/driver/temp_sensor/g753.h +++ /dev/null @@ -1,53 +0,0 @@ -/* Copyright 2019 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. - */ - -/* G753 temperature sensor module for Chrome EC */ - -#ifndef __CROS_EC_G753_H -#define __CROS_EC_G753_H - - -#define G753_I2C_ADDR_FLAGS 0x48 - -#define G753_IDX_INTERNAL 0 - -/* G753 register */ -#define G753_TEMP_LOCAL 0x00 -#define G753_STATUS 0x02 -#define G753_CONFIGURATION_R 0x03 -#define G753_CONVERSION_RATE_R 0x04 -#define G753_LOCAL_TEMP_HIGH_LIMIT_R 0x05 -#define G753_CONFIGURATION_W 0x09 -#define G753_CONVERSION_RATE_W 0x0A -#define G753_LOCAL_TEMP_HIGH_LIMIT_W 0x0B -#define G753_ONESHOT 0x0F -#define G753_Customer_Data_Log_Register_1 0x2D -#define G753_Customer_Data_Log_Register_2 0x2E -#define G753_Customer_Data_Log_Register_3 0x2F -#define G753_ALERT_MODE 0xBF -#define G753_CHIP_ID 0xFD -#define G753_VENDOR_ID 0xFE -#define G753_DEVICE_ID 0xFF - -/* Config register bits */ -#define G753_CONFIGURATION_STANDBY BIT(6) -#define G753_CONFIGURATION_ALERT_MASK BIT(7) - -/* Status register bits */ -#define G753_STATUS_LOCAL_TEMP_HIGH_ALARM BIT(6) -#define G753_STATUS_BUSY BIT(7) - -/** - * Get the last polled value of a sensor. - * - * @param idx Index to read. Idx indicates whether to read die - * temperature or external temperature. - * @param temp_ptr Destination for temperature in K. - * - * @return EC_SUCCESS if successful, non-zero if error. - */ -int g753_get_val(int idx, int *temp_ptr); - -#endif /* __CROS_EC_G753_H */ diff --git a/driver/temp_sensor/g78x.c b/driver/temp_sensor/g78x.c deleted file mode 100644 index aef13d3d68..0000000000 --- a/driver/temp_sensor/g78x.c +++ /dev/null @@ -1,238 +0,0 @@ -/* Copyright 2016 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. - */ - -/* G781/G782 temperature sensor module for Chrome EC */ - -#include "common.h" -#include "console.h" -#include "g78x.h" -#include "gpio.h" -#include "i2c.h" -#include "hooks.h" -#include "util.h" - -static int temp_val_local; -static int temp_val_remote1; -#ifdef CONFIG_TEMP_SENSOR_G782 -static int temp_val_remote2; -#endif - -/** - * Determine whether the sensor is powered. - * - * @return non-zero the g781/g782 sensor is powered. - */ -static int has_power(void) -{ -#ifdef CONFIG_TEMP_SENSOR_POWER_GPIO - return gpio_get_level(CONFIG_TEMP_SENSOR_POWER_GPIO); -#else - return 1; -#endif -} - -static int raw_read8(const int offset, int *data_ptr) -{ - return i2c_read8(I2C_PORT_THERMAL, G78X_I2C_ADDR_FLAGS, - offset, data_ptr); -} - -#ifdef CONFIG_CMD_TEMP_SENSOR -static int raw_write8(const int offset, int data) -{ - return i2c_write8(I2C_PORT_THERMAL, G78X_I2C_ADDR_FLAGS, - offset, data); -} -#endif - -static int get_temp(const int offset, int *temp_ptr) -{ - int rv; - int temp_raw = 0; - - rv = raw_read8(offset, &temp_raw); - if (rv < 0) - return rv; - - *temp_ptr = (int)(int8_t)temp_raw; - return EC_SUCCESS; -} - -#ifdef CONFIG_CMD_TEMP_SENSOR -static int set_temp(const int offset, int temp) -{ - if (temp < -127 || temp > 127) - return EC_ERROR_INVAL; - - return raw_write8(offset, (uint8_t)temp); -} -#endif - -int g78x_get_val(int idx, int *temp_ptr) -{ - if (!has_power()) - return EC_ERROR_NOT_POWERED; - - switch (idx) { - case G78X_IDX_INTERNAL: - *temp_ptr = temp_val_local; - break; - case G78X_IDX_EXTERNAL1: - *temp_ptr = temp_val_remote1; - break; -#ifdef CONFIG_TEMP_SENSOR_G782 - case G78X_IDX_EXTERNAL2: - *temp_ptr = temp_val_remote2; - break; -#endif - default: - return EC_ERROR_UNKNOWN; - } - - return EC_SUCCESS; -} - -static void temp_sensor_poll(void) -{ - if (!has_power()) - return; - - get_temp(G78X_TEMP_LOCAL, &temp_val_local); - temp_val_local = C_TO_K(temp_val_local); - - get_temp(G78X_TEMP_REMOTE1, &temp_val_remote1); - temp_val_remote1 = C_TO_K(temp_val_remote1); - -#ifdef CONFIG_TEMP_SENSOR_G782 - get_temp(G78X_TEMP_REMOTE2, &temp_val_remote2); - temp_val_remote2 = C_TO_K(temp_val_remote2); -#endif -} -DECLARE_HOOK(HOOK_SECOND, temp_sensor_poll, HOOK_PRIO_TEMP_SENSOR); - -#ifdef CONFIG_CMD_TEMP_SENSOR -static void print_temps(const char *name, - const int temp_reg, - const int therm_limit_reg, - const int high_limit_reg, - const int low_limit_reg) -{ - int value; - - ccprintf("%s:\n", name); - - if (get_temp(temp_reg, &value) == EC_SUCCESS) - ccprintf(" Temp: %3dC\n", value); - - if (get_temp(therm_limit_reg, &value) == EC_SUCCESS) - ccprintf(" Therm Trip: %3dC\n", value); - - if (get_temp(high_limit_reg, &value) == EC_SUCCESS) - ccprintf(" High Alarm: %3dC\n", value); - - if (get_temp(low_limit_reg, &value) == EC_SUCCESS) - ccprintf(" Low Alarm: %3dC\n", value); -} - -static int print_status(void) -{ - int value; - - if (!has_power()) { - ccprintf("ERROR: Temp sensor not powered.\n"); - return EC_ERROR_NOT_POWERED; - } - - print_temps("Local", G78X_TEMP_LOCAL, - G78X_LOCAL_TEMP_THERM_LIMIT, - G78X_LOCAL_TEMP_HIGH_LIMIT_R, - G78X_LOCAL_TEMP_LOW_LIMIT_R); - - print_temps("Remote1", G78X_TEMP_REMOTE1, - G78X_REMOTE1_TEMP_THERM_LIMIT, - G78X_REMOTE1_TEMP_HIGH_LIMIT_R, - G78X_REMOTE1_TEMP_LOW_LIMIT_R); - -#ifdef CONFIG_TEMP_SENSOR_G782 - print_temps("Remote2", G78X_TEMP_REMOTE1, - G78X_REMOTE2_TEMP_THERM_LIMIT, - G78X_REMOTE2_TEMP_HIGH_LIMIT_R, - G78X_REMOTE2_TEMP_LOW_LIMIT_R); -#endif - - ccprintf("\n"); - - if (raw_read8(G78X_STATUS, &value) == EC_SUCCESS) - ccprintf("STATUS: %pb\n", BINARY_VALUE(value, 8)); - -#ifdef CONFIG_TEMP_SENSOR_G782 - if (raw_read8(G78X_STATUS1, &value) == EC_SUCCESS) - ccprintf("STATUS1: %pb\n", BINARY_VALUE(value, 8)); -#endif - - if (raw_read8(G78X_CONFIGURATION_R, &value) == EC_SUCCESS) - ccprintf("CONFIG: %pb\n", BINARY_VALUE(value, 8)); - - return EC_SUCCESS; -} - -static int command_g78x(int argc, char **argv) -{ - char *command; - char *e; - int data; - int offset; - int rv; - - if (!has_power()) { - ccprintf("ERROR: Temp sensor not powered.\n"); - return EC_ERROR_NOT_POWERED; - } - - /* If no args just print status */ - if (argc == 1) - return print_status(); - - if (argc < 3) - return EC_ERROR_PARAM_COUNT; - - command = argv[1]; - offset = strtoi(argv[2], &e, 0); - if (*e || offset < 0 || offset > 255) - return EC_ERROR_PARAM2; - - if (!strcasecmp(command, "getbyte")) { - rv = raw_read8(offset, &data); - if (rv < 0) - return rv; - ccprintf("Byte at offset 0x%02x is %pb\n", - offset, BINARY_VALUE(data, 8)); - return rv; - } - - /* Remaining commands are of the form "g78x set-command offset data" */ - if (argc != 4) - return EC_ERROR_PARAM_COUNT; - - data = strtoi(argv[3], &e, 0); - if (*e) - return EC_ERROR_PARAM3; - - if (!strcasecmp(command, "settemp")) { - ccprintf("Setting 0x%02x to %dC\n", offset, data); - rv = set_temp(offset, data); - } else if (!strcasecmp(command, "setbyte")) { - ccprintf("Setting 0x%02x to 0x%02x\n", offset, data); - rv = raw_write8(offset, data); - } else - return EC_ERROR_PARAM1; - - return rv; -} -DECLARE_CONSOLE_COMMAND(g78x, command_g78x, - "[settemp|setbyte <offset> <value>] or [getbyte <offset>]. " - "Temps in Celsius.", - "Print g781/g782 temp sensor status or set parameters."); -#endif diff --git a/driver/temp_sensor/g78x.h b/driver/temp_sensor/g78x.h deleted file mode 100644 index fdd987fcbd..0000000000 --- a/driver/temp_sensor/g78x.h +++ /dev/null @@ -1,140 +0,0 @@ -/* Copyright 2016 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. - */ - -/* G781/G782 temperature sensor module for Chrome EC */ - -#ifndef __CROS_EC_G78X_H -#define __CROS_EC_G78X_H - -#if defined(CONFIG_TEMP_SENSOR_G781) && defined(CONFIG_TEMP_SENSOR_G782) -#error Cannot support both G781 and G782 together! -#endif - -#define G78X_I2C_ADDR_FLAGS 0x4C - -#define G78X_IDX_INTERNAL 0 -#define G78X_IDX_EXTERNAL1 1 -#define G78X_IDX_EXTERNAL2 2 - -#if defined(CONFIG_TEMP_SENSOR_G781) -/* G781 register */ -#define G78X_TEMP_LOCAL 0x00 -#define G78X_TEMP_REMOTE1 0x01 -#define G78X_STATUS 0x02 -#define G78X_CONFIGURATION_R 0x03 -#define G78X_CONVERSION_RATE_R 0x04 -#define G78X_LOCAL_TEMP_HIGH_LIMIT_R 0x05 -#define G78X_LOCAL_TEMP_LOW_LIMIT_R 0x06 -#define G78X_REMOTE1_TEMP_HIGH_LIMIT_R 0x07 -#define G78X_REMOTE1_TEMP_LOW_LIMIT_R 0x08 -#define G78X_CONFIGURATION_W 0x09 -#define G78X_CONVERSION_RATE_W 0x0a -#define G78X_LOCAL_TEMP_HIGH_LIMIT_W 0x0b -#define G78X_LOCAL_TEMP_LOW_LIMIT_W 0x0c -#define G78X_REMOTE1_TEMP_HIGH_LIMIT_W 0x0d -#define G78X_REMOTE1_TEMP_LOW_LIMIT_W 0x0e -#define G78X_ONESHOT 0x0f -#define G78X_REMOTE1_TEMP_EXTENDED 0x10 -#define G78X_REMOTE1_TEMP_OFFSET_HIGH 0x11 -#define G78X_REMOTE1_TEMP_OFFSET_EXTD 0x12 -#define G78X_REMOTE1_T_HIGH_LIMIT_EXTD 0x13 -#define G78X_REMOTE1_T_LOW_LIMIT_EXTD 0x14 -#define G78X_REMOTE1_TEMP_THERM_LIMIT 0x19 -#define G78X_LOCAL_TEMP_THERM_LIMIT 0x20 -#define G78X_THERM_HYSTERESIS 0x21 -#define G78X_ALERT_FAULT_QUEUE_CODE 0x22 -#define G78X_MANUFACTURER_ID 0xFE -#define G78X_DEVICE_ID 0xFF - -/* Config register bits */ -#define G78X_CONFIGURATION_STANDBY BIT(6) -#define G78X_CONFIGURATION_ALERT_MASK BIT(7) - -/* Status register bits */ -#define G78X_STATUS_LOCAL_TEMP_THERM_ALARM BIT(0) -#define G78X_STATUS_REMOTE1_TEMP_THERM_ALARM BIT(1) -#define G78X_STATUS_REMOTE1_TEMP_FAULT BIT(2) -#define G78X_STATUS_REMOTE1_TEMP_LOW_ALARM BIT(3) -#define G78X_STATUS_REMOTE1_TEMP_HIGH_ALARM BIT(4) -#define G78X_STATUS_LOCAL_TEMP_LOW_ALARM BIT(5) -#define G78X_STATUS_LOCAL_TEMP_HIGH_ALARM BIT(6) -#define G78X_STATUS_BUSY BIT(7) - -#elif defined(CONFIG_TEMP_SENSOR_G782) -/* G782 register */ -#define G78X_TEMP_LOCAL 0x00 -#define G78X_TEMP_REMOTE1 0x01 -#define G78X_TEMP_REMOTE2 0x02 -#define G78X_STATUS 0x03 -#define G78X_CONFIGURATION_R 0x04 -#define G78X_CONFIGURATION_W 0x04 -#define G78X_CONVERSION_RATE_R 0x05 -#define G78X_CONVERSION_RATE_W 0x05 -#define G78X_LOCAL_TEMP_HIGH_LIMIT_R 0x06 -#define G78X_LOCAL_TEMP_HIGH_LIMIT_W 0x06 -#define G78X_LOCAL_TEMP_LOW_LIMIT_R 0x07 -#define G78X_LOCAL_TEMP_LOW_LIMIT_W 0x07 -#define G78X_REMOTE1_TEMP_HIGH_LIMIT_R 0x08 -#define G78X_REMOTE1_TEMP_HIGH_LIMIT_W 0x08 -#define G78X_REMOTE1_TEMP_LOW_LIMIT_R 0x09 -#define G78X_REMOTE1_TEMP_LOW_LIMIT_W 0x09 -#define G78X_REMOTE2_TEMP_HIGH_LIMIT_R 0x0a -#define G78X_REMOTE2_TEMP_HIGH_LIMIT_W 0x0a -#define G78X_REMOTE2_TEMP_LOW_LIMIT_R 0x0b -#define G78X_REMOTE2_TEMP_LOW_LIMIT_W 0x0b -#define G78X_ONESHOT 0x0c -#define G78X_REMOTE1_TEMP_EXTENDED 0x0d -#define G78X_REMOTE1_TEMP_OFFSET_HIGH 0x0e -#define G78X_REMOTE1_TEMP_OFFSET_EXTD 0x0f -#define G78X_REMOTE1_T_HIGH_LIMIT_EXTD 0x10 -#define G78X_REMOTE1_T_LOW_LIMIT_EXTD 0x11 -#define G78X_REMOTE1_TEMP_THERM_LIMIT 0x12 -#define G78X_REMOTE2_TEMP_EXTENDED 0x13 -#define G78X_REMOTE2_TEMP_OFFSET_HIGH 0x14 -#define G78X_REMOTE2_TEMP_OFFSET_EXTD 0x15 -#define G78X_REMOTE2_T_HIGH_LIMIT_EXTD 0x16 -#define G78X_REMOTE2_T_LOW_LIMIT_EXTD 0x17 -#define G78X_REMOTE2_TEMP_THERM_LIMIT 0x18 -#define G78X_STATUS1 0x19 -#define G78X_LOCAL_TEMP_THERM_LIMIT 0x20 -#define G78X_THERM_HYSTERESIS 0x21 -#define G78X_ALERT_FAULT_QUEUE_CODE 0x22 -#define G78X_MANUFACTURER_ID 0xFE -#define G78X_DEVICE_ID 0xFF - -/* Config register bits */ -#define G78X_CONFIGURATION_REMOTE2_DIS BIT(5) -#define G78X_CONFIGURATION_STANDBY BIT(6) -#define G78X_CONFIGURATION_ALERT_MASK BIT(7) - -/* Status register bits */ -#define G78X_STATUS_LOCAL_TEMP_LOW_ALARM BIT(0) -#define G78X_STATUS_LOCAL_TEMP_HIGH_ALARM BIT(1) -#define G78X_STATUS_LOCAL_TEMP_THERM_ALARM BIT(2) -#define G78X_STATUS_REMOTE2_TEMP_THERM_ALARM BIT(3) -#define G78X_STATUS_REMOTE1_TEMP_THERM_ALARM BIT(4) -#define G78X_STATUS_REMOTE2_TEMP_FAULT BIT(5) -#define G78X_STATUS_REMOTE1_TEMP_FAULT BIT(6) -#define G78X_STATUS_BUSY BIT(7) - -/* Status1 register bits */ -#define G78X_STATUS_REMOTE2_TEMP_LOW_ALARM BIT(4) -#define G78X_STATUS_REMOTE2_TEMP_HIGH_ALARM BIT(5) -#define G78X_STATUS_REMOTE1_TEMP_LOW_ALARM BIT(6) -#define G78X_STATUS_REMOTE1_TEMP_HIGH_ALARM BIT(7) -#endif - -/** - * Get the last polled value of a sensor. - * - * @param idx Index to read. Idx indicates whether to read die - * temperature or external temperature. - * @param temp_ptr Destination for temperature in K. - * - * @return EC_SUCCESS if successful, non-zero if error. - */ -int g78x_get_val(int idx, int *temp_ptr); - -#endif /* __CROS_EC_G78X_H */ diff --git a/driver/temp_sensor/oti502.c b/driver/temp_sensor/oti502.c deleted file mode 100644 index 8a420363e8..0000000000 --- a/driver/temp_sensor/oti502.c +++ /dev/null @@ -1,67 +0,0 @@ -/* Copyright 2019 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. - */ - -/* OTI502 temperature sensor module for Chrome EC */ - -#include "common.h" -#include "console.h" -#include "oti502.h" -#include "i2c.h" -#include "hooks.h" -#include "util.h" - -static int temp_val_ambient; /* Ambient is chip temperature*/ -static int temp_val_object; /* Object is IR temperature */ - -static int oti502_read_block(const int offset, uint8_t *data, int len) -{ - return i2c_read_block(I2C_PORT_THERMAL, OTI502_I2C_ADDR_FLAGS, - offset, data, len); -} - -int oti502_get_val(int idx, int *temp_ptr) -{ - switch (idx) { - case OTI502_IDX_AMBIENT: - *temp_ptr = temp_val_ambient; - break; - case OTI502_IDX_OBJECT: - *temp_ptr = temp_val_object; - break; - default: - return EC_ERROR_UNKNOWN; - } - - return EC_SUCCESS; -} - -static void temp_sensor_poll(void) -{ - uint8_t temp_val[6]; - - memset(temp_val, 0, sizeof(temp_val)); - - oti502_read_block(0x80, temp_val, sizeof(temp_val)); - - if (temp_val[2] >= 0x80) { - /* Treat temperature as 0 degree C if temperature is negative*/ - temp_val_ambient = 0; - ccprintf("Temperature ambient is negative !\n"); - } else { - temp_val_ambient = ((temp_val[1] << 8) + temp_val[0]) / 200; - temp_val_ambient = C_TO_K(temp_val_ambient); - } - - if (temp_val[5] >= 0x80) { - /* Treat temperature as 0 degree C if temperature is negative*/ - temp_val_object = 0; - ccprintf("Temperature object is negative !\n"); - } else { - temp_val_object = ((temp_val[4] << 8) + temp_val[5]) / 200; - temp_val_object = C_TO_K(temp_val_object); - } -} -DECLARE_HOOK(HOOK_SECOND, temp_sensor_poll, HOOK_PRIO_TEMP_SENSOR); - diff --git a/driver/temp_sensor/oti502.h b/driver/temp_sensor/oti502.h deleted file mode 100644 index 4e846282c1..0000000000 --- a/driver/temp_sensor/oti502.h +++ /dev/null @@ -1,27 +0,0 @@ -/* Copyright 2019 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. - */ - -/* OTI502 temperature sensor module for Chrome EC */ - -#ifndef __CROS_EC_OTI502_H -#define __CROS_EC_OTI502_H - -#define OTI502_I2C_ADDR_FLAGS 0x10 - -#define OTI502_IDX_AMBIENT 0 -#define OTI502_IDX_OBJECT 1 - -/** - * Get the last polled value of a sensor. - * - * @param idx Index to read. Idx indicates whether to read die - * temperature or external temperature. - * @param temp_ptr Destination for temperature in K. - * - * @return EC_SUCCESS if successful, non-zero if error. - */ -int oti502_get_val(int idx, int *temp_ptr); - -#endif /* __CROS_EC_OTI502_H */ diff --git a/driver/temp_sensor/sb_tsi.c b/driver/temp_sensor/sb_tsi.c deleted file mode 100644 index ba47bcb727..0000000000 --- a/driver/temp_sensor/sb_tsi.c +++ /dev/null @@ -1,41 +0,0 @@ -/* Copyright 2016 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. - */ - -/* - * SB-TSI: SB Temperature Sensor Interface. - * This is an I2C temp sensor on the AMD Stony Ridge FT4 SOC. - */ - -#include "chipset.h" -#include "common.h" -#include "console.h" -#include "gpio.h" -#include "hooks.h" -#include "i2c.h" -#include "sb_tsi.h" -#include "util.h" - -static int raw_read8(const int offset, int *data_ptr) -{ - return i2c_read8(I2C_PORT_THERMAL_AP, SB_TSI_I2C_ADDR_FLAGS, - offset, data_ptr); -} - -int sb_tsi_get_val(int idx, int *temp_ptr) -{ - int ret; - /* There is only one temp sensor on the FT4 */ - if (idx != 0) - return EC_ERROR_PARAM1; - /* FT4 SB-TSI sensor only powered in S0 */ - if (!chipset_in_state(CHIPSET_STATE_ON)) - return EC_ERROR_NOT_POWERED; - /* Read the value over I2C */ - ret = raw_read8(SB_TSI_TEMP_H, temp_ptr); - if (ret) - return ret; - *temp_ptr = C_TO_K(*temp_ptr); - return EC_SUCCESS; -} diff --git a/driver/temp_sensor/sb_tsi.h b/driver/temp_sensor/sb_tsi.h deleted file mode 100644 index b7113dbc70..0000000000 --- a/driver/temp_sensor/sb_tsi.h +++ /dev/null @@ -1,46 +0,0 @@ -/* Copyright 2016 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. - */ - -/* - * SB-TSI: SB Temperature Sensor Interface. - * This is an I2C temp sensor on the AMD Stony Ridge FT4 SOC. - */ - -#ifndef __CROS_EC_SB_TSI_H -#define __CROS_EC_SB_TSI_H - -#define SB_TSI_I2C_ADDR_FLAGS 0x4C - -/* G781 register */ -#define SB_TSI_TEMP_H 0x01 -#define SB_TSI_STATUS 0x02 -#define SB_TSI_CONFIG_1 0x03 -#define SB_TSI_UPDATE_RATE 0x04 -#define SB_TSI_HIGH_TEMP_THRESHOLD_H 0x07 -#define SB_TSI_LOW_TEMP_THRESHOLD_H 0x08 -#define SB_TSI_CONFIG_2 0x09 -#define SB_TSI_TEMP_L 0x10 -#define SB_TSI_TEMP_OFFSET_H 0x11 -#define SB_TSI_TEMP_OFFSET_L 0x12 -#define SB_TSI_HIGH_TEMP_THRESHOLD_L 0x13 -#define SB_TSI_LOW_TEMP_THRESHOLD_L 0x14 -#define SB_TSI_TIMEOUT_CONFIG 0x22 -#define SB_TSI_PSTATE_LIMIT_CONFIG 0x2F -#define SB_TSI_ALERT_THRESHOLD 0x32 -#define SB_TSI_ALERT_CONFIG 0xBF -#define SB_TSI_MANUFACTURE_ID 0xFE -#define SB_TSI_REVISION 0xFF - -/** - * Get the value of a sensor in K. - * - * @param idx Index to read. Only 0 is valid for sb_tsi. - * @param temp_ptr Destination for temperature in K. - * - * @return EC_SUCCESS if successful, non-zero if error. - */ -int sb_tsi_get_val(int idx, int *temp_ptr); - -#endif /* __CROS_EC_SB_TSI_H */ diff --git a/driver/temp_sensor/thermistor.c b/driver/temp_sensor/thermistor.c deleted file mode 100644 index ffa780cb07..0000000000 --- a/driver/temp_sensor/thermistor.c +++ /dev/null @@ -1,273 +0,0 @@ -/* Copyright 2018 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. - */ - -/* - * Common thermistor code for Chrome EC. See ./thermistor.md for table of - * resistance of a 47kΩ B4050 thermistor - */ - -#include "adc.h" -#include "common.h" -#include "gpio.h" -#include "temp_sensor/thermistor.h" -#include "util.h" - -int thermistor_linear_interpolate(uint16_t mv, - const struct thermistor_info *info) -{ - const struct thermistor_data_pair *data = info->data; - int v_high = 0, v_low = 0, t_low, t_high, num_steps; - int head, tail, mid = 0; - - /* We need at least two points to form a line. */ - ASSERT(info->num_pairs >= 2); - - /* - * If input value is out of bounds return the lowest or highest - * value in the data sets provided. - */ - if (mv > data[0].mv * info->scaling_factor) - return data[0].temp; - else if (mv < data[info->num_pairs - 1].mv * info->scaling_factor) - return data[info->num_pairs - 1].temp; - - head = 0; - tail = info->num_pairs - 1; - while (head != tail) { - mid = (head + tail) / 2; - v_high = data[mid].mv * info->scaling_factor; - v_low = data[mid + 1].mv * info->scaling_factor; - - if ((mv <= v_high) && (mv >= v_low)) - break; - else if (mv > v_high) - tail = mid; - else if (mv < v_low) - head = mid + 1; - } - - t_low = data[mid].temp; - t_high = data[mid + 1].temp; - - /* - * The obvious way of doing this is to figure out how many mV per - * degree are in between the two points (mv_per_deg_c), and then how - * many of those exist between the input voltage and voltage of - * lower temperature : - * 1. mv_per_deg_c = (v_high - v_low) / (t_high - t_low) - * 2. num_steps = (v_high - mv) / mv_per_deg_c - * 3. result = t_low + num_steps - * - * Combine #1 and #2 to mitigate precision loss due to integer division. - */ - num_steps = ((v_high - mv) * (t_high - t_low)) / (v_high - v_low); - return t_low + num_steps; -} - -#if defined(CONFIG_STEINHART_HART_3V3_51K1_47K_4050B) || \ - defined(CONFIG_STEINHART_HART_3V3_13K7_47K_4050B) || \ - defined(CONFIG_STEINHART_HART_6V0_51K1_47K_4050B) || \ - defined(CONFIG_STEINHART_HART_3V0_22K6_47K_4050B) || \ - defined(CONFIG_STEINHART_HART_3V3_30K9_47K_4050B) || \ - defined(CONFIG_ZEPHYR) -int thermistor_get_temperature(int idx_adc, int *temp_ptr, - const struct thermistor_info *info) -{ - int mv; - -#ifdef CONFIG_TEMP_SENSOR_POWER_GPIO - /* - * If the power rail for the thermistor circuit is not enabled, then - * need to ignore any ADC measurments. - */ - if (!gpio_get_level(CONFIG_TEMP_SENSOR_POWER_GPIO)) - return EC_ERROR_NOT_POWERED; -#endif /* CONFIG_TEMP_SENSOR_POWER_GPIO */ - mv = adc_read_channel(idx_adc); - if (mv < 0) - return EC_ERROR_UNKNOWN; - - *temp_ptr = thermistor_linear_interpolate(mv, info); - *temp_ptr = C_TO_K(*temp_ptr); - return EC_SUCCESS; -} -#endif - -#ifdef CONFIG_STEINHART_HART_3V3_51K1_47K_4050B -/* - * Data derived from Steinhart-Hart equation in a resistor divider circuit with - * Vdd=3300mV, R = 51.1Kohm, and thermistor (B = 4050, T0 = 298.15 K, nominal - * resistance (R0) = 47Kohm). - */ -#define THERMISTOR_SCALING_FACTOR_51_47 11 -static const struct thermistor_data_pair thermistor_data_51_47[] = { - { 2484 / THERMISTOR_SCALING_FACTOR_51_47, 0 }, - { 2142 / THERMISTOR_SCALING_FACTOR_51_47, 10 }, - { 1767 / THERMISTOR_SCALING_FACTOR_51_47, 20 }, - { 1400 / THERMISTOR_SCALING_FACTOR_51_47, 30 }, - { 1072 / THERMISTOR_SCALING_FACTOR_51_47, 40 }, - { 802 / THERMISTOR_SCALING_FACTOR_51_47, 50 }, - { 593 / THERMISTOR_SCALING_FACTOR_51_47, 60 }, - { 436 / THERMISTOR_SCALING_FACTOR_51_47, 70 }, - { 321 / THERMISTOR_SCALING_FACTOR_51_47, 80 }, - { 276 / THERMISTOR_SCALING_FACTOR_51_47, 85 }, - { 237 / THERMISTOR_SCALING_FACTOR_51_47, 90 }, - { 204 / THERMISTOR_SCALING_FACTOR_51_47, 95 }, - { 177 / THERMISTOR_SCALING_FACTOR_51_47, 100 }, -}; - -static const struct thermistor_info thermistor_info_51_47 = { - .scaling_factor = THERMISTOR_SCALING_FACTOR_51_47, - .num_pairs = ARRAY_SIZE(thermistor_data_51_47), - .data = thermistor_data_51_47, -}; - -int get_temp_3v3_51k1_47k_4050b(int idx_adc, int *temp_ptr) -{ - return thermistor_get_temperature(idx_adc, temp_ptr, - &thermistor_info_51_47); -} -#endif /* CONFIG_STEINHART_HART_3V3_51K1_47K_4050B */ - -#ifdef CONFIG_STEINHART_HART_3V3_13K7_47K_4050B -/* - * Data derived from Steinhart-Hart equation in a resistor divider circuit with - * Vdd=3300mV, R = 13.7Kohm, and thermistor (B = 4050, T0 = 298.15 K, nominal - * resistance (R0) = 47Kohm). - */ -#define THERMISTOR_SCALING_FACTOR_13_47 13 -static const struct thermistor_data_pair thermistor_data_13_47[] = { - { 3033 / THERMISTOR_SCALING_FACTOR_13_47, 0 }, - { 2882 / THERMISTOR_SCALING_FACTOR_13_47, 10 }, - { 2677 / THERMISTOR_SCALING_FACTOR_13_47, 20 }, - { 2420 / THERMISTOR_SCALING_FACTOR_13_47, 30 }, - { 2119 / THERMISTOR_SCALING_FACTOR_13_47, 40 }, - { 1799 / THERMISTOR_SCALING_FACTOR_13_47, 50 }, - { 1485 / THERMISTOR_SCALING_FACTOR_13_47, 60 }, - { 1197 / THERMISTOR_SCALING_FACTOR_13_47, 70 }, - { 947 / THERMISTOR_SCALING_FACTOR_13_47, 80 }, - { 839 / THERMISTOR_SCALING_FACTOR_13_47, 85 }, - { 741 / THERMISTOR_SCALING_FACTOR_13_47, 90 }, - { 653 / THERMISTOR_SCALING_FACTOR_13_47, 95 }, - { 576 / THERMISTOR_SCALING_FACTOR_13_47, 100 }, -}; - -static const struct thermistor_info thermistor_info_13_47 = { - .scaling_factor = THERMISTOR_SCALING_FACTOR_13_47, - .num_pairs = ARRAY_SIZE(thermistor_data_13_47), - .data = thermistor_data_13_47, -}; - -int get_temp_3v3_13k7_47k_4050b(int idx_adc, int *temp_ptr) -{ - return thermistor_get_temperature(idx_adc, temp_ptr, - &thermistor_info_13_47); -} -#endif /* CONFIG_STEINHART_HART_3V3_13K7_47K_4050B */ - -#ifdef CONFIG_STEINHART_HART_6V0_51K1_47K_4050B -/* - * Data derived from Steinhart-Hart equation in a resistor divider circuit with - * Vdd=6000mV, R = 51.1Kohm, and thermistor (B = 4050, T0 = 298.15 K, nominal - * resistance (R0) = 47Kohm). - */ -#define THERMISTOR_SCALING_FACTOR_6V0_51_47 18 -static const struct thermistor_data_pair thermistor_data_6v0_51_47[] = { - { 4517 / THERMISTOR_SCALING_FACTOR_6V0_51_47, 0 }, - { 3895 / THERMISTOR_SCALING_FACTOR_6V0_51_47, 10 }, - { 3214 / THERMISTOR_SCALING_FACTOR_6V0_51_47, 20 }, - { 2546 / THERMISTOR_SCALING_FACTOR_6V0_51_47, 30 }, - { 1950 / THERMISTOR_SCALING_FACTOR_6V0_51_47, 40 }, - { 1459 / THERMISTOR_SCALING_FACTOR_6V0_51_47, 50 }, - { 1079 / THERMISTOR_SCALING_FACTOR_6V0_51_47, 60 }, - { 794 / THERMISTOR_SCALING_FACTOR_6V0_51_47, 70 }, - { 584 / THERMISTOR_SCALING_FACTOR_6V0_51_47, 80 }, - { 502 / THERMISTOR_SCALING_FACTOR_6V0_51_47, 85 }, - { 432 / THERMISTOR_SCALING_FACTOR_6V0_51_47, 90 }, - { 372 / THERMISTOR_SCALING_FACTOR_6V0_51_47, 95 }, - { 322 / THERMISTOR_SCALING_FACTOR_6V0_51_47, 100 }, -}; - -static const struct thermistor_info thermistor_info_6v0_51_47 = { - .scaling_factor = THERMISTOR_SCALING_FACTOR_6V0_51_47, - .num_pairs = ARRAY_SIZE(thermistor_data_6v0_51_47), - .data = thermistor_data_6v0_51_47, -}; - -int get_temp_6v0_51k1_47k_4050b(int idx_adc, int *temp_ptr) -{ - return thermistor_get_temperature(idx_adc, temp_ptr, - &thermistor_info_6v0_51_47); -} -#endif /* CONFIG_STEINHART_HART_6V0_51K1_47K_4050B */ - -#ifdef CONFIG_STEINHART_HART_3V0_22K6_47K_4050B -/* - * Data derived from Steinhart-Hart equation in a resistor divider circuit with - * Vdd=3000mV, R = 22.6Kohm, and thermistor (B = 4050, T0 = 298.15 K, nominal - * resistance (R0) = 47Kohm). - */ -#define THERMISTOR_SCALING_FACTOR_22_47 11 -static const struct thermistor_data_pair thermistor_data_22_47[] = { - { 2619 / THERMISTOR_SCALING_FACTOR_22_47, 0 }, - { 2421 / THERMISTOR_SCALING_FACTOR_22_47, 10 }, - { 2168 / THERMISTOR_SCALING_FACTOR_22_47, 20 }, - { 1875 / THERMISTOR_SCALING_FACTOR_22_47, 30 }, - { 1563 / THERMISTOR_SCALING_FACTOR_22_47, 40 }, - { 1262 / THERMISTOR_SCALING_FACTOR_22_47, 50 }, - { 994 / THERMISTOR_SCALING_FACTOR_22_47, 60 }, - { 769 / THERMISTOR_SCALING_FACTOR_22_47, 70 }, - { 588 / THERMISTOR_SCALING_FACTOR_22_47, 80 }, - { 513 / THERMISTOR_SCALING_FACTOR_22_47, 85 }, - { 448 / THERMISTOR_SCALING_FACTOR_22_47, 90 }, - { 390 / THERMISTOR_SCALING_FACTOR_22_47, 95 }, - { 340 / THERMISTOR_SCALING_FACTOR_22_47, 100 }, -}; - -static const struct thermistor_info thermistor_info_22_47 = { - .scaling_factor = THERMISTOR_SCALING_FACTOR_22_47, - .num_pairs = ARRAY_SIZE(thermistor_data_22_47), - .data = thermistor_data_22_47, -}; - -int get_temp_3v0_22k6_47k_4050b(int idx_adc, int *temp_ptr) -{ - return thermistor_get_temperature(idx_adc, temp_ptr, - &thermistor_info_22_47); -} -#endif /* CONFIG_STEINHART_HART_3V0_22K6_47K_4050B */ - -#ifdef CONFIG_STEINHART_HART_3V3_30K9_47K_4050B -/* - * Data derived from Steinhart-Hart equation in a resistor divider circuit with - * Vdd=3300mV, R = 30.9Kohm, and thermistor (B = 4050, T0 = 298.15 K, nominal - * resistance (R0) = 47Kohm). - */ -#define THERMISTOR_SCALING_FACTOR_31_47 11 -static const struct thermistor_data_pair thermistor_data_31_47[] = { - { 2753 / THERMISTOR_SCALING_FACTOR_31_47, 0 }, - { 2487 / THERMISTOR_SCALING_FACTOR_31_47, 10 }, - { 2165 / THERMISTOR_SCALING_FACTOR_31_47, 20 }, - { 1813 / THERMISTOR_SCALING_FACTOR_31_47, 30 }, - { 1145 / THERMISTOR_SCALING_FACTOR_31_47, 50 }, - { 878 / THERMISTOR_SCALING_FACTOR_31_47, 60 }, - { 665 / THERMISTOR_SCALING_FACTOR_31_47, 70 }, - { 500 / THERMISTOR_SCALING_FACTOR_31_47, 80 }, - { 375 / THERMISTOR_SCALING_FACTOR_31_47, 90 }, - { 282 / THERMISTOR_SCALING_FACTOR_31_47, 100 }, -}; - -static const struct thermistor_info thermistor_info_31_47 = { - .scaling_factor = THERMISTOR_SCALING_FACTOR_31_47, - .num_pairs = ARRAY_SIZE(thermistor_data_31_47), - .data = thermistor_data_31_47, -}; - -int get_temp_3v3_30k9_47k_4050b(int idx_adc, int *temp_ptr) -{ - return thermistor_get_temperature(idx_adc, temp_ptr, - &thermistor_info_31_47); -} -#endif /* CONFIG_STEINHART_HART_3V3_30K9_47K_4050B */ diff --git a/driver/temp_sensor/thermistor.md b/driver/temp_sensor/thermistor.md deleted file mode 100644 index bb9faa04ef..0000000000 --- a/driver/temp_sensor/thermistor.md +++ /dev/null @@ -1,106 +0,0 @@ -We used the following resistance table for a 47kΩ B4050 thermistor in the -[thermistor.c](./thermistor.c) tables. - -C° | kΩ ---- | ----- -0 | 155.7 -1 | 147.9 -2 | 140.6 -3 | 133.7 -4 | 127.2 -5 | 121.0 -6 | 115.1 -7 | 109.6 -8 | 104.3 -9 | 99.31 -10 | 94.6 -11 | 90.13 -12 | 85.89 -13 | 81.87 -14 | 78.07 -15 | 74.45 -16 | 71.02 -17 | 67.77 -18 | 64.68 -19 | 61.75 -20 | 58.97 -21 | 56.32 -22 | 53.81 -23 | 51.43 -24 | 49.16 -25 | 47.0 -26 | 44.95 -27 | 42.99 -28 | 41.13 -29 | 39.36 -30 | 37.68 -31 | 36.07 -32 | 34.54 -33 | 33.08 -34 | 31.69 -35 | 30.36 -36 | 29.1 -37 | 27.9 -38 | 26.75 -39 | 25.65 -40 | 24.61 -41 | 23.61 -42 | 22.66 -43 | 21.75 -44 | 20.88 -45 | 20.05 -46 | 19.26 -47 | 18.5 -48 | 17.78 -49 | 17.09 -50 | 16.43 -51 | 15.8 -52 | 15.2 -53 | 14.62 -54 | 14.07 -55 | 13.54 -56 | 13.03 -57 | 12.55 -58 | 12.09 -59 | 11.64 -60 | 11.21 -61 | 10.8 -62 | 10.41 -63 | 10.04 -64 | 9.676 -65 | 9.331 -66 | 8.999 -67 | 8.68 -68 | 8.374 -69 | 8.081 -70 | 7.799 -71 | 7.528 -72 | 7.268 -73 | 7.018 -74 | 6.777 -75 | 6.546 -76 | 6.324 -77 | 6.111 -78 | 5.906 -79 | 5.708 -80 | 5.518 -81 | 5.335 -82 | 5.16 -83 | 4.99 -84 | 4.827 -85 | 4.671 -86 | 4.519 -87 | 4.374 -88 | 4.233 -89 | 4.098 -90 | 3.968 -91 | 3.842 -92 | 3.721 -93 | 3.605 -94 | 3.492 -95 | 3.384 -96 | 3.279 -97 | 3.179 -98 | 3.082 -99 | 2.988 -100 | 2.898 diff --git a/driver/temp_sensor/thermistor_ncp15wb.c b/driver/temp_sensor/thermistor_ncp15wb.c deleted file mode 100644 index dba06ee326..0000000000 --- a/driver/temp_sensor/thermistor_ncp15wb.c +++ /dev/null @@ -1,100 +0,0 @@ -/* 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. - */ - -/* NCP15WB thermistor module for Chrome EC */ - -#include "common.h" -#include "temp_sensor/thermistor.h" -#include "util.h" - -/* - * ADC-to-temp conversion assumes recommended thermistor / resistor - * configuration (NCP15WB* / 24.9K) with a 10-bit ADC. - * For 50C through 100C, use linear interpolation from discreet points - * in table below. For temps < 50C, use a simplified linear function. - */ -#define ADC_DISCREET_RANGE_START_TEMP 50 -/* 10 bit ADC result corresponding to START_TEMP */ -#define ADC_DISCREET_RANGE_START_RESULT 407 - -#define ADC_DISCREET_RANGE_LIMIT_TEMP 100 -/* 10 bit ADC result corresponding to LIMIT_TEMP */ -#define ADC_DISCREET_RANGE_LIMIT_RESULT 107 - -/* Table entries in steppings of 5C */ -#define ADC_DISCREET_RANGE_STEP 5 - -/* Discreet range ADC results (9 bit) per temperature, in 5 degree steps */ -static const uint8_t adc_result[] = { - 203, /* 50 C */ - 178, /* 55 C */ - 157, /* 60 C */ - 138, /* 65 C */ - 121, /* 70 C */ - 106, /* 75 C */ - 93, /* 80 C */ - 81, /* 85 C */ - 70, /* 90 C */ - 61, /* 95 C */ - 53, /* 100 C */ -}; - -/* - * From 20C (reasonable lower limit of temperatures we care about accuracy) - * to 50C, the temperature curve is roughly linear, so we don't need to include - * data points in our table. - */ -#define adc_to_temp(result) (ADC_DISCREET_RANGE_START_TEMP - \ - (((result) - ADC_DISCREET_RANGE_START_RESULT) * 3 + 16) / 32) - -/* Convert ADC result (10 bit) to temperature in celsius */ -int ncp15wb_calculate_temp(uint16_t adc) -{ - int temp; - int head, tail, mid; - uint8_t delta, step; - - /* Is ADC result in linear range? */ - if (adc >= ADC_DISCREET_RANGE_START_RESULT) - temp = adc_to_temp(adc); - /* Hotter than our discreet range limit? */ - else if (adc <= ADC_DISCREET_RANGE_LIMIT_RESULT) - temp = ADC_DISCREET_RANGE_LIMIT_TEMP; - /* We're in the discreet range */ - else { - /* Table uses 9 bit ADC values */ - adc /= 2; - - /* Binary search to find proper table entry */ - head = 0; - tail = ARRAY_SIZE(adc_result) - 1; - while (head != tail) { - mid = (head + tail) / 2; - if (adc_result[mid] >= adc && - adc_result[mid+1] < adc) - break; - if (adc_result[mid] > adc) - head = mid + 1; - else - tail = mid; - } - - /* Now fit between table entries using linear interpolation. */ - if (head != tail) { - delta = adc_result[mid] - adc_result[mid + 1]; - step = ((adc_result[mid] - adc) * - ADC_DISCREET_RANGE_STEP + delta / 2) / delta; - } else { - /* Edge case where adc = max */ - mid = head; - step = 0; - } - - temp = ADC_DISCREET_RANGE_START_TEMP + - ADC_DISCREET_RANGE_STEP * mid + step; - } - - return temp; -} diff --git a/driver/temp_sensor/tmp006.c b/driver/temp_sensor/tmp006.c deleted file mode 100644 index e4794ccc4a..0000000000 --- a/driver/temp_sensor/tmp006.c +++ /dev/null @@ -1,504 +0,0 @@ -/* Copyright 2014 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. - */ - -/* TMP006 temperature sensor module for Chrome EC */ - -#include "common.h" -#include "console.h" -#include "gpio.h" -#include "hooks.h" -#include "host_command.h" -#include "i2c.h" -#include "math.h" -#include "task.h" -#include "temp_sensor.h" -#include "tmp006.h" -#include "util.h" - -/* Console output macros */ -#define CPUTS(outstr) cputs(CC_THERMAL, outstr) -#define CPRINTS(format, args...) cprints(CC_THERMAL, format, ## args) - -/* - * Alg 0 was what's in the TMP006 User's Guide. Alg 1 is Alg 0, but with - * some filters applied to the Tdie input and Tobj output (see - * crosbug.com/p/32260). - */ -#define ALGORITHM_NUM 1 -#define ALGORITHM_PARAMS 12 - -/* Flags for tdata->fail */ -#define FAIL_INIT BIT(0) /* Just initialized */ -#define FAIL_POWER BIT(1) /* Sensor not powered */ -#define FAIL_I2C BIT(2) /* I2C communication error */ -#define FAIL_NOT_READY BIT(3) /* Data not ready */ - -/* State and conversion factors to track for each sensor */ -struct tmp006_data_t { - /* chip info */ - int16_t v_raw; /* TMP006_REG_VOBJ */ - int16_t t_raw0; /* TMP006_REG_TDIE */ - int fail; /* Fail flags; non-zero if last read failed */ - /* calibration params */ - float s0, a1, a2; /* Sensitivity factors */ - float b0, b1, b2; /* Self-heating correction */ - float c2; /* Seebeck effect */ - float d0, d1, ds; /* Tdie filter and slope adjustment */ - float e0, e1; /* Tobj output filter */ - /* FIR filter stages */ - float tdie1, tobj1; -}; -static struct tmp006_data_t tmp006_data[TMP006_COUNT]; - -/* Default state and conversion factors */ -static const struct tmp006_data_t tmp006_data_default = { - .fail = FAIL_INIT, - - /* Alg 0 params from User's Guide */ - .s0 = 0.0f, /* zero == "uncalibrated" */ - .a1 = 1.75e-3f, - .a2 = -1.678e-5f, - .b0 = -2.94e-5f, - .b1 = -5.7e-7f, - .b2 = 4.63e-9f, - .c2 = 13.4f, - - /* Additional Alg 1 filter params */ - .d0 = 0.2f, - .d1 = 0.8f, - .ds = 1.48e-4, - .e0 = 0.1f, - .e1 = 0.9f, -}; - -static int tmp006_has_power(int idx) -{ -#ifdef CONFIG_TEMP_SENSOR_POWER_GPIO - return gpio_get_level(CONFIG_TEMP_SENSOR_POWER_GPIO); -#else - return 1; -#endif -} - -static void tmp006_poll_sensor(int sensor_id) -{ - struct tmp006_data_t *tdata = tmp006_data + sensor_id; - int t, v, rv; - int addr_flags = tmp006_sensors[sensor_id].addr_flags; - - /* Invalidate the filter history if there is any error */ - if (tdata->fail) { - tdata->tdie1 = 0.0f; - tdata->tobj1 = 0.0; - } - - if (!tmp006_has_power(sensor_id)) { - tdata->fail |= FAIL_POWER; - return; - } - - /* - * If sensor has just initialized and/or has lost power, wait for - * data ready; otherwise, we read garbage data. - */ - if (tdata->fail & (FAIL_POWER | FAIL_INIT)) { - rv = i2c_read16(TMP006_PORT(addr_flags), - TMP006_REG(addr_flags), - TMP006_REG_CONFIG, &v); - if (rv) { - tdata->fail |= FAIL_I2C; - return; - } else if (!(v & 0x80)) { - /* Bit 7 is the Data Ready bit */ - tdata->fail |= FAIL_NOT_READY; - return; - } - } - - rv = i2c_read16(TMP006_PORT(addr_flags), - TMP006_REG(addr_flags), - TMP006_REG_TDIE, &t); - if (rv) { - tdata->fail |= FAIL_I2C; - return; - } - - rv = i2c_read16(TMP006_PORT(addr_flags), - TMP006_REG(addr_flags), - TMP006_REG_VOBJ, &v); - if (rv) { - tdata->fail |= FAIL_I2C; - return; - } - - tdata->t_raw0 = t; - tdata->v_raw = v; - - tdata->fail = 0; -} - -/*****************************************************************************/ -/* Hooks */ - -static void tmp006_init(void) -{ - int i; - - for (i = 0; i < TMP006_COUNT; ++i) - tmp006_data[i] = tmp006_data_default; -} -DECLARE_HOOK(HOOK_INIT, tmp006_init, HOOK_PRIO_DEFAULT); - -static void tmp006_poll(void) -{ - int i; - - for (i = 0; i < TMP006_COUNT; ++i) - tmp006_poll_sensor(i); -} -DECLARE_HOOK(HOOK_SECOND, tmp006_poll, HOOK_PRIO_TEMP_SENSOR); - -/*****************************************************************************/ -/* Interface to the rest of the EC */ - -/* This just returns Tdie */ -static int tmp006_read_die_temp_k(const struct tmp006_data_t *tdata, - int *temp_ptr) -{ - if (tdata->fail) - return EC_ERROR_UNKNOWN; - - /* Tdie reg is signed 1/128 degrees C, resolution 1/32 degrees */ - *temp_ptr = (int)tdata->t_raw0 / 128 + 273; - return EC_SUCCESS; -} - -/* - * This uses Tdie and Vobj and a bunch of magic parameters to calculate the - * object temperature, Tobj. - */ -static int tmp006_read_object_temp_k(struct tmp006_data_t *tdata, - int *temp_ptr) -{ - float tdie, vobj; - float tx, s, vos, vx, fv, tobj, t4; - float tdie_filtered, tdie_slope, tobj_filtered; - - if (tdata->fail) - return EC_ERROR_UNKNOWN; - - if (!tdata->s0) - return EC_ERROR_NOT_CALIBRATED; - - /* Tdie reg is signed 1/128 degrees C, resolution 1/32 degrees - * We need degrees K */ - tdie = (float)tdata->t_raw0 / 128.0f + 273.15f; - /* Vobj reg is signed int, LSB = 156.25 nV - * We need volts */ - vobj = (float)tdata->v_raw / 156.25f * 1e-9f; - - /* Alg1: apply filter to tdie. If tdie1 is 0K, initialize it. */ - if (tdata->tdie1 == 0.0f) - tdata->tdie1 = tdie; - tdie_filtered = tdata->d0 * tdie + tdata->d1 * tdata->tdie1; - tdie_slope = tdie - tdie_filtered; - /* Remember the current Tdie for next time */ - tdata->tdie1 = tdie; - - /* Calculate according to TMP006 users guide. */ - tx = tdie - 298.15f; - /* s is the sensitivity */ - s = tdata->s0 * (1.0f + tdata->a1 * tx + tdata->a2 * tx * tx); - /* vos is the offset voltage */ - vos = tdata->b0 + tdata->b1 * tx + tdata->b2 * tx * tx; - /* Alg1: use Tdie FIR here */ - vx = vobj - vos + tdie_slope * tdata->ds; - /* fv is Seebeck coefficient f(vobj) */ - fv = vx + tdata->c2 * vx * vx; - - t4 = tdie * tdie * tdie * tdie + fv / s; - tobj = sqrtf(sqrtf(t4)); - - /* Alg1: apply another filter on the calculated tobj. */ - if (tdata->tobj1 == 0.0f) - tdata->tobj1 = tobj; - - tobj_filtered = tdata->e0 * tobj + tdata->e1 * tdata->tobj1; - tdata->tobj1 = tobj; - - /* return integer degrees K */ - *temp_ptr = tobj_filtered; - - return EC_SUCCESS; -} - -int tmp006_get_val(int idx, int *temp_ptr) -{ - /* - * Note: idx is a thermal sensor index, where the top N-1 bits are the - * TMP006 index and the bottom bit is (0=die, 1=remote). - */ - int tidx = idx >> 1; - struct tmp006_data_t *tdata = tmp006_data + tidx; - - if (tdata->fail & FAIL_POWER) { - /* - * Sensor isn't powered, or hasn't successfully provided data - * since being powered. Keep reporting not-powered until - * we get good data (which will clear FAIL_POWER) or there is - * an I2C error. - */ - return (tdata->fail & FAIL_I2C) ? EC_ERROR_UNKNOWN : - EC_ERROR_NOT_POWERED; - } - - /* Check the low bit to determine which temperature to read. */ - if ((idx & 0x1) == 0) - return tmp006_read_die_temp_k(tdata, temp_ptr); - else - return tmp006_read_object_temp_k(tdata, temp_ptr); -} - -/*****************************************************************************/ -/* Host commands */ - -enum ec_status tmp006_get_calibration(struct host_cmd_handler_args *args) -{ - const struct ec_params_tmp006_get_calibration *p = args->params; - struct ec_response_tmp006_get_calibration_v1 *r1 = args->response; - const struct tmp006_data_t *tdata; - - if (p->index >= TMP006_COUNT) - return EC_RES_INVALID_PARAM; - - tdata = tmp006_data + p->index; - - r1->algorithm = ALGORITHM_NUM; - r1->num_params = ALGORITHM_PARAMS; - r1->val[0] = tdata->s0; - r1->val[1] = tdata->a1; - r1->val[2] = tdata->a2; - r1->val[3] = tdata->b0; - r1->val[4] = tdata->b1; - r1->val[5] = tdata->b2; - r1->val[6] = tdata->c2; - r1->val[7] = tdata->d0; - r1->val[8] = tdata->d1; - r1->val[9] = tdata->ds; - r1->val[10] = tdata->e0; - r1->val[11] = tdata->e1; - - args->response_size = sizeof(*r1) + - r1->num_params * sizeof(r1->val[0]); - - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_TMP006_GET_CALIBRATION, - tmp006_get_calibration, - EC_VER_MASK(1)); - -enum ec_status tmp006_set_calibration(struct host_cmd_handler_args *args) -{ - const struct ec_params_tmp006_set_calibration_v1 *p1 = args->params; - struct tmp006_data_t *tdata; - - if (p1->index >= TMP006_COUNT) - return EC_RES_INVALID_PARAM; - - /* We only have one algorithm today */ - if (p1->algorithm != ALGORITHM_NUM || - p1->num_params != ALGORITHM_PARAMS) - return EC_RES_INVALID_PARAM; - - tdata = tmp006_data + p1->index; - - tdata->s0 = p1->val[0]; - tdata->a1 = p1->val[1]; - tdata->a2 = p1->val[2]; - tdata->b0 = p1->val[3]; - tdata->b1 = p1->val[4]; - tdata->b2 = p1->val[5]; - tdata->c2 = p1->val[6]; - tdata->d0 = p1->val[7]; - tdata->d1 = p1->val[8]; - tdata->ds = p1->val[9]; - tdata->e0 = p1->val[10]; - tdata->e1 = p1->val[11]; - - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_TMP006_SET_CALIBRATION, - tmp006_set_calibration, - EC_VER_MASK(1)); - -enum ec_status tmp006_get_raw(struct host_cmd_handler_args *args) -{ - const struct ec_params_tmp006_get_raw *p = args->params; - struct ec_response_tmp006_get_raw *r = args->response; - const struct tmp006_data_t *tdata; - - if (p->index >= TMP006_COUNT) - return EC_RES_INVALID_PARAM; - - tdata = tmp006_data + p->index; - - /* Vobj reg is signed int, LSB = 156.25 nV - * response units are nV */ - r->v = ((int)tdata->v_raw * 15625) / 100; - - /* Tdie reg is signed 1/128 degrees C, resolution 1/32 degrees - * response units are 1/100 degrees K */ - r->t = ((int)tdata->t_raw0 * 100) / 128 + 27315; - - args->response_size = sizeof(*r); - - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_TMP006_GET_RAW, - tmp006_get_raw, - EC_VER_MASK(0)); - -/*****************************************************************************/ -/* Console commands */ - -#ifdef CONFIG_CMD_TEMP_SENSOR -/** - * Print temperature info for a sensor; used by console command. - */ -static int tmp006_print(int idx) -{ - int vraw, v; - int traw, t; - int rv; - int d; - int addr_flags = tmp006_sensors[idx].addr_flags; - - - ccprintf("Debug data from %s:\n", tmp006_sensors[idx].name); - - if (!tmp006_has_power(idx)) { - ccputs("Sensor powered off.\n"); - return EC_ERROR_UNKNOWN; - } - - rv = i2c_read16(TMP006_PORT(addr_flags), - TMP006_REG(addr_flags), - TMP006_REG_MANUFACTURER_ID, &d); - if (rv) - return rv; - ccprintf(" Manufacturer ID: 0x%04x\n", d); - - rv = i2c_read16(TMP006_PORT(addr_flags), - TMP006_REG(addr_flags), - TMP006_REG_DEVICE_ID, &d); - ccprintf(" Device ID: 0x%04x\n", d); - - rv = i2c_read16(TMP006_PORT(addr_flags), - TMP006_REG(addr_flags), - TMP006_REG_CONFIG, &d); - ccprintf(" Config: 0x%04x\n", d); - - rv = i2c_read16(TMP006_PORT(addr_flags), - TMP006_REG(addr_flags), - TMP006_REG_VOBJ, &vraw); - - v = ((int)vraw * 15625) / 100; - ccprintf(" Voltage: 0x%04x = %d nV\n", vraw, v); - - rv = i2c_read16(TMP006_PORT(addr_flags), - TMP006_REG(addr_flags), - TMP006_REG_TDIE, &traw); - t = (int)traw; - ccprintf(" Temperature: 0x%04x = %d.%02d C\n", - traw, t / 128, t > 0 ? t % 128 : 128 - (t % 128)); - - return EC_SUCCESS; -} - -static int command_sensor_info(int argc, char **argv) -{ - int i; - int rv, rv1; - int a = 0, b = TMP006_COUNT; - - if (argc > 1) { - char *e = 0; - i = strtoi(argv[1], &e, 0); - if (*e || i < 0 || i >= TMP006_COUNT) - return EC_ERROR_PARAM1; - a = i; - b = i + 1; - } - - rv1 = EC_SUCCESS; - for (i = a; i < b; i++) { - rv = tmp006_print(i); - if (rv != EC_SUCCESS) - rv1 = rv; - cflush(); - } - - return rv1; -} -DECLARE_CONSOLE_COMMAND(tmp006, command_sensor_info, - "[ <index> ]", - "Print TMP006 sensors"); -#endif - -/* Disable the t6cal command until/unless we have FP support in printf */ -#if 0 -static int command_t6cal(int argc, char **argv) -{ - struct tmp006_data_t *tdata; - char *e; - int v; - int i; - - if (argc < 2) { - ccprintf("# Name S0 b0" - " b1 b2\n"); - for (i = 0; i < TMP006_COUNT; i++) { - tdata = tmp006_data + i; - ccprintf("%d %-11s" - "%7de-17 %7de-8 %7de-10 %7de-12\n", - i, tmp006_sensors[i].name, - (int)(tdata->s0 * 1e17f), - (int)(tdata->b0 * 1e8f), - (int)(tdata->b1 * 1e10f), - (int)(tdata->b2 * 1e12f)); - } - - return EC_SUCCESS; - } - - if (argc != 4) - return EC_ERROR_PARAM_COUNT; - - i = strtoi(argv[1], &e, 0); - if (*e || i < 0 || i >= TMP006_COUNT) - return EC_ERROR_PARAM1; - tdata = tmp006_data + i; - - v = strtoi(argv[3], &e, 0); - if (*e) - return EC_ERROR_PARAM3; - - if (!strcasecmp(argv[2], "s0")) - tdata->s0 = (float)v * 1e-17f; - else if (!strcasecmp(argv[2], "b0")) - tdata->b0 = (float)v * 1e-8f; - else if (!strcasecmp(argv[2], "b1")) - tdata->b1 = (float)v * 1e-10f; - else if (!strcasecmp(argv[2], "b2")) - tdata->b2 = (float)v * 1e-12f; - else - return EC_ERROR_PARAM2; - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(t6cal, command_t6cal, - "[<index> <coeff_name> <radix>]", - "Set/print TMP006 calibration"); -#endif diff --git a/driver/temp_sensor/tmp006.h b/driver/temp_sensor/tmp006.h deleted file mode 100644 index 594dbc711a..0000000000 --- a/driver/temp_sensor/tmp006.h +++ /dev/null @@ -1,43 +0,0 @@ -/* Copyright 2014 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. - */ - -/* TMP006 temperature sensor module for Chrome EC */ - -#ifndef __CROS_EC_TMP006_H -#define __CROS_EC_TMP006_H - -/* Registers within the TMP006 chip */ -#define TMP006_REG_VOBJ 0x00 -#define TMP006_REG_TDIE 0x01 -#define TMP006_REG_CONFIG 0x02 -#define TMP006_REG_MANUFACTURER_ID 0xfe -#define TMP006_REG_DEVICE_ID 0xff - -/* I2C address components */ -#define TMP006_ADDR(PORT, REG) ((PORT << 16) + REG) -#define TMP006_PORT(ADDR) (ADDR >> 16) -#define TMP006_REG(ADDR) (ADDR & 0xffff) - -struct tmp006_t { - const char *name; - int addr_flags; /* I2C address formed by TMP006_ADDR macro. */ -}; - -/* Names and addresses of the sensors we have */ -extern const struct tmp006_t tmp006_sensors[]; - -/** - * Get the last polled value of a sensor. - * - * @param idx Index to read. The low bit in idx indicates whether - * to read die temperature or object temperature. The - * other bits serve as internal index to tmp006 module. - * @param temp_ptr Destination for temperature in K. - * - * @return EC_SUCCESS if successful, non-zero if error. - */ -int tmp006_get_val(int idx, int *temp_ptr); - -#endif /* __CROS_EC_TMP006_H */ diff --git a/driver/temp_sensor/tmp112.c b/driver/temp_sensor/tmp112.c deleted file mode 100644 index 4da5c4e0e8..0000000000 --- a/driver/temp_sensor/tmp112.c +++ /dev/null @@ -1,124 +0,0 @@ -/* Copyright 2016 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. - */ - -/* TMP112 temperature sensor module for Chrome EC */ - -#include "common.h" -#include "console.h" -#include "tmp112.h" -#include "i2c.h" -#include "hooks.h" -#include "math_util.h" -#include "util.h" - -#define TMP112_RESOLUTION 12 -#define TMP112_SHIFT1 (16 - TMP112_RESOLUTION) -#define TMP112_SHIFT2 (TMP112_RESOLUTION - 8) - -#define CPRINTS(format, args...) cprints(CC_THERMAL, format, ## args) - -static int temp_mk_local[TMP112_COUNT]; - -static int raw_read16(int sensor, const int offset, int *data_ptr) -{ -#ifdef CONFIG_I2C_BUS_MAY_BE_UNPOWERED - /* - * Don't try to read if the port is unpowered - */ - if (!board_is_i2c_port_powered(tmp112_sensors[sensor].i2c_port)) - return EC_ERROR_NOT_POWERED; -#endif - return i2c_read16(tmp112_sensors[sensor].i2c_port, - tmp112_sensors[sensor].i2c_addr_flags, - offset, data_ptr); -} - -static int raw_write16(int sensor, const int offset, int data) -{ -#ifdef CONFIG_I2C_BUS_MAY_BE_UNPOWERED - /* - * Don't try to write if the port is unpowered - */ - if (!board_is_i2c_port_powered(tmp112_sensors[sensor].i2c_port)) - return EC_ERROR_NOT_POWERED; -#endif - return i2c_write16(tmp112_sensors[sensor].i2c_port, - tmp112_sensors[sensor].i2c_addr_flags, - offset, data); -} - -static int get_reg_temp(int sensor, int *temp_ptr) -{ - int rv; - int temp_raw = 0; - - rv = raw_read16(sensor, TMP112_REG_TEMP, &temp_raw); - if (rv) - return rv; - - *temp_ptr = (int)(int16_t)temp_raw; - return EC_SUCCESS; -} - -static inline int tmp112_reg_to_mk(int16_t reg) -{ - int temp_mc; - - temp_mc = (((reg >> TMP112_SHIFT1) * 1000) >> TMP112_SHIFT2); - - return MILLI_CELSIUS_TO_MILLI_KELVIN(temp_mc); -} - -int tmp112_get_val_k(int idx, int *temp_k_ptr) -{ - if (idx >= TMP112_COUNT) - return EC_ERROR_INVAL; - - *temp_k_ptr = MILLI_KELVIN_TO_KELVIN(temp_mk_local[idx]); - return EC_SUCCESS; -} - -int tmp112_get_val_mk(int idx, int *temp_mk_ptr) -{ - if (idx >= TMP112_COUNT) - return EC_ERROR_INVAL; - - *temp_mk_ptr = temp_mk_local[idx]; - return EC_SUCCESS; -} - -static void tmp112_poll(void) -{ - int s; - int temp_reg = 0; - - for (s = 0; s < TMP112_COUNT; s++) { - if (get_reg_temp(s, &temp_reg) == EC_SUCCESS) - temp_mk_local[s] = tmp112_reg_to_mk(temp_reg); - } -} -DECLARE_HOOK(HOOK_SECOND, tmp112_poll, HOOK_PRIO_TEMP_SENSOR); - -void tmp112_init(void) -{ - int tmp, s, rv; - int set_mask, clr_mask; - - /* 12 bit mode */ - set_mask = (3 << 5); - - /* not oneshot mode */ - clr_mask = BIT(7); - - for (s = 0; s < TMP112_COUNT; s++) { - rv = raw_read16(s, TMP112_REG_CONF, &tmp); - if (rv != EC_SUCCESS) { - CPRINTS("TMP112-%d: Failed to init (rv %d)", s, rv); - continue; - } - raw_write16(s, TMP112_REG_CONF, (tmp & ~clr_mask) | set_mask); - } -} -DECLARE_HOOK(HOOK_INIT, tmp112_init, HOOK_PRIO_DEFAULT); diff --git a/driver/temp_sensor/tmp112.h b/driver/temp_sensor/tmp112.h deleted file mode 100644 index d1b97b138c..0000000000 --- a/driver/temp_sensor/tmp112.h +++ /dev/null @@ -1,66 +0,0 @@ -/* Copyright 2016 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. - */ - -#ifndef __CROS_EC_TMP112_H -#define __CROS_EC_TMP112_H - -#include "i2c.h" - -#define TMP112_I2C_ADDR_FLAGS0 (0x48 | I2C_FLAG_BIG_ENDIAN) -#define TMP112_I2C_ADDR_FLAGS1 (0x49 | I2C_FLAG_BIG_ENDIAN) -#define TMP112_I2C_ADDR_FLAGS2 (0x4A | I2C_FLAG_BIG_ENDIAN) -#define TMP112_I2C_ADDR_FLAGS3 (0x4B | I2C_FLAG_BIG_ENDIAN) - -#define TMP112_REG_TEMP 0x00 -#define TMP112_REG_CONF 0x01 -#define TMP112_REG_HYST 0x02 -#define TMP112_REG_MAX 0x03 - -/* - * I2C port and address information for all the board TMP112 sensors should be - * defined in an array of the following structures, with an enum tmp112_sensor - * indexing the array. The enum tmp112_sensor shall end with a TMP112_COUNT - * defining the maximum number of sensors for the board. - */ - -struct tmp112_sensor_t { - int i2c_port; - int i2c_addr_flags; -}; - -extern const struct tmp112_sensor_t tmp112_sensors[]; - -/** - * Get the last polled value of a sensor. - * - * @param idx Index to read, from board's enum tmp112_sensor - * definition - * - * @param temp_k_ptr Destination for temperature in K. - * - * @return EC_SUCCESS if successful, non-zero if error. - */ -int tmp112_get_val_k(int idx, int *temp_k_ptr); - -/** - * Get the last polled value of a sensor. - * - * @param idx Index to read, from board's enum tmp112_sensor - * definition - * - * @param temp_mk_ptr Destination for temperature in mK. - * - * @return EC_SUCCESS if successful, non-zero if error. - */ -int tmp112_get_val_mk(int idx, int *temp_mk_ptr); - -/** - * Init the sensors. Note, this will run automatically on HOOK_INIT, but is - * made available for boards which may not always power the sensor in all - * states. - */ -void tmp112_init(void); - -#endif /* __CROS_EC_TMP112_H */ diff --git a/driver/temp_sensor/tmp411.c b/driver/temp_sensor/tmp411.c deleted file mode 100644 index ef22052da8..0000000000 --- a/driver/temp_sensor/tmp411.c +++ /dev/null @@ -1,330 +0,0 @@ -/* Copyright 2017 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. - */ - -/* TMP411 temperature sensor module for Chrome EC */ - -#include "common.h" -#include "console.h" -#include "tmp411.h" -#include "gpio.h" -#include "i2c.h" -#include "hooks.h" -#include "util.h" - -static int temp_val_local; -static int temp_val_remote1; -static uint8_t is_sensor_shutdown; - -/** - * Determine whether the sensor is powered. - * - * @return non-zero the tmp411 sensor is powered. - */ -static int has_power(void) -{ -#ifdef CONFIG_TEMP_SENSOR_POWER_GPIO - return gpio_get_level(CONFIG_TEMP_SENSOR_POWER_GPIO); -#else - return !is_sensor_shutdown; -#endif -} - -static int raw_read8(const int offset, int *data_ptr) -{ - return i2c_read8(I2C_PORT_THERMAL, TMP411_I2C_ADDR, offset, data_ptr); -} - -static int raw_write8(const int offset, int data) -{ - return i2c_write8(I2C_PORT_THERMAL, TMP411_I2C_ADDR, offset, data); -} - -static int get_temp(const int offset, int *temp_ptr) -{ - int rv; - int temp_raw = 0; - - rv = raw_read8(offset, &temp_raw); - if (rv < 0) - return rv; - - *temp_ptr = (int)(int8_t)temp_raw; - return EC_SUCCESS; -} - -#ifdef CONFIG_CMD_TEMP_SENSOR -static int tmp411_set_temp(const int offset, int temp) -{ - if (temp < -127 || temp > 127) - return EC_ERROR_INVAL; - - return raw_write8(offset, (uint8_t)temp); -} -#endif - -int tmp411_get_val(int idx, int *temp_ptr) -{ - if (!has_power()) - return EC_ERROR_NOT_POWERED; - - switch (idx) { - case TMP411_IDX_LOCAL: - *temp_ptr = temp_val_local; - break; - case TMP411_IDX_REMOTE1: - *temp_ptr = temp_val_remote1; - break; - default: - return EC_ERROR_UNKNOWN; - } - - return EC_SUCCESS; -} - -static int tmp411_shutdown(uint8_t want_shutdown) -{ - int ret, value; - - if (want_shutdown == is_sensor_shutdown) - return EC_SUCCESS; - - ret = raw_read8(TMP411_CONFIGURATION1_R, &value); - if (ret < 0) { - ccprintf("ERROR: Temp sensor I2C read8 error.\n"); - return ret; - } - - if (want_shutdown && !(value & TMP411_CONFIG1_RUN_L)) { - /* tmp411 is running, and want it to shutdown */ - /* CONFIG REG1 BIT6: 0=Run, 1=Shutdown */ - /* shut it down */ - value |= TMP411_CONFIG1_RUN_L; - ret = raw_write8(TMP411_CONFIGURATION1_R, value); - } else if (!want_shutdown && (value & TMP411_CONFIG1_RUN_L)) { - /* tmp411 is shutdown, and want turn it on */ - value &= ~TMP411_CONFIG1_RUN_L; - ret = raw_write8(TMP411_CONFIGURATION1_R, value); - } - /* else, the current setting is exactly what you want */ - - is_sensor_shutdown = want_shutdown; - return ret; -} - -static int tmp411_set_therm_mode(void) -{ - int ret = 0; - int data = 0; - - ret = raw_read8(TMP411_CONFIGURATION1_R, &data); - if (ret) - return EC_ERROR_UNKNOWN; - - data |= TMP411_CONFIG1_MODE; - ret = raw_write8(TMP411_CONFIGURATION1_W, data); - if (ret) - return EC_ERROR_UNKNOWN; - - return EC_SUCCESS; -} - -int tmp411_set_therm_limit(int channel, int limit_c, int hysteresis) -{ - int ret = 0; - int reg = 0; - - if (channel >= TMP411_CHANNEL_COUNT) - return EC_ERROR_INVAL; - - if (hysteresis > TMP411_HYSTERESIS_HIGH_LIMIT || - hysteresis < TMP411_HYSTERESIS_LOW_LIMIT) - return EC_ERROR_INVAL; - - /* hysteresis must be less than high limit */ - if (hysteresis > limit_c) - return EC_ERROR_INVAL; - - if (tmp411_set_therm_mode() != EC_SUCCESS) - return EC_ERROR_UNKNOWN; - - switch (channel) { - case TMP411_CHANNEL_LOCAL: - reg = TMP411_LOCAL_HIGH_LIMIT_W; - break; - case TMP411_CHANNEL_REMOTE1: - reg = TMP411_REMOTE1_HIGH_LIMIT_W; - break; - } - - ret = raw_write8(reg, limit_c); - if (ret) - return EC_ERROR_UNKNOWN; - - ret = raw_write8(TMP411_THERM_HYSTERESIS, hysteresis); - if (ret) - return EC_ERROR_UNKNOWN; - - return EC_SUCCESS; -} - -static void tmp411_temp_sensor_poll(void) -{ - int temp_c; - - if (!has_power()) - return; - - if (get_temp(TMP411_LOCAL, &temp_c) == EC_SUCCESS) - temp_val_local = C_TO_K(temp_c); - - if (get_temp(TMP411_REMOTE1, &temp_c) == EC_SUCCESS) - temp_val_remote1 = C_TO_K(temp_c); - -} -DECLARE_HOOK(HOOK_SECOND, tmp411_temp_sensor_poll, HOOK_PRIO_TEMP_SENSOR); - -#ifdef CONFIG_CMD_TEMP_SENSOR -static void print_temps( - const char *name, - const int tmp411_temp_reg, - const int tmp411_therm_limit_reg, - const int tmp411_high_limit_reg, - const int tmp411_low_limit_reg) -{ - int value; - - if (!has_power()) { - ccprintf(" TMP411 is shutdown\n"); - return; - } - - ccprintf("%s:\n", name); - - if (get_temp(tmp411_temp_reg, &value) == EC_SUCCESS) - ccprintf(" Temp %3dC\n", value); - - if (get_temp(tmp411_therm_limit_reg, &value) == EC_SUCCESS) - ccprintf(" Therm Trip %3dC\n", value); - - if (get_temp(tmp411_high_limit_reg, &value) == EC_SUCCESS) - ccprintf(" High Alarm %3dC\n", value); - - if (get_temp(tmp411_low_limit_reg, &value) == EC_SUCCESS) - ccprintf(" Low Alarm %3dC\n", value); -} - -static int print_status(void) -{ - int value; - - print_temps("Local", TMP411_LOCAL, - TMP411_LOCAL_THERM_LIMIT, - TMP411_LOCAL_HIGH_LIMIT_R, - TMP411_LOCAL_LOW_LIMIT_R); - - print_temps("Remote1", TMP411_REMOTE1, - TMP411_REMOTE1_THERM_LIMIT, - TMP411_REMOTE1_HIGH_LIMIT_R, - TMP411_REMOTE1_LOW_LIMIT_R); - - ccprintf("\n"); - - if (raw_read8(TMP411_STATUS_R, &value) == EC_SUCCESS) - ccprintf("STATUS: %pb\n", BINARY_VALUE(value, 8)); - - if (raw_read8(TMP411_CONFIGURATION1_R, &value) == EC_SUCCESS) - ccprintf("CONFIG1: %pb\n", BINARY_VALUE(value, 8)); - - return EC_SUCCESS; -} - -static int command_tmp411(int argc, char **argv) -{ - char *command; - char *e; - char *power; - int data; - int offset; - int rv; - - /* handle "power" command before checking the power status. */ - if ((argc == 3) && !strcasecmp(argv[1], "power")) { - power = argv[2]; - if (!strncasecmp(power, "on", sizeof("on"))) { - rv = tmp411_set_power(TMP411_POWER_ON); - if (!rv) - print_status(); - } else if (!strncasecmp(power, "off", sizeof("off"))) - rv = tmp411_set_power(TMP411_POWER_OFF); - else - return EC_ERROR_PARAM2; - ccprintf("Set TMP411 %s\n", power); - return rv; - } - - if (!has_power()) { - ccprintf("ERROR: Temp sensor not powered.\n"); - return EC_ERROR_NOT_POWERED; - } - - /* If no args just print status */ - if (argc == 1) - return print_status(); - - if (argc < 3) - return EC_ERROR_PARAM_COUNT; - - command = argv[1]; - offset = strtoi(argv[2], &e, 0); - if (*e || offset < 0 || offset > 255) - return EC_ERROR_PARAM2; - - if (!strcasecmp(command, "getbyte")) { - rv = raw_read8(offset, &data); - if (rv < 0) - return rv; - ccprintf("Byte at offset 0x%02x is %pb\n", - offset, BINARY_VALUE(data, 8)); - return rv; - } - - /* Remaining commands are "tmp411 set-command offset data" */ - if (argc != 4) - return EC_ERROR_PARAM_COUNT; - - data = strtoi(argv[3], &e, 0); - if (*e) - return EC_ERROR_PARAM3; - - if (!strcasecmp(command, "settemp")) { - ccprintf("Setting 0x%02x to %dC\n", offset, data); - rv = tmp411_set_temp(offset, data); - } else if (!strcasecmp(command, "setbyte")) { - ccprintf("Setting 0x%02x to 0x%02x\n", offset, data); - rv = raw_write8(offset, data); - } else - return EC_ERROR_PARAM1; - - return rv; -} -DECLARE_CONSOLE_COMMAND(tmp411, command_tmp411, - "[settemp|setbyte <offset> <value>] or [getbyte <offset>] or" - "[power <on|off>]. " - "Temps in Celsius.", - "Print tmp411 temp sensor status or set parameters."); -#endif - -int tmp411_set_power(enum tmp411_power_state power_on) -{ -#ifndef CONFIG_TEMP_SENSOR_POWER_GPIO - uint8_t shutdown = (power_on == TMP411_POWER_OFF) ? 1 : 0; - - return tmp411_shutdown(shutdown); -#else - gpio_set_level(CONFIG_TEMP_SENSOR_POWER_GPIO, power_on); - return EC_SUCCESS; -#endif -} - diff --git a/driver/temp_sensor/tmp411.h b/driver/temp_sensor/tmp411.h deleted file mode 100644 index ef1b23278c..0000000000 --- a/driver/temp_sensor/tmp411.h +++ /dev/null @@ -1,140 +0,0 @@ -/* Copyright 2017 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. - */ - -/* TMP411 temperature sensor module for Chrome EC */ - -#ifndef __CROS_EC_TMP411_H -#define __CROS_EC_TMP411_H - -#define TMP411_I2C_ADDR_FLAGS 0x4C - -#define TMP411_IDX_LOCAL 0 -#define TMP411_IDX_REMOTE1 1 -#define TMP411_IDX_REMOTE2 2 - -/* Chip-specific registers */ -#define TMP411_LOCAL 0x00 -#define TMP411_REMOTE1 0x01 -#define TMP411_STATUS_R 0x02 -#define TMP411_CONFIGURATION1_R 0x03 -#define TMP411_CONVERSION_RATE_R 0x04 -#define TMP411_LOCAL_HIGH_LIMIT_R 0x05 -#define TMP411_LOCAL_LOW_LIMIT_R 0x06 -#define TMP411_REMOTE1_HIGH_LIMIT_R 0x07 -#define TMP411_REMOTE1_LOW_LIMIT_R 0x08 -#define TMP411_CONFIGURATION1_W 0x09 -#define TMP411_CONVERSION_RATE_W 0x0a -#define TMP411_LOCAL_HIGH_LIMIT_W 0x0b -#define TMP411_LOCAL_LOW_LIMIT_W 0x0c -#define TMP411_REMOTE1_HIGH_LIMIT_W 0x0d -#define TMP411_REMOTE1_LOW_LIMIT_W 0x0e -#define TMP411_ONESHOT 0x0f -#define TMP411_REMOTE1_EXTD 0x10 -#define TMP411_REMOTE1_HIGH_LIMIT_EXTD 0x13 -#define TMP411_REMOTE1_LOW_LIMIT_EXTD 0x14 -#define TMP411_REMOTE2_HIGH_LIMIT_R 0x15 -#define TMP411_REMOTE2_HIGH_LIMIT_W 0x15 -#define TMP411_REMOTE2_LOW_LIMIT_R 0x16 -#define TMP411_REMOTE2_LOW_LIMIT_W 0x16 -#define TMP411_REMOTE2_HIGH_LIMIT_EXTD 0x17 -#define TMP411_REMOTE2_LOW_LIMIT_EXTD 0x18 -#define TMP411_REMOTE1_THERM_LIMIT 0x19 -#define TMP411_REMOTE2_THERM_LIMIT 0x1a -#define TMP411_STATUS_FAULT 0x1b -#define TMP411_CHANNEL_MASK 0x1f -#define TMP411_LOCAL_THERM_LIMIT 0x20 -#define TMP411_THERM_HYSTERESIS 0x21 -#define TMP411_CONSECUTIVE_ALERT 0x22 -#define TMP411_REMOTE2 0x23 -#define TMP411_REMOTE2_EXTD 0x24 -#define TMP411_BETA_RANGE_CH1 0x25 -#define TMP411_BETA_RANGE_CH2 0x26 -#define TMP411_NFACTOR_REMOTE1 0x27 -#define TMP411_NFACTOR_REMOTE2 0x28 -#define TMP411_LOCAL_EXTD 0x29 -#define TMP411_STATUS_LIMIT_HIGH 0x35 -#define TMP411_STATUS_LIMIT_LOW 0x36 -#define TMP411_STATUS_THERM 0x37 -#define TMP411_RESET_W 0xfc -#define TMP411_MANUFACTURER_ID 0xfe -#define TMP411_DEVICE_ID 0xff - -#define TMP411A_DEVICE_ID_VAL 0x12 -#define TMP411B_DEVICE_ID_VAL 0x13 -#define TMP411C_DEVICE_ID_VAL 0x10 -#define TMP411d_DEVICE_ID_VAL 0x12 - -/* Config register bits */ -#define TMP411_CONFIG1_TEMP_RANGE BIT(2) -/* TMP411_CONFIG1_MODE bit is use to enable THERM mode */ -#define TMP411_CONFIG1_MODE BIT(5) -#define TMP411_CONFIG1_RUN_L BIT(6) -#define TMP411_CONFIG1_ALERT_MASK_L BIT(7) - -/* Status register bits */ -#define TMP411_STATUS_TEMP_THERM_ALARM BIT(1) -#define TMP411_STATUS_OPEN BIT(2) -#define TMP411_STATUS_TEMP_LOW_ALARM BIT(3) -#define TMP411_STATUS_TEMP_HIGH_ALARM BIT(4) -#define TMP411_STATUS_LOCAL_TEMP_LOW_ALARM BIT(5) -#define TMP411_STATUS_LOCAL_TEMP_HIGH_ALARM BIT(6) -#define TMP411_STATUS_BUSY BIT(7) - -/* Limits */ -#define TMP411_HYSTERESIS_HIGH_LIMIT 255 -#define TMP411_HYSTERESIS_LOW_LIMIT 0 - -enum tmp411_power_state { - TMP411_POWER_OFF = 0, - TMP411_POWER_ON, - TMP411_POWER_COUNT -}; - -enum tmp411_channel_id { - TMP411_CHANNEL_LOCAL, - TMP411_CHANNEL_REMOTE1, - - TMP411_CHANNEL_COUNT -}; - -/** - * Get the last polled value of a sensor. - * - * @param idx Index to read. Idx indicates whether to read die - * temperature or external temperature. - * @param temp_ptr Destination for temperature in K. - * - * @return EC_SUCCESS if successful, non-zero if error. - */ -int tmp411_get_val(int idx, int *temp_ptr); - -/** - * Power control function of tmp411 temperature sensor. - * - * @param power_on TMP411_POWER_ON: turn tmp411 sensor on. - * TMP411_POWER_OFF: shut tmp411 sensor down. - * - * @return EC_SUCCESS if successful, non-zero if error. - */ -int tmp411_set_power(enum tmp411_power_state power_on); - -/* - * Set TMP411 ALERT#/THERM2# pin to THERM mode, and give a limit - * for a specific channel. - * - * @param channel specific a channel - * - * @param limit_c High limit temperature, default: 85C - * - * @param hysteresis Hysteresis temperature, default: 10C - * All channels share the same hysteresis - * - * In THERM mode, ALERT# pin will trigger(Low) by itself when any - * channel's temperature is greater( >= )than channel's limit_c, - * and release(High) by itself when channel's temperature is lower - * than (limit_c - hysteresis) - */ -int tmp411_set_therm_limit(int channel, int limit_c, int hysteresis); -#endif /* __CROS_EC_TMP411_H */ diff --git a/driver/temp_sensor/tmp432.c b/driver/temp_sensor/tmp432.c deleted file mode 100644 index 6260678dcd..0000000000 --- a/driver/temp_sensor/tmp432.c +++ /dev/null @@ -1,399 +0,0 @@ -/* Copyright 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. - */ - -/* TMP432 temperature sensor module for Chrome EC */ - -#include "common.h" -#include "console.h" -#include "tmp432.h" -#include "gpio.h" -#include "i2c.h" -#include "hooks.h" -#include "util.h" - -static int temp_val_local; -static int temp_val_remote1; -static int temp_val_remote2; -#ifndef CONFIG_TEMP_SENSOR_POWER_GPIO -static uint8_t is_sensor_shutdown; -#endif -static int fake_temp[TMP432_IDX_COUNT] = {-1, -1, -1}; - -/** - * Determine whether the sensor is powered. - * - * @return non-zero the tmp432 sensor is powered. - */ -static int has_power(void) -{ -#ifdef CONFIG_TEMP_SENSOR_POWER_GPIO - return gpio_get_level(CONFIG_TEMP_SENSOR_POWER_GPIO); -#else - return !is_sensor_shutdown; -#endif -} - -static int raw_read8(const int offset, int *data_ptr) -{ - return i2c_read8(I2C_PORT_THERMAL, TMP432_I2C_ADDR_FLAGS, - offset, data_ptr); -} - -static int raw_write8(const int offset, int data) -{ - return i2c_write8(I2C_PORT_THERMAL, TMP432_I2C_ADDR_FLAGS, - offset, data); -} - -static int get_temp(const int offset, int *temp_ptr) -{ - int rv; - int temp_raw = 0; - - rv = raw_read8(offset, &temp_raw); - if (rv < 0) - return rv; - - *temp_ptr = (int)(int8_t)temp_raw; - return EC_SUCCESS; -} - -#ifdef CONFIG_CMD_TEMP_SENSOR -static int tmp432_set_temp(const int offset, int temp) -{ - if (temp < -127 || temp > 127) - return EC_ERROR_INVAL; - - return raw_write8(offset, (uint8_t)temp); -} -#endif - -int tmp432_get_val(int idx, int *temp_ptr) -{ - if (!has_power()) - return EC_ERROR_NOT_POWERED; - - switch (idx) { - case TMP432_IDX_LOCAL: - *temp_ptr = temp_val_local; - break; - case TMP432_IDX_REMOTE1: - *temp_ptr = temp_val_remote1; - break; - case TMP432_IDX_REMOTE2: - *temp_ptr = temp_val_remote2; - break; - default: - return EC_ERROR_UNKNOWN; - } - - return EC_SUCCESS; -} - -#ifndef CONFIG_TEMP_SENSOR_POWER_GPIO -static int tmp432_shutdown(uint8_t want_shutdown) -{ - int ret, value; - - if (want_shutdown == is_sensor_shutdown) - return EC_SUCCESS; - - ret = raw_read8(TMP432_CONFIGURATION1_R, &value); - if (ret < 0) { - ccprintf("ERROR: Temp sensor I2C read8 error.\n"); - return ret; - } - - if (want_shutdown && !(value & TMP432_CONFIG1_RUN_L)) { - /* tmp432 is running, and want it to shutdown */ - /* CONFIG REG1 BIT6: 0=Run, 1=Shutdown */ - /* shut it down */ - value |= TMP432_CONFIG1_RUN_L; - ret = raw_write8(TMP432_CONFIGURATION1_R, value); - } else if (!want_shutdown && (value & TMP432_CONFIG1_RUN_L)) { - /* tmp432 is shutdown, and want turn it on */ - value &= ~TMP432_CONFIG1_RUN_L; - ret = raw_write8(TMP432_CONFIGURATION1_R, value); - } - /* else, the current setting is exactly what you want */ - - is_sensor_shutdown = want_shutdown; - return ret; -} -#endif - -static int tmp432_set_therm_mode(void) -{ - int ret = 0; - int data = 0; - - ret = raw_read8(TMP432_CONFIGURATION1_R, &data); - if (ret) - return EC_ERROR_UNKNOWN; - - data |= TMP432_CONFIG1_MODE; - ret = raw_write8(TMP432_CONFIGURATION1_W, data); - if (ret) - return EC_ERROR_UNKNOWN; - - return EC_SUCCESS; -} - -int tmp432_set_therm_limit(int channel, int limit_c, int hysteresis) -{ - int ret = 0; - int reg = 0; - - if (channel >= TMP432_CHANNEL_COUNT) - return EC_ERROR_INVAL; - - if (hysteresis > TMP432_HYSTERESIS_HIGH_LIMIT || - hysteresis < TMP432_HYSTERESIS_LOW_LIMIT) - return EC_ERROR_INVAL; - - /* hysteresis must be less than high limit */ - if (hysteresis > limit_c) - return EC_ERROR_INVAL; - - if (tmp432_set_therm_mode() != EC_SUCCESS) - return EC_ERROR_UNKNOWN; - - switch (channel) { - case TMP432_CHANNEL_LOCAL: - reg = TMP432_LOCAL_HIGH_LIMIT_W; - break; - case TMP432_CHANNEL_REMOTE1: - reg = TMP432_REMOTE1_HIGH_LIMIT_W; - break; - case TMP432_CHANNEL_REMOTE2: - reg = TMP432_REMOTE2_HIGH_LIMIT_W; - break; - } - - ret = raw_write8(reg, limit_c); - if (ret) - return EC_ERROR_UNKNOWN; - - ret = raw_write8(TMP432_THERM_HYSTERESIS, hysteresis); - if (ret) - return EC_ERROR_UNKNOWN; - - return EC_SUCCESS; -} - -static void temp_sensor_poll(void) -{ - int temp_c; - - if (!has_power()) - return; - - if (fake_temp[TMP432_IDX_LOCAL] != -1) { - temp_val_local = C_TO_K(fake_temp[TMP432_IDX_LOCAL]); - } else { - if (get_temp(TMP432_LOCAL, &temp_c) == EC_SUCCESS) - temp_val_local = C_TO_K(temp_c); - /* else: Keep previous value when it fails */ - } - - if (fake_temp[TMP432_IDX_REMOTE1] != -1) { - temp_val_remote1 = C_TO_K(fake_temp[TMP432_IDX_REMOTE1]); - } else { - if (get_temp(TMP432_REMOTE1, &temp_c) == EC_SUCCESS) - temp_val_remote1 = C_TO_K(temp_c); - /* else: Keep previous value when it fails */ - } - - if (fake_temp[TMP432_IDX_REMOTE2] != -1) { - temp_val_remote2 = C_TO_K(fake_temp[TMP432_IDX_REMOTE2]); - } else { - if (get_temp(TMP432_REMOTE2, &temp_c) == EC_SUCCESS) - temp_val_remote2 = C_TO_K(temp_c); - /* else: Keep previous value when it fails */ - } -} -DECLARE_HOOK(HOOK_SECOND, temp_sensor_poll, HOOK_PRIO_TEMP_SENSOR); - -#ifdef CONFIG_CMD_TEMP_SENSOR -static int tmp432_set_fake_temp(int index, int degree_c) -{ - if ((index < 0) || (index >= TMP432_IDX_COUNT)) - return EC_ERROR_INVAL; - - fake_temp[index] = degree_c; - ccprintf("New degree will be updated 1 sec later\n\n"); - - return EC_SUCCESS; -} - -static void print_temps( - const char *name, - const int tmp432_temp_reg, - const int tmp432_therm_limit_reg, - const int tmp432_high_limit_reg, - const int tmp432_low_limit_reg) -{ - int value; - - if (!has_power()) { - ccprintf(" TMP432 is shutdown\n"); - return; - } - - ccprintf("%s:\n", name); - - if (get_temp(tmp432_temp_reg, &value) == EC_SUCCESS) - ccprintf(" Temp %3dC\n", value); - - if (get_temp(tmp432_therm_limit_reg, &value) == EC_SUCCESS) - ccprintf(" Therm Trip %3dC\n", value); - - if (get_temp(tmp432_high_limit_reg, &value) == EC_SUCCESS) - ccprintf(" High Alarm %3dC\n", value); - - if (get_temp(tmp432_low_limit_reg, &value) == EC_SUCCESS) - ccprintf(" Low Alarm %3dC\n", value); -} - -static int print_status(void) -{ - int value, i; - - print_temps("Local", TMP432_LOCAL, - TMP432_LOCAL_THERM_LIMIT, - TMP432_LOCAL_HIGH_LIMIT_R, - TMP432_LOCAL_LOW_LIMIT_R); - - print_temps("Remote1", TMP432_REMOTE1, - TMP432_REMOTE1_THERM_LIMIT, - TMP432_REMOTE1_HIGH_LIMIT_R, - TMP432_REMOTE1_LOW_LIMIT_R); - - print_temps("Remote2", TMP432_REMOTE2, - TMP432_REMOTE2_THERM_LIMIT, - TMP432_REMOTE2_HIGH_LIMIT_R, - TMP432_REMOTE2_LOW_LIMIT_R); - - ccprintf("\n"); - - for (i = 0; i < TMP432_IDX_COUNT; ++i) { - ccprintf("fake temperature[%d]= ", i); - if (fake_temp[i] == -1) { - ccprintf("Not overridden\n"); - continue; - } - - if (tmp432_get_val(i, &value) == EC_SUCCESS) - ccprintf("%d C or %d K\n", (value - 273), value); - else - ccprintf("Access error\n"); - } - - ccprintf("\n"); - - if (raw_read8(TMP432_STATUS, &value) == EC_SUCCESS) - ccprintf("STATUS: %pb\n", BINARY_VALUE(value, 8)); - - if (raw_read8(TMP432_CONFIGURATION1_R, &value) == EC_SUCCESS) - ccprintf("CONFIG1: %pb\n", BINARY_VALUE(value, 8)); - - if (raw_read8(TMP432_CONFIGURATION2_R, &value) == EC_SUCCESS) - ccprintf("CONFIG2: %pb\n", BINARY_VALUE(value, 8)); - - return EC_SUCCESS; -} - -static int command_tmp432(int argc, char **argv) -{ - char *command; - char *e; - char *power; - int data; - int offset; - int rv; - - /* handle "power" command before checking the power status. */ - if ((argc == 3) && !strcasecmp(argv[1], "power")) { - power = argv[2]; - if (!strncasecmp(power, "on", sizeof("on"))) { - rv = tmp432_set_power(TMP432_POWER_ON); - if (!rv) - print_status(); - } - else if (!strncasecmp(power, "off", sizeof("off"))) - rv = tmp432_set_power(TMP432_POWER_OFF); - else - return EC_ERROR_PARAM2; - ccprintf("Set TMP432 %s\n", power); - return rv; - } - - if (!has_power()) { - ccprintf("ERROR: Temp sensor not powered.\n"); - return EC_ERROR_NOT_POWERED; - } - - /* If no args just print status */ - if (argc == 1) - return print_status(); - - if (argc < 3) - return EC_ERROR_PARAM_COUNT; - - command = argv[1]; - offset = strtoi(argv[2], &e, 0); - if (*e || offset < 0 || offset > 255) - return EC_ERROR_PARAM2; - - if (!strcasecmp(command, "getbyte")) { - rv = raw_read8(offset, &data); - if (rv < 0) - return rv; - ccprintf("Byte at offset 0x%02x is %pb\n", - offset, BINARY_VALUE(data, 8)); - return rv; - } - - /* Remaining commands are "tmp432 set-command offset data" */ - if (argc != 4) - return EC_ERROR_PARAM_COUNT; - - data = strtoi(argv[3], &e, 0); - if (*e) - return EC_ERROR_PARAM3; - - if (!strcasecmp(command, "settemp")) { - ccprintf("Setting 0x%02x to %dC\n", offset, data); - rv = tmp432_set_temp(offset, data); - } else if (!strcasecmp(command, "setbyte")) { - ccprintf("Setting 0x%02x to 0x%02x\n", offset, data); - rv = raw_write8(offset, data); - } else if (!strcasecmp(command, "fake")) { - ccprintf("Hook temperature\n"); - rv = tmp432_set_fake_temp(offset, data); - print_status(); - } else - return EC_ERROR_PARAM1; - - return rv; -} -DECLARE_CONSOLE_COMMAND(tmp432, command_tmp432, - "[settemp|setbyte <offset> <value>] or [getbyte <offset>] or" - "[fake <index> <value>] or [power <on|off>]. " - "Temps in Celsius.", - "Print tmp432 temp sensor status or set parameters."); -#endif - -int tmp432_set_power(enum tmp432_power_state power_on) -{ -#ifndef CONFIG_TEMP_SENSOR_POWER_GPIO - uint8_t shutdown = (power_on == TMP432_POWER_OFF) ? 1 : 0; - return tmp432_shutdown(shutdown); -#else - gpio_set_level(CONFIG_TEMP_SENSOR_POWER_GPIO, power_on); - return EC_SUCCESS; -#endif -} - diff --git a/driver/temp_sensor/tmp432.h b/driver/temp_sensor/tmp432.h deleted file mode 100644 index e58e39a4a0..0000000000 --- a/driver/temp_sensor/tmp432.h +++ /dev/null @@ -1,143 +0,0 @@ -/* Copyright 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. - */ - -/* TMP432 temperature sensor module for Chrome EC */ - -#ifndef __CROS_EC_TMP432_H -#define __CROS_EC_TMP432_H - -#define TMP432_I2C_ADDR_FLAGS 0x4C - -#define TMP432_IDX_LOCAL 0 -#define TMP432_IDX_REMOTE1 1 -#define TMP432_IDX_REMOTE2 2 -#define TMP432_IDX_COUNT 3 - -/* Chip-specific registers */ -#define TMP432_LOCAL 0x00 -#define TMP432_REMOTE1 0x01 -#define TMP432_STATUS 0x02 -#define TMP432_CONFIGURATION1_R 0x03 -#define TMP432_CONVERSION_RATE_R 0x04 -#define TMP432_LOCAL_HIGH_LIMIT_R 0x05 -#define TMP432_LOCAL_LOW_LIMIT_R 0x06 -#define TMP432_REMOTE1_HIGH_LIMIT_R 0x07 -#define TMP432_REMOTE1_LOW_LIMIT_R 0x08 -#define TMP432_CONFIGURATION1_W 0x09 -#define TMP432_CONVERSION_RATE_W 0x0a -#define TMP432_LOCAL_HIGH_LIMIT_W 0x0b -#define TMP432_LOCAL_LOW_LIMIT_W 0x0c -#define TMP432_REMOTE1_HIGH_LIMIT_W 0x0d -#define TMP432_REMOTE1_LOW_LIMIT_W 0x0e -#define TMP432_ONESHOT 0x0f -#define TMP432_REMOTE1_EXTD 0x10 -#define TMP432_REMOTE1_HIGH_LIMIT_EXTD 0x13 -#define TMP432_REMOTE1_LOW_LIMIT_EXTD 0x14 -#define TMP432_REMOTE2_HIGH_LIMIT_R 0x15 -#define TMP432_REMOTE2_HIGH_LIMIT_W 0x15 -#define TMP432_REMOTE2_LOW_LIMIT_R 0x16 -#define TMP432_REMOTE2_LOW_LIMIT_W 0x16 -#define TMP432_REMOTE2_HIGH_LIMIT_EXTD 0x17 -#define TMP432_REMOTE2_LOW_LIMIT_EXTD 0x18 -#define TMP432_REMOTE1_THERM_LIMIT 0x19 -#define TMP432_REMOTE2_THERM_LIMIT 0x1a -#define TMP432_STATUS_FAULT 0x1b -#define TMP432_CHANNEL_MASK 0x1f -#define TMP432_LOCAL_THERM_LIMIT 0x20 -#define TMP432_THERM_HYSTERESIS 0x21 -#define TMP432_CONSECUTIVE_ALERT 0x22 -#define TMP432_REMOTE2 0x23 -#define TMP432_REMOTE2_EXTD 0x24 -#define TMP432_BETA_RANGE_CH1 0x25 -#define TMP432_BETA_RANGE_CH2 0x26 -#define TMP432_NFACTOR_REMOTE1 0x27 -#define TMP432_NFACTOR_REMOTE2 0x28 -#define TMP432_LOCAL_EXTD 0x29 -#define TMP432_STATUS_LIMIT_HIGH 0x35 -#define TMP432_STATUS_LIMIT_LOW 0x36 -#define TMP432_STATUS_THERM 0x37 -#define TMP432_LOCAL_HIGH_LIMIT_EXTD 0x3d -#define TMP432_LOCAL_LOW_LIMIT_EXTD 0x3e -#define TMP432_CONFIGURATION2_R 0x3f -#define TMP432_CONFIGURATION2_W 0x3f -#define TMP432_RESET_W 0xfc -#define TMP432_DEVICE_ID 0xfd -#define TMP432_MANUFACTURER_ID 0xfe - -/* Config register bits */ -#define TMP432_CONFIG1_TEMP_RANGE BIT(2) -/* TMP432_CONFIG1_MODE bit is use to enable THERM mode */ -#define TMP432_CONFIG1_MODE BIT(5) -#define TMP432_CONFIG1_RUN_L BIT(6) -#define TMP432_CONFIG1_ALERT_MASK_L BIT(7) -#define TMP432_CONFIG2_RESISTANCE_CORRECTION BIT(2) -#define TMP432_CONFIG2_LOCAL_ENABLE BIT(3) -#define TMP432_CONFIG2_REMOTE1_ENABLE BIT(4) -#define TMP432_CONFIG2_REMOTE2_ENABLE BIT(5) - -/* Status register bits */ -#define TMP432_STATUS_TEMP_THERM_ALARM BIT(1) -#define TMP432_STATUS_OPEN BIT(2) -#define TMP432_STATUS_TEMP_LOW_ALARM BIT(3) -#define TMP432_STATUS_TEMP_HIGH_ALARM BIT(4) -#define TMP432_STATUS_BUSY BIT(7) - -/* Limintaions */ -#define TMP432_HYSTERESIS_HIGH_LIMIT 255 -#define TMP432_HYSTERESIS_LOW_LIMIT 0 - -enum tmp432_power_state { - TMP432_POWER_OFF = 0, - TMP432_POWER_ON, - TMP432_POWER_COUNT -}; - -enum tmp432_channel_id { - TMP432_CHANNEL_LOCAL, - TMP432_CHANNEL_REMOTE1, - TMP432_CHANNEL_REMOTE2, - - TMP432_CHANNEL_COUNT -}; - -/** - * Get the last polled value of a sensor. - * - * @param idx Index to read. Idx indicates whether to read die - * temperature or external temperature. - * @param temp_ptr Destination for temperature in K. - * - * @return EC_SUCCESS if successful, non-zero if error. - */ -int tmp432_get_val(int idx, int *temp_ptr); - -/** - * Power control function of tmp432 temperature sensor. - * - * @param power_on TMP432_POWER_ON: turn tmp432 sensor on. - * TMP432_POWER_OFF: shut tmp432 sensor down. - * - * @return EC_SUCCESS if successful, non-zero if error. - */ -int tmp432_set_power(enum tmp432_power_state power_on); - -/* - * Set TMP432 ALERT#/THERM2# pin to THERM mode, and give a limit - * for a specific channel. - * - * @param channel specific a channel - * - * @param limit_c High limit temperature, default: 85C - * - * @param hysteresis Hysteresis temperature, default: 10C - * All channels share the same hysteresis - * - * In THERM mode, ALERT# pin will trigger(Low) by itself when any - * channel's temperature is greater( >= )than channel's limit_c, - * and release(High) by itself when channel's temperature is lower - * than (limit_c - hysteresis) - */ -int tmp432_set_therm_limit(int channel, int limit_c, int hysteresis); -#endif /* __CROS_EC_TMP432_H */ diff --git a/driver/temp_sensor/tmp468.c b/driver/temp_sensor/tmp468.c deleted file mode 100644 index 46e77ca696..0000000000 --- a/driver/temp_sensor/tmp468.c +++ /dev/null @@ -1,101 +0,0 @@ -/* Copyright 2018 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. - */ - -/* TMP468 temperature sensor module for Chrome EC */ - -#include "common.h" -#include "console.h" -#include "tmp432.h" -#include "gpio.h" -#include "i2c.h" -#include "hooks.h" -#include "util.h" - -#include "tmp468.h" - - -static int fake_temp[TMP468_CHANNEL_COUNT] = {-1, -1, -1, -1, -1, -1, -1 , -1, -1}; -static int temp_val[TMP468_CHANNEL_COUNT] = {0, 0, 0, 0, 0, 0, 0 , 0, 0}; -static uint8_t is_sensor_shutdown; - -static int has_power(void) -{ - return !is_sensor_shutdown; -} - -static int raw_read16(const int offset, int *data_ptr) -{ - return i2c_read16(I2C_PORT_THERMAL, TMP468_I2C_ADDR_FLAGS, - offset, data_ptr); -} - -static int raw_write16(const int offset, int data_ptr) -{ - return i2c_write16(I2C_PORT_THERMAL, TMP468_I2C_ADDR_FLAGS, - offset, data_ptr); -} - -static int tmp468_shutdown(uint8_t want_shutdown) -{ - int ret, value; - - if (want_shutdown == is_sensor_shutdown) - return EC_SUCCESS; - - ret = raw_read16(TMP468_CONFIGURATION, &value); - if (ret < 0) { - ccprintf("ERROR: Temp sensor I2C read16 error.\n"); - return ret; - } - - if (want_shutdown) - value |= TMP468_SHUTDOWN; - else - value &= ~TMP468_SHUTDOWN; - - ret = raw_write16(TMP468_CONFIGURATION, value); - if (ret == EC_SUCCESS) - is_sensor_shutdown = want_shutdown; - - return EC_SUCCESS; -} - -int tmp468_get_val(int idx, int *temp_ptr) -{ - if(!has_power()) - return EC_ERROR_NOT_POWERED; - - if (idx < TMP468_CHANNEL_COUNT) { - *temp_ptr = C_TO_K(temp_val[idx]); - return EC_SUCCESS; - } - - return EC_ERROR_INVAL; -} - -static void temp_sensor_poll(void) -{ - int i, ret; - - if (!has_power()) - return; - - for (i = 0; i < TMP468_CHANNEL_COUNT; i++) - if (fake_temp[i] != -1) { - temp_val[i] = fake_temp[i]; - } else { - ret = raw_read16(TMP468_LOCAL + i, &temp_val[i]); - if (ret < 0) - return; - temp_val[i] >>= TMP468_SHIFT1; - } -} -DECLARE_HOOK(HOOK_SECOND, temp_sensor_poll, HOOK_PRIO_TEMP_SENSOR); - -int tmp468_set_power(enum tmp468_power_state power_on) -{ - uint8_t shutdown = (power_on == TMP468_POWER_OFF) ? 1 : 0; - return tmp468_shutdown(shutdown); -} diff --git a/driver/temp_sensor/tmp468.h b/driver/temp_sensor/tmp468.h deleted file mode 100644 index 59fbd20477..0000000000 --- a/driver/temp_sensor/tmp468.h +++ /dev/null @@ -1,126 +0,0 @@ -/* Copyright 2018 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. - */ - -/* TMP468 temperature sensor module for Chrome EC */ - -#ifndef __CROS_EC_TMP468_H -#define __CROS_EC_TMP468_H - -#define TMP468_I2C_ADDR_FLAGS (0x48 | I2C_FLAG_BIG_ENDIAN) -#define TMP468_SHIFT1 7 - -#define TMP468_LOCAL 0x00 -#define TMP468_REMOTE1 0x01 -#define TMP468_REMOTE2 0x02 -#define TMP468_REMOTE3 0x03 -#define TMP468_REMOTE4 0x04 -#define TMP468_REMOTE5 0x05 -#define TMP468_REMOTE6 0x06 -#define TMP468_REMOTE7 0x07 -#define TMP468_REMOTE8 0x08 - -#define TMP468_SRST 0x20 -#define TMP468_THERM 0x21 -#define TMP468_THERM2 0x22 -#define TMP468_ROPEN 0x23 - -#define TMP468_CONFIGURATION 0x30 -#define TMP468_THERM_HYST 0x38 - -#define TMP468_LOCAL_LOW_LIMIT 0x39 -#define TMP468_LOCAL_HIGH_LIMT 0x3a - -#define TMP468_REMOTE1_OFFSET 0x40 -#define TMP468_REMOTE1_NFACTOR 0x41 -#define TMP468_REMOTE1_LOW_LIMIT 0x41 -#define TMP468_REMOTE1_HIGH_LIMIT 0x42 - -#define TMP468_REMOTE2_OFFSET 0x48 -#define TMP468_REMOTE2_NFACTOR 0x49 -#define TMP468_REMOTE2_LOW_LIMIT 0x4a -#define TMP468_REMOTE2_HIGH_LIMIT 0x4b - -#define TMP468_REMOTE3_OFFSET 0x50 -#define TMP468_REMOTE3_NFACTOR 0x51 -#define TMP468_REMOTE3_LOW_LIMIT 0x52 -#define TMP468_REMOTE3_HIGH_LIMIT 0x53 - -#define TMP468_REMOTE4_OFFSET 0x58 -#define TMP468_REMOTE4_NFACTOR 0x59 -#define TMP468_REMOTE4_LOW_LIMIT 0x59 -#define TMP468_REMOTE4_HIGH_LIMIT 0x5a - -#define TMP468_REMOTE5_OFFSET 0x60 -#define TMP468_REMOTE5_NFACTOR 0x61 -#define TMP468_REMOTE5_LOW_LIMIT 0x62 -#define TMP468_REMOTE5_HIGH_LIMIT 0x63 - -#define TMP468_REMOTE6_OFFSET 0x68 -#define TMP468_REMOTE6_NFACTOR 0x69 -#define TMP468_REMOTE6_LOW_LIMIT 0x6a -#define TMP468_REMOTE6_HIGH_LIMIT 0x6b - -#define TMP468_REMOTE7_OFFSET 0x70 -#define TMP468_REMOTE7_NFACTOR 0x71 -#define TMP468_REMOTE7_LOW_LIMIT 0x72 -#define TMP468_REMOTE7_HIGH_LIMIT 0x73 - -#define TMP468_REMOTE8_OFFSET 0x78 -#define TMP468_REMOTE8_NFACTOR 0x79 -#define TMP468_REMOTE8_LOW_LIMIT 0x7a -#define TMP468_REMOTE8_HIGH_LIMIT 0x7b - -#define TMP468_LOCK 0xc4 - -#define TMP468_DEVICE_ID 0xfd -#define TMP468_MANUFACTURER_ID 0xfe - -#define TMP468_SHUTDOWN BIT(5) - -enum tmp468_channel_id { - TMP468_CHANNEL_LOCAL, - - TMP468_CHANNEL_REMOTE1, - TMP468_CHANNEL_REMOTE2, - TMP468_CHANNEL_REMOTE3, - TMP468_CHANNEL_REMOTE4, - TMP468_CHANNEL_REMOTE5, - TMP468_CHANNEL_REMOTE6, - TMP468_CHANNEL_REMOTE7, - TMP468_CHANNEL_REMOTE8, - - TMP468_CHANNEL_COUNT -}; - -enum tmp468_power_state { - TMP468_POWER_OFF = 0, - TMP468_POWER_ON, - - TMP468_POWER_COUNT -}; - - -/** - * Get the last polled value of a sensor. - * - * @param idx Index to read. Idx indicates whether to read die - * temperature or external temperature. - * @param temp_ptr Destination for temperature in K. - * - * @return EC_SUCCESS if successful, non-zero if error. - */ -int tmp468_get_val(int idx, int *temp_ptr); - -/** - * Power control function of tmp432 temperature sensor. - * - * @param power_on TMP468_POWER_ON: turn tmp468 sensor on. - * TMP468_POWER_OFF: shut tmp468 sensor down. - * - * @return EC_SUCCESS if successful, non-zero if error. - */ -int tmp468_set_power(enum tmp468_power_state power_on); - -#endif /* __CROS_EC_TMP468_H */ diff --git a/driver/touchpad_elan.c b/driver/touchpad_elan.c deleted file mode 100644 index 6df4f0f7de..0000000000 --- a/driver/touchpad_elan.c +++ /dev/null @@ -1,847 +0,0 @@ -/* Copyright 2016 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 "byteorder.h" -#include "common.h" -#include "console.h" -#include "gpio.h" -#include "hwtimer.h" -#include "hooks.h" -#include "i2c.h" -#include "math_util.h" -#include "sha256.h" -#include "shared_mem.h" -#include "task.h" -#include "tablet_mode.h" -#include "timer.h" -#include "touchpad.h" -#include "update_fw.h" -#include "util.h" -#include "usb_api.h" -#include "usb_hid_touchpad.h" -#include "watchdog.h" - -/* Console output macros */ -#define CPUTS(outstr) cputs(CC_TOUCHPAD, outstr) -#define CPRINTF(format, args...) cprintf(CC_TOUCHPAD, format, ## args) -#define CPRINTS(format, args...) cprints(CC_TOUCHPAD, format, ## args) - -#define TASK_EVENT_POWER TASK_EVENT_CUSTOM_BIT(0) - -/******************************************************************************/ -/* How to talk to the controller */ -/******************************************************************************/ - -#define ELAN_VENDOR_ID 0x04f3 - -#define ETP_I2C_RESET 0x0100 -#define ETP_I2C_WAKE_UP 0x0800 -#define ETP_I2C_SLEEP 0x0801 - -#define ETP_I2C_STAND_CMD 0x0005 -#define ETP_I2C_UNIQUEID_CMD 0x0101 -#define ETP_I2C_FW_VERSION_CMD 0x0102 -#define ETP_I2C_OSM_VERSION_CMD 0x0103 -#define ETP_I2C_XY_TRACENUM_CMD 0x0105 -#define ETP_I2C_MAX_X_AXIS_CMD 0x0106 -#define ETP_I2C_MAX_Y_AXIS_CMD 0x0107 -#define ETP_I2C_RESOLUTION_CMD 0x0108 -#define ETP_I2C_IAP_VERSION_CMD 0x0110 -#define ETP_I2C_PRESSURE_CMD 0x010A -#define ETP_I2C_SET_CMD 0x0300 -#define ETP_I2C_IAP_TYPE_CMD 0x0304 -#define ETP_I2C_POWER_CMD 0x0307 -#define ETP_I2C_FW_CHECKSUM_CMD 0x030F - -#define ETP_ENABLE_ABS 0x0001 - -#define ETP_DISABLE_POWER 0x0001 - -#define ETP_I2C_REPORT_LEN 34 - -#define ETP_MAX_FINGERS 5 -#define ETP_FINGER_DATA_LEN 5 - -#define ETP_PRESSURE_OFFSET 25 -#define ETP_FWIDTH_REDUCE 90 - -#define ETP_REPORT_ID 0x5D -#define ETP_REPORT_ID_OFFSET 2 -#define ETP_TOUCH_INFO_OFFSET 3 -#define ETP_FINGER_DATA_OFFSET 4 -#define ETP_HOVER_INFO_OFFSET 30 -#define ETP_MAX_REPORT_LEN 34 - -#define ETP_IAP_START_ADDR 0x0083 - -#define ETP_I2C_IAP_RESET_CMD 0x0314 -#define ETP_I2C_IAP_RESET 0xF0F0 -#define ETP_I2C_IAP_CTRL_CMD 0x0310 -#define ETP_I2C_MAIN_MODE_ON BIT(9) -#define ETP_I2C_IAP_CMD 0x0311 -#define ETP_I2C_IAP_PASSWORD 0x1EA5 - -#define ETP_I2C_IAP_REG_L 0x01 -#define ETP_I2C_IAP_REG_H 0x06 - -#define ETP_FW_IAP_PAGE_ERR BIT(5) -#define ETP_FW_IAP_INTF_ERR BIT(4) - -#ifdef CONFIG_USB_UPDATE -/* The actual FW_SIZE depends on IC. */ -#define FW_SIZE CONFIG_TOUCHPAD_VIRTUAL_SIZE -#endif - -struct { - /* Max X/Y position */ - uint16_t max_x; - uint16_t max_y; - /* Scaling factor for finger width/height */ - uint16_t width_x; - uint16_t width_y; - /* Pressure adjustment */ - uint8_t pressure_adj; - uint16_t ic_type; - uint16_t page_count; - uint16_t page_size; - uint16_t iap_version; -} elan_tp_params; - -/* - * Report a more reasonable pressure value, so that no adjustment is necessary - * on Chrome OS side. 3216/1024 ~= 3.1416. - */ -const int pressure_mult = 3216; -const int pressure_div = 1024; - -static int elan_tp_read_cmd(uint16_t reg, uint16_t *val) -{ - uint8_t buf[2]; - - buf[0] = reg; - buf[1] = reg >> 8; - - return i2c_xfer(CONFIG_TOUCHPAD_I2C_PORT, - CONFIG_TOUCHPAD_I2C_ADDR_FLAGS, - buf, sizeof(buf), (uint8_t *)val, sizeof(*val)); -} - -static int elan_tp_write_cmd(uint16_t reg, uint16_t val) -{ - uint8_t buf[4]; - - buf[0] = reg; - buf[1] = reg >> 8; - buf[2] = val; - buf[3] = val >> 8; - - return i2c_xfer(CONFIG_TOUCHPAD_I2C_PORT, - CONFIG_TOUCHPAD_I2C_ADDR_FLAGS, - buf, sizeof(buf), NULL, 0); -} - -/* Power is on by default. */ -static int elan_tp_power = 1; - -static int elan_tp_set_power(int enable) -{ - int rv; - uint16_t val; - - if ((enable && elan_tp_power) || (!enable && !elan_tp_power)) - return EC_SUCCESS; - - CPRINTS("elan TP power %s", enable ? "on" : "off"); - - rv = elan_tp_read_cmd(ETP_I2C_POWER_CMD, &val); - if (rv) - goto out; - - if (enable) - val &= ~ETP_DISABLE_POWER; - else - val |= ETP_DISABLE_POWER; - - rv = elan_tp_write_cmd(ETP_I2C_POWER_CMD, val); - - elan_tp_power = enable; -out: - return rv; -} - -static int finger_status[ETP_MAX_FINGERS] = {0}; - -/* - * Timestamp of last interrupt (32 bits are enough as we divide the value by 100 - * and then put it in a 16-bit field). - */ -static uint32_t irq_ts; - -/* - * Read touchpad report. - * Returns 0 on success, positive (EC_RES_*) value on I2C error, and a negative - * value if the I2C transaction is successful but the data is invalid (fairly - * common). - */ -static int elan_tp_read_report(void) -{ - int rv; - uint8_t tp_buf[ETP_I2C_REPORT_LEN]; - int i, ri; - uint8_t touch_info; - uint8_t hover_info; - uint8_t *finger = tp_buf+ETP_FINGER_DATA_OFFSET; - struct usb_hid_touchpad_report report; - uint16_t timestamp; - - /* Compute and save timestamp early in case another interrupt comes. */ - timestamp = irq_ts / USB_HID_TOUCHPAD_TIMESTAMP_UNIT; - - rv = i2c_xfer(CONFIG_TOUCHPAD_I2C_PORT, - CONFIG_TOUCHPAD_I2C_ADDR_FLAGS, - NULL, 0, tp_buf, ETP_I2C_REPORT_LEN); - - if (rv) { - CPRINTS("read report error (%d)", rv); - return rv; - } - - if (tp_buf[ETP_REPORT_ID_OFFSET] != ETP_REPORT_ID) { - CPRINTS("Invalid report id (%x)", tp_buf[ETP_REPORT_ID_OFFSET]); - return -1; - } - - memset(&report, 0, sizeof(report)); - report.id = 0x01; - ri = 0; /* Next finger index in HID report */ - - touch_info = tp_buf[ETP_TOUCH_INFO_OFFSET]; - hover_info = tp_buf[ETP_HOVER_INFO_OFFSET]; - - for (i = 0; i < ETP_MAX_FINGERS; i++) { - int valid = touch_info & (1 << (3+i)); - - if (valid) { - int width = finger[3] & 0x0f; - int height = (finger[3] & 0xf0) >> 4; - int pressure = finger[4] + elan_tp_params.pressure_adj; - pressure = DIV_ROUND_NEAREST(pressure * pressure_mult, - pressure_div); - - width = MIN(4095, width * elan_tp_params.width_x); - height = MIN(4095, height * elan_tp_params.width_y); - pressure = MIN(1023, pressure); - - report.finger[ri].confidence = 1; - report.finger[ri].tip = 1; - report.finger[ri].inrange = 1; - report.finger[ri].id = i; - report.finger[ri].width = width; - report.finger[ri].height = height; - report.finger[ri].x = - ((finger[0] & 0xf0) << 4) | finger[1]; - report.finger[ri].y = - elan_tp_params.max_y - - (((finger[0] & 0x0f) << 8) | finger[2]); - report.finger[ri].pressure = pressure; - finger += ETP_FINGER_DATA_LEN; - ri++; - finger_status[i] = 1; - } else if (finger_status[i]) { - report.finger[ri].id = i; - /* When a finger is leaving, it's not a plam */ - report.finger[ri].confidence = 1; - ri++; - finger_status[i] = 0; - } - } - - report.count = ri; - report.timestamp = timestamp; - - if (touch_info & 0x01) { - /* Do not report zero-finger click events */ - if (report.count > 0) - report.button = 1; - } - - if (hover_info & 0x40) { - /* TODO(b/35582031): Report hover event */ - CPRINTF("[TP] hover!\n"); - } - - set_touchpad_report(&report); - - return 0; -} - -static void elan_get_fwinfo(void) -{ - uint16_t ic_type = elan_tp_params.ic_type; - uint16_t iap_version = elan_tp_params.iap_version; - - switch (ic_type) { - case 0x09: - elan_tp_params.page_count = 768; - break; - case 0x0D: - elan_tp_params.page_count = 896; - break; - case 0x00: - case 0x10: - case 0x14: - case 0x15: - elan_tp_params.page_count = 1024; - break; - default: - elan_tp_params.page_count = -1; - CPRINTS("unknown ic_type: %d", ic_type); - } - - if ((ic_type == 0x14 || ic_type == 0x15) && iap_version >= 2) { - elan_tp_params.page_count /= 8; - elan_tp_params.page_size = 512; - } else if (ic_type >= 0x0D && iap_version >= 1) { - elan_tp_params.page_count /= 2; - elan_tp_params.page_size = 128; - } else { - elan_tp_params.page_size = 64; - } -} - -/* - * - dpi == logical dimension / physical dimension (inches) - * (254 tenths of mm per inch) - */ -__maybe_unused static int calc_physical_dimension(int dpi, int logical_dim) -{ - return round_divide(254 * logical_dim, dpi); -} - -/* Initialize the controller ICs after reset */ -static void elan_tp_init(void) -{ - int rv; - uint8_t val[2]; - int dpi_x, dpi_y; - - CPRINTS("%s", __func__); - - elan_tp_write_cmd(ETP_I2C_STAND_CMD, ETP_I2C_RESET); - msleep(100); - rv = i2c_xfer(CONFIG_TOUCHPAD_I2C_PORT, - CONFIG_TOUCHPAD_I2C_ADDR_FLAGS, - NULL, 0, val, sizeof(val)); - - CPRINTS("reset rv %d buf=%04x", rv, *((uint16_t *)val)); - if (rv) - goto out; - - /* Read IC type, IAP version */ - rv = elan_tp_read_cmd(ETP_I2C_OSM_VERSION_CMD, &elan_tp_params.ic_type); - CPRINTS("%s: ic_type:%04X.", __func__, elan_tp_params.ic_type); - elan_tp_params.ic_type >>= 8; - if (rv) - goto out; - - rv = elan_tp_read_cmd(ETP_I2C_IAP_VERSION_CMD, - &elan_tp_params.iap_version); - CPRINTS("%s: iap_version:%04X.", __func__, elan_tp_params.iap_version); - elan_tp_params.iap_version >>= 8; - if (rv) - goto out; - - elan_get_fwinfo(); - - /* Read min/max */ - rv = elan_tp_read_cmd(ETP_I2C_MAX_X_AXIS_CMD, &elan_tp_params.max_x); - if (rv) - goto out; - rv = elan_tp_read_cmd(ETP_I2C_MAX_Y_AXIS_CMD, &elan_tp_params.max_y); - if (rv) - goto out; - - /* Read min/max */ - rv = elan_tp_read_cmd(ETP_I2C_XY_TRACENUM_CMD, (uint16_t *)val); - if (rv) - goto out; - if (val[0] == 0 || val[1] == 0) { - CPRINTS("Invalid XY_TRACENUM"); - goto out; - } - - /* ETP_FWIDTH_REDUCE reduces the apparent width to avoid treating large - * finger as palm. Multiply value by 2 as HID multitouch divides it. - */ - elan_tp_params.width_x = - 2 * ((elan_tp_params.max_x / val[0]) - ETP_FWIDTH_REDUCE); - elan_tp_params.width_y = - 2 * ((elan_tp_params.max_y / val[1]) - ETP_FWIDTH_REDUCE); - - rv = elan_tp_read_cmd(ETP_I2C_PRESSURE_CMD, (uint16_t *)val); - if (rv) - goto out; - elan_tp_params.pressure_adj = (val[0] & 0x10) ? 0 : ETP_PRESSURE_OFFSET; - - rv = elan_tp_read_cmd(ETP_I2C_RESOLUTION_CMD, (uint16_t *)val); - if (rv) - goto out; - - dpi_x = 10*val[0] + 790; - dpi_y = 10*val[1] + 790; - - CPRINTS("max=%d/%d width=%d/%d adj=%d dpi=%d/%d", - elan_tp_params.max_x, elan_tp_params.max_y, - elan_tp_params.width_x, elan_tp_params.width_y, - elan_tp_params.pressure_adj, dpi_x, dpi_y); - -#ifdef CONFIG_USB_HID_TOUCHPAD - /* Validity check dimensions provided at build time. */ - if (elan_tp_params.max_x != CONFIG_USB_HID_TOUCHPAD_LOGICAL_MAX_X || - elan_tp_params.max_y != CONFIG_USB_HID_TOUCHPAD_LOGICAL_MAX_Y || - calc_physical_dimension(dpi_x, elan_tp_params.max_x) != - CONFIG_USB_HID_TOUCHPAD_PHYSICAL_MAX_X || - calc_physical_dimension(dpi_y, elan_tp_params.max_y) != - CONFIG_USB_HID_TOUCHPAD_PHYSICAL_MAX_Y) { - CPRINTS("*** TP mismatch!"); - } -#endif - - /* Switch to absolute mode */ - rv = elan_tp_write_cmd(ETP_I2C_SET_CMD, ETP_ENABLE_ABS); - if (rv) - goto out; - - /* Sleep control off */ - rv = elan_tp_write_cmd(ETP_I2C_STAND_CMD, ETP_I2C_WAKE_UP); - - /* Enable interrupt to fetch reports */ - gpio_enable_interrupt(GPIO_TOUCHPAD_INT); - -out: - CPRINTS("%s:%d", __func__, rv); - - return; -} -DECLARE_DEFERRED(elan_tp_init); - -#ifdef CONFIG_USB_UPDATE -int touchpad_get_info(struct touchpad_info *tp) -{ - int rv; - uint16_t val; - - tp->status = EC_RES_SUCCESS; - tp->vendor = ELAN_VENDOR_ID; - - /* Get unique ID, FW, SM version. */ - rv = elan_tp_read_cmd(ETP_I2C_UNIQUEID_CMD, &val); - if (rv) - return -1; - tp->elan.id = val; - - rv = elan_tp_read_cmd(ETP_I2C_FW_VERSION_CMD, &val); - if (rv) - return -1; - tp->elan.fw_version = val & 0xff; - - rv = elan_tp_read_cmd(ETP_I2C_FW_CHECKSUM_CMD, &val); - if (rv) - return -1; - tp->elan.fw_checksum = val; - - return sizeof(*tp); -} - -static int elan_in_main_mode(void) -{ - uint16_t val; - - elan_tp_read_cmd(ETP_I2C_IAP_CTRL_CMD, &val); - return val & ETP_I2C_MAIN_MODE_ON; -} - -static int elan_read_write_iap_type(void) -{ - for (int retry = 0; retry < 3; ++retry) { - uint16_t val; - - if (elan_tp_write_cmd(ETP_I2C_IAP_TYPE_CMD, - elan_tp_params.page_size / 2)) - return EC_ERROR_UNKNOWN; - - if (elan_tp_read_cmd(ETP_I2C_IAP_TYPE_CMD, &val)) - return EC_ERROR_UNKNOWN; - - if (val == elan_tp_params.page_size / 2) - return EC_SUCCESS; - - } - return EC_ERROR_UNKNOWN; -} - -static int elan_prepare_for_update(void) -{ - uint16_t rx_buf; - int initial_mode; - - initial_mode = elan_in_main_mode(); - if (!initial_mode) { - CPRINTS("%s: In IAP mode, reset IC.", __func__); - elan_tp_write_cmd(ETP_I2C_IAP_RESET_CMD, ETP_I2C_IAP_RESET); - msleep(30); - } - /* Send the passphrase */ - elan_tp_write_cmd(ETP_I2C_IAP_CMD, ETP_I2C_IAP_PASSWORD); - msleep(initial_mode ? 100 : 30); - - /* We should be in the IAP mode now */ - if (elan_in_main_mode()) { - CPRINTS("%s: Failure to enter IAP mode.", __func__); - return EC_ERROR_UNKNOWN; - } - - if (elan_tp_params.ic_type >= 0x0D && elan_tp_params.iap_version >= 1) { - if (elan_read_write_iap_type()) - return EC_ERROR_UNKNOWN; - } - - /* Send the passphrase again */ - elan_tp_write_cmd(ETP_I2C_IAP_CMD, ETP_I2C_IAP_PASSWORD); - msleep(30); - - /* Verify the password */ - if (elan_tp_read_cmd(ETP_I2C_IAP_CMD, &rx_buf)) { - CPRINTS("%s: Cannot read IAP password.", __func__); - return EC_ERROR_UNKNOWN; - } - if (rx_buf != ETP_I2C_IAP_PASSWORD) { - CPRINTS("%s: Got an unexpected IAP password %0x4x.", __func__, - rx_buf); - return EC_ERROR_UNKNOWN; - } - return EC_SUCCESS; -} - -static int touchpad_update_page(const uint8_t *data) -{ - const uint8_t cmd[2] = {ETP_I2C_IAP_REG_L, ETP_I2C_IAP_REG_H}; - uint16_t checksum = 0; - uint16_t rx_buf; - int i, rv; - - for (i = 0; i < elan_tp_params.page_size; i += 2) - checksum += ((uint16_t)(data[i + 1]) << 8) | (data[i]); - checksum = htole16(checksum); - - i2c_lock(CONFIG_TOUCHPAD_I2C_PORT, 1); - - rv = i2c_xfer_unlocked(CONFIG_TOUCHPAD_I2C_PORT, - CONFIG_TOUCHPAD_I2C_ADDR_FLAGS, - cmd, sizeof(cmd), NULL, 0, I2C_XFER_START); - if (rv) - goto fail; - rv = i2c_xfer_unlocked(CONFIG_TOUCHPAD_I2C_PORT, - CONFIG_TOUCHPAD_I2C_ADDR_FLAGS, - data, elan_tp_params.page_size, NULL, 0, 0); - if (rv) - goto fail; - rv = i2c_xfer_unlocked(CONFIG_TOUCHPAD_I2C_PORT, - CONFIG_TOUCHPAD_I2C_ADDR_FLAGS, - (uint8_t *)&checksum, sizeof(checksum), NULL, 0, - I2C_XFER_STOP); - if (rv) - goto fail; - -fail: - i2c_lock(CONFIG_TOUCHPAD_I2C_PORT, 0); - if (rv) - return rv; - msleep(elan_tp_params.page_size >= 512 ? 50 : 35); - - rv = elan_tp_read_cmd(ETP_I2C_IAP_CTRL_CMD, &rx_buf); - - if (rv || (rx_buf & (ETP_FW_IAP_PAGE_ERR | ETP_FW_IAP_INTF_ERR))) { - CPRINTS("%s: IAP reports failed write : %x.", - __func__, rx_buf); - return EC_ERROR_UNKNOWN; - } - return 0; -} - -int touchpad_update_write(int offset, int size, const uint8_t *data) -{ - static int iap_addr = -1; - int addr, rv; - - CPRINTS("%s %08x %d", __func__, offset, size); - - if (offset == 0) { - /* Verify the IC type is aligned with defined firmware size */ - if (elan_tp_params.page_size * elan_tp_params.page_count - != FW_SIZE) { - CPRINTS("%s: IC(%d*%d) size and FW_SIZE(%d) mismatch", - __func__, elan_tp_params.page_count, - elan_tp_params.page_size, FW_SIZE); - return EC_ERROR_UNKNOWN; - } - - gpio_disable_interrupt(GPIO_TOUCHPAD_INT); - CPRINTS("%s: prepare fw update.", __func__); - rv = elan_prepare_for_update(); - if (rv) - return rv; - iap_addr = 0; - } - - if (offset <= (ETP_IAP_START_ADDR * 2) && - (ETP_IAP_START_ADDR * 2) < (offset + size)) { - iap_addr = ((data[ETP_IAP_START_ADDR * 2 - offset + 1] << 8) | - data[ETP_IAP_START_ADDR * 2 - offset]) << 1; - CPRINTS("%s: payload starts from 0x%x.", __func__, iap_addr); - } - - /* Data that comes in must align with page_size */ - if (offset % elan_tp_params.page_size) - return EC_ERROR_INVAL; - - for (addr = offset; addr < (offset + size); - addr += elan_tp_params.page_size) { - if (iap_addr > addr) /* Skip chunk */ - continue; - rv = touchpad_update_page(data + addr - offset); - if (rv) - return rv; - CPRINTF("/p%d", addr / elan_tp_params.page_size); - watchdog_reload(); - } - CPRINTF("\n"); - - if (offset + size == FW_SIZE) { - CPRINTS("%s: End update, wait for reset.", __func__); - hook_call_deferred(&elan_tp_init_data, 600 * MSEC); - } - return EC_SUCCESS; -} - -/* Debugging mode. */ - -/* Allowed debug commands. We only store a hash of the allowed commands. */ -#define TOUCHPAD_ELAN_DEBUG_CMD_LENGTH 50 -#define TOUCHPAD_ELAN_DEBUG_NUM_CMD 2 - -static const uint8_t -allowed_command_hashes[TOUCHPAD_ELAN_DEBUG_NUM_CMD][SHA256_DIGEST_SIZE] = { - { - 0x0a, 0xf6, 0x37, 0x03, 0x93, 0xb2, 0xde, 0x8c, - 0x56, 0x7b, 0x86, 0xba, 0xa6, 0x79, 0xe3, 0xa3, - 0x8b, 0xc7, 0x15, 0xf2, 0x53, 0xcf, 0x71, 0x8b, - 0x3d, 0xe4, 0x81, 0xf9, 0xd9, 0xa8, 0x78, 0x48 - }, - { - 0xac, 0xe5, 0xbf, 0x17, 0x1f, 0xde, 0xce, 0x76, - 0x0c, 0x0e, 0xf8, 0xa2, 0xe9, 0x67, 0x2d, 0xc9, - 0x1b, 0xd4, 0xba, 0x34, 0x51, 0xca, 0xf6, 0x6d, - 0x7b, 0xb2, 0x1f, 0x14, 0x82, 0x1c, 0x0b, 0x74 - }, -}; - -/* Debugging commands need to allocate a <=1k buffer. */ -SHARED_MEM_CHECK_SIZE(1024); - -int touchpad_debug(const uint8_t *param, unsigned int param_size, - uint8_t **data, unsigned int *data_size) -{ - static uint8_t *buffer; - static unsigned int buffer_size; - unsigned int offset; - - /* Offset parameter is 1 byte. */ - if (param_size < 1) - return EC_RES_INVALID_PARAM; - - /* - * Debug command, compute SHA-256, check that it matches allowed hashes, - * and execute I2C command. - * - * param[0] must be 0xff - * param[1] is the offset of the command in the data - * param[2] is the command length - * param[3-4] is the read-back length (MSB first), can be 0 - * param[5-49] is verified using SHA-256 hash. - */ - if (param[0] == 0xff && param_size == TOUCHPAD_ELAN_DEBUG_CMD_LENGTH) { - struct sha256_ctx ctx; - uint8_t *command_hash; - unsigned int offset = param[1]; - unsigned int write_length = param[2]; - unsigned int read_length = - ((unsigned int)param[3] << 8) | param[4]; - int i; - int match; - int rv; - - if (offset < 5 || write_length == 0 || - (offset + write_length) >= TOUCHPAD_ELAN_DEBUG_CMD_LENGTH) - return EC_RES_INVALID_PARAM; - - SHA256_init(&ctx); - SHA256_update(&ctx, param+5, TOUCHPAD_ELAN_DEBUG_CMD_LENGTH-5); - command_hash = SHA256_final(&ctx); - - match = 0; - for (i = 0; i < TOUCHPAD_ELAN_DEBUG_NUM_CMD; i++) { - if (!memcmp(command_hash, allowed_command_hashes[i], - sizeof(allowed_command_hashes[i]))) { - match = 1; - break; - } - } - - if (!match) - return EC_RES_INVALID_PARAM; - - if (buffer) { - shared_mem_release(buffer); - buffer = NULL; - } - - buffer_size = read_length; - - if (read_length > 0) { - if (shared_mem_acquire(buffer_size, - (char **)&buffer) != EC_SUCCESS) { - buffer = NULL; - buffer_size = 0; - return EC_RES_BUSY; - } - - memset(buffer, 0, buffer_size); - } - - rv = i2c_xfer(CONFIG_TOUCHPAD_I2C_PORT, - CONFIG_TOUCHPAD_I2C_ADDR_FLAGS, - ¶m[offset], write_length, - buffer, read_length); - - if (rv) - return EC_RES_BUS_ERROR; - - return EC_RES_SUCCESS; - } - - /* - * Data request: Retrieve previously read data from buffer, in blocks of - * 64 bytes. - */ - offset = param[0] * 64; - - if (!buffer) - return EC_RES_UNAVAILABLE; - - if (offset >= buffer_size) { - shared_mem_release(buffer); - buffer = NULL; - *data = NULL; - *data_size = 0; - return EC_RES_OVERFLOW; - } - - *data = buffer + offset; - *data_size = MIN(64, buffer_size - offset); - - return EC_RES_SUCCESS; -} -#endif - -/* - * Try to read touchpad report up to 3 times, reset the touchpad if we still - * fail. - */ -void elan_tp_read_report_retry(void) -{ - int ret; - int retry = 3; - - while (retry--) { - ret = elan_tp_read_report(); - - if (ret <= 0) - return; - - /* Try again */ - msleep(1); - } - - /* Failed to read data, reset the touchpad. */ - CPRINTF("Resetting TP.\n"); - board_touchpad_reset(); - elan_tp_init(); -} - -void touchpad_interrupt(enum gpio_signal signal) -{ - irq_ts = __hw_clock_source_read(); - - task_wake(TASK_ID_TOUCHPAD); -} - -/* Make a decision on touchpad power, based on USB and tablet mode status. */ -static void touchpad_power_control(void) -{ - static int enabled = 1; - int enable = 1; - -#ifdef CONFIG_USB_SUSPEND - enable = enable && - (!usb_is_suspended() || usb_is_remote_wakeup_enabled()); -#endif - -#ifdef CONFIG_TABLET_MODE - enable = enable && !tablet_get_mode(); -#endif - - if (enabled == enable) - return; - - elan_tp_set_power(enable); - - enabled = enable; -} - -void touchpad_task(void *u) -{ - uint32_t event; - - elan_tp_init(); - touchpad_power_control(); - - while (1) { - event = task_wait_event(-1); - - if (event & TASK_EVENT_WAKE) - elan_tp_read_report_retry(); - - if (event & TASK_EVENT_POWER) - touchpad_power_control(); - } -} - -/* - * When USB PM status changes, or tablet mode changes, call in the main task to - * decide whether to turn touchpad on or off. - */ -#if defined(CONFIG_USB_SUSPEND) || defined(CONFIG_TABLET_MODE) -static void touchpad_power_change(void) -{ - task_set_event(TASK_ID_TOUCHPAD, TASK_EVENT_POWER); -} -#endif -#ifdef CONFIG_USB_SUSPEND -DECLARE_HOOK(HOOK_USB_PM_CHANGE, touchpad_power_change, HOOK_PRIO_DEFAULT); -#endif -#ifdef CONFIG_TABLET_MODE -DECLARE_HOOK(HOOK_TABLET_MODE_CHANGE, touchpad_power_change, HOOK_PRIO_DEFAULT); -#endif diff --git a/driver/touchpad_gt7288.c b/driver/touchpad_gt7288.c deleted file mode 100644 index ac05b88323..0000000000 --- a/driver/touchpad_gt7288.c +++ /dev/null @@ -1,227 +0,0 @@ -/* Copyright 2019 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 <stdbool.h> - -#include "common.h" -#include "console.h" -#include "hooks.h" -#include "i2c.h" -#include "task.h" -#include "touchpad_gt7288.h" -#include "util.h" - -/* Define this to enable various warning messages during report parsing. */ -#undef DEBUG_CHECKS - -#define CPRINTS(format, args...) cprints(CC_TOUCHPAD, format, ## args) - -#define GT7288_I2C_ADDR_FLAGS 0x14 - -#define GT7288_REPORT_ID_PTP 0x04 - -#define GT7288_BUTTON_STATE_UP 0x80 -#define GT7288_BUTTON_STATE_DOWN 0x81 - -#define GT7288_REG_HID_DESCRIPTOR 0x0001 -#define GT7288_REG_REPORT_DESCRIPTOR 0x0002 - -#define GT7288_HID_DESCRIPTOR_LENGTH 0x1E -#define GT7288_REPORT_DESCRIPTOR_LENGTH 0x1AE -#define GT7288_REPORT_LENGTH 16 - -/** - * Reads a descriptor using the Conventional Read Mode. - * - * @param[in] register_id The register containing the descriptor to read. - * @param[out] data The data that is read. - * @param[in] max_length The maximum length of data. - * - * @return EC_SUCCESS or an error code. - */ -static int gt7288_read_desc(uint16_t register_id, uint8_t *data, - size_t max_length) -{ - uint8_t reg_bytes[] = { - register_id & 0xFF, (register_id & 0xFF00) >> 8 - }; - return i2c_xfer(CONFIG_TOUCHPAD_I2C_PORT, GT7288_I2C_ADDR_FLAGS, - reg_bytes, sizeof(reg_bytes), data, max_length); -} - -int gt7288_get_version_info(struct gt7288_version_info *info) -{ - uint8_t data[GT7288_HID_DESCRIPTOR_LENGTH]; - - RETURN_ERROR(gt7288_read_desc(GT7288_REG_HID_DESCRIPTOR, data, - sizeof(data))); - info->product_id = UINT16_FROM_BYTE_ARRAY_LE(data, 22); - info->version_id = UINT16_FROM_BYTE_ARRAY_LE(data, 24); - return EC_SUCCESS; -} - -static void gt7288_translate_contact(const uint8_t *data, - struct gt7288_contact *contact) -{ - if (IS_ENABLED(DEBUG_CHECKS)) { - uint8_t report_id = data[2]; - - if (report_id != GT7288_REPORT_ID_PTP) { - CPRINTS("WARNING: unexpected report ID 0x%02X (expected 0x%02X).", - report_id, GT7288_REPORT_ID_PTP); - } - } - - contact->id = data[3] >> 4; - /* Note: these bits appear to be in the wrong order in the programming - * guide, verified by experimentation. - */ - contact->tip = (data[3] & BIT(1)) >> 1; - contact->confidence = data[3] & BIT(0); - contact->x = UINT16_FROM_BYTE_ARRAY_LE(data, 4); - contact->y = UINT16_FROM_BYTE_ARRAY_LE(data, 6); - contact->width = data[12]; - contact->height = data[13]; -} - -static int gt7288_read(uint8_t *data, size_t max_length) -{ - return i2c_xfer(CONFIG_TOUCHPAD_I2C_PORT, GT7288_I2C_ADDR_FLAGS, - NULL, 0, data, max_length); -} - -int gt7288_read_ptp_report(struct gt7288_ptp_report *report) -{ - size_t i; - uint8_t data[GT7288_REPORT_LENGTH]; - - RETURN_ERROR(gt7288_read(data, sizeof(data))); - report->timestamp = UINT16_FROM_BYTE_ARRAY_LE(data, 8); - - if (data[10] > GT7288_MAX_CONTACTS) { - if (IS_ENABLED(DEBUG_CHECKS)) - CPRINTS("ERROR: too many contacts (%d > %d).", - data[10], GT7288_MAX_CONTACTS); - return EC_ERROR_HW_INTERNAL; - } - report->num_contacts = data[10]; - - if (IS_ENABLED(DEBUG_CHECKS) && data[11] != GT7288_BUTTON_STATE_UP && - data[11] != GT7288_BUTTON_STATE_DOWN) { - CPRINTS("WARNING: unexpected button state 0x%02X (expected 0x%02X or 0x%02X).", - data[11], GT7288_BUTTON_STATE_UP, - GT7288_BUTTON_STATE_DOWN); - } - report->button_down = data[11] == GT7288_BUTTON_STATE_DOWN; - - gt7288_translate_contact(data, &report->contacts[0]); - - for (i = 1; i < report->num_contacts; i++) { - RETURN_ERROR(gt7288_read(data, sizeof(data))); - gt7288_translate_contact(data, &report->contacts[i]); - } - return EC_SUCCESS; -} - -#ifdef CONFIG_CMD_GT7288 -static int command_gt7288_read_desc(int argc, char **argv) -{ - uint16_t register_id; - long parsed_arg; - char *end; - int i; - uint8_t data[GT7288_HID_DESCRIPTOR_LENGTH]; - - if (argc != 2) - return EC_ERROR_PARAM_COUNT; - - parsed_arg = strtoi(argv[1], &end, 0); - if (parsed_arg < 0 || parsed_arg > UINT16_MAX || end == argv[1]) - return EC_ERROR_PARAM1; - register_id = parsed_arg; - - RETURN_ERROR(gt7288_read_desc(register_id, data, sizeof(data))); - - ccprintf("Data: "); - for (i = 0; i < sizeof(data); i++) - ccprintf("%02X ", data[i]); - ccprintf("\n"); - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(gt7288_desc, command_gt7288_read_desc, - "register", - "Read a descriptor on the GT7288"); - -static int command_gt7288_read_report_descriptor(int argc, char **argv) -{ - int i; - uint8_t data[64]; - size_t bytes_read = 0; - - if (argc != 1) - return EC_ERROR_PARAM_COUNT; - - /* The report descriptor is bigger than the Maxim I2C code can handle in - * one go, so we have to split it into chunks. - */ - RETURN_ERROR(gt7288_read_desc(GT7288_REG_REPORT_DESCRIPTOR, NULL, 0)); - ccprintf("Report descriptor: "); - while (bytes_read < GT7288_REPORT_DESCRIPTOR_LENGTH) { - size_t bytes_to_read = - MIN(GT7288_REPORT_DESCRIPTOR_LENGTH - bytes_read, - sizeof(data)); - RETURN_ERROR(gt7288_read(data, bytes_to_read)); - - for (i = 0; i < sizeof(data); i++) - ccprintf("%02X ", data[i]); - - bytes_read += bytes_to_read; - } - ccprintf("\n"); - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(gt7288_repdesc, command_gt7288_read_report_descriptor, - "", "Read the report descriptor on the GT7288"); - -static int command_gt7288_ver(int argc, char **argv) -{ - struct gt7288_version_info info; - - if (argc != 1) - return EC_ERROR_PARAM_COUNT; - - RETURN_ERROR(gt7288_get_version_info(&info)); - ccprintf("Product ID: 0x%04X\n", info.product_id); - ccprintf("Version ID: 0x%04X\n", info.version_id); - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(gt7288_ver, command_gt7288_ver, "", - "Read version information from the GT7288"); - -static int command_gt7288_report(int argc, char **argv) -{ - int i; - struct gt7288_ptp_report report; - - RETURN_ERROR(gt7288_read_ptp_report(&report)); - ccprintf("Timestamp %d, button %s, %d contacts\n", report.timestamp, - report.button_down ? "down" : "up", report.num_contacts); - if (report.num_contacts == 0) - return EC_SUCCESS; - - ccprintf("ID, X, Y, width, height, tip, confidence\n"); - for (i = 0; i < report.num_contacts; i++) { - struct gt7288_contact *contact = &report.contacts[i]; - - ccprintf("%2d, %4d, %4d, %5d, %6d, %3d, %10d\n", contact->id, - contact->x, contact->y, contact->width, - contact->height, contact->tip, contact->confidence); - } - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(gt7288_rep, command_gt7288_report, "", - "Read a report from the GT7288."); -#endif /* CONFIG_CMD_GT7288 */ diff --git a/driver/touchpad_gt7288.h b/driver/touchpad_gt7288.h deleted file mode 100644 index c89c586784..0000000000 --- a/driver/touchpad_gt7288.h +++ /dev/null @@ -1,84 +0,0 @@ -/* Copyright 2019 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. - */ - -/* Driver for the Goodix GT7288 touch controller. */ - -#ifndef __CROS_EC_TOUCHPAD_GT7288_H -#define __CROS_EC_TOUCHPAD_GT7288_H - -#include <stdbool.h> -#include <stddef.h> - -/* The maximum number of contacts that can be reported at once. */ -#define GT7288_MAX_CONTACTS 5 - -/** - * Version information for the chip. - */ -struct gt7288_version_info { - /** HID product ID (0x01F0 for touchpads, 0x01F1 for touchscreens). */ - uint16_t product_id; - /** - * The firmware version. For touchpads equipped with a fingerprint - * sensor, the MSB will be 1. - */ - uint16_t version_id; -}; - -/** - * Reads version information from the GT7288. - * - * @param[out] info The version information. - * - * @return EC_SUCCESS or an error code. - */ -int gt7288_get_version_info(struct gt7288_version_info *info); - -/** - * Data describing a single contact. - */ -struct gt7288_contact { - /** - * A 4-bit ID that uniquely identifies the contact during its lifecycle. - */ - uint8_t id; - /** The absolute X coordinate. */ - uint16_t x; - /** The absolute Y coordinate. */ - uint16_t y; - /** The width of the contact (with firmware version 4 or greater). */ - uint8_t width; - /** The height of the contact (with firmware version 4 or greater). */ - uint8_t height; - /** Whether the finger is touching the pad. (Currently always true.) */ - bool tip; - /** Whether the touch is a finger (true) or palm (false). */ - bool confidence; -}; - -/** - * Data from a complete report in PTP mode. - */ -struct gt7288_ptp_report { - /** A relative timestamp, in units of 100µs. */ - uint16_t timestamp; - /** The number of contacts on the pad. */ - size_t num_contacts; - /** Whether the button is pressed. */ - bool button_down; - /** An array of structs describing the individual contacts. */ - struct gt7288_contact contacts[GT7288_MAX_CONTACTS]; -}; - -/** - * Reads a complete report, when the GT7288 is in PTP mode. - * - * @param[out] report The report that is read. - * - * @return EC_SUCCESS or an error code. - */ -int gt7288_read_ptp_report(struct gt7288_ptp_report *report); - -#endif /* __CROS_EC_TOUCHPAD_GT7288_H */ diff --git a/driver/touchpad_st.c b/driver/touchpad_st.c deleted file mode 100644 index 56633bad16..0000000000 --- a/driver/touchpad_st.c +++ /dev/null @@ -1,1895 +0,0 @@ -/* Copyright 2018 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 "atomic.h" -#include "board.h" -#include "common.h" -#include "console.h" -#include "gpio.h" -#include "hwtimer.h" -#include "hooks.h" -#include "i2c.h" -#include "registers.h" -#include "spi.h" -#include "task.h" -#include "tablet_mode.h" -#include "timer.h" -#include "touchpad.h" -#include "touchpad_st.h" -#include "update_fw.h" -#include "usb_api.h" -#include "usb_hid_touchpad.h" -#include "usb_isochronous.h" -#include "util.h" -#include "watchdog.h" - -/* Console output macros */ -#define CC_TOUCHPAD CC_USB -#define CPUTS(outstr) cputs(CC_TOUCHPAD, outstr) -#define CPRINTF(format, args...) cprintf(CC_TOUCHPAD, format, ## args) -#define CPRINTS(format, args...) cprints(CC_TOUCHPAD, format, ## args) - -#define TASK_EVENT_POWER TASK_EVENT_CUSTOM_BIT(0) -#define TASK_EVENT_TP_UPDATED TASK_EVENT_CUSTOM_BIT(1) - -#define SPI (&(spi_devices[SPI_ST_TP_DEVICE_ID])) - -BUILD_ASSERT(sizeof(struct st_tp_event_t) == 8); -BUILD_ASSERT(BYTES_PER_PIXEL == 1); - -/* Function prototypes */ -static int st_tp_panel_init(int full); -static int st_tp_read_all_events(int show_error); -static int st_tp_read_host_buffer_header(void); -static int st_tp_send_ack(void); -static int st_tp_start_scan(void); -static int st_tp_stop_scan(void); -static int st_tp_update_system_state(int new_state, int mask); -static void touchpad_power_control(void); - -/* Global variables */ -/* - * Current system state, meaning of each bit is defined below. - */ -static int system_state; - -#define SYSTEM_STATE_DEBUG_MODE BIT(0) -#define SYSTEM_STATE_ENABLE_HEAT_MAP BIT(1) -#define SYSTEM_STATE_ENABLE_DOME_SWITCH BIT(2) -#define SYSTEM_STATE_ACTIVE_MODE BIT(3) -#define SYSTEM_STATE_DOME_SWITCH_LEVEL BIT(4) -#define SYSTEM_STATE_READY BIT(5) - -/* - * Pending action for touchpad. - */ -static int tp_control; - -#define TP_CONTROL_SHALL_HALT BIT(0) -#define TP_CONTROL_SHALL_RESET BIT(1) -#define TP_CONTROL_SHALL_INIT BIT(2) -#define TP_CONTROL_SHALL_INIT_FULL BIT(3) -#define TP_CONTROL_SHALL_DUMP_ERROR BIT(4) -#define TP_CONTROL_RESETTING BIT(5) -#define TP_CONTROL_INIT BIT(6) -#define TP_CONTROL_INIT_FULL BIT(7) - -/* - * Number of times we have reset the touchpad because of errors. - */ -static int tp_reset_retry_count; - -#define MAX_TP_RESET_RETRY_COUNT 3 - -static int dump_memory_on_error; - -/* - * Bitmap to track if a finger exists. - */ -static int touch_slot; - -/* - * Timestamp of last interrupt (32 bits are enough as we divide the value by 100 - * and then put it in a 16-bit field). - */ -static uint32_t irq_ts; - -/* - * Cached system info. - */ -static struct st_tp_system_info_t system_info; - -static struct { -#if ST_TP_EXTRA_BYTE == 1 - uint8_t extra_byte; -#endif - union { - uint8_t bytes[512]; - struct st_tp_host_buffer_header_t buffer_header; - struct st_tp_host_buffer_heat_map_t heat_map; - struct st_tp_host_data_header_t data_header; - struct st_tp_event_t events[32]; - uint32_t dump_info[32]; - } /* anonymous */; -} __packed rx_buf; - - -#ifdef CONFIG_USB_ISOCHRONOUS -#define USB_ISO_PACKET_SIZE 256 -/* - * Header of each USB pacaket. - */ -struct packet_header_t { - uint8_t index; - -#define HEADER_FLAGS_NEW_FRAME BIT(0) - uint8_t flags; -} __packed; -BUILD_ASSERT(sizeof(struct packet_header_t) < USB_ISO_PACKET_SIZE); - -static struct packet_header_t packet_header; - -/* What will be sent to USB interface. */ -struct st_tp_usb_packet_t { -#define USB_FRAME_FLAGS_BUTTON BIT(0) - /* - * This will be true if user clicked on touchpad. - * TODO(b/70482333): add corresponding code for button signal. - */ - uint8_t flags; - - /* - * This will be `st_tp_host_buffer_heat_map_t.frame` but each pixel - * will be scaled to 8 bits value. - */ - uint8_t frame[ST_TOUCH_ROWS * ST_TOUCH_COLS]; -} __packed; - -/* Next buffer index SPI will write to. */ -static volatile uint32_t spi_buffer_index; -/* Next buffer index USB will read from. */ -static volatile uint32_t usb_buffer_index; -static struct st_tp_usb_packet_t usb_packet[2]; /* double buffering */ -/* How many bytes we have transmitted. */ -static size_t transmit_report_offset; - -/* Function prototypes */ -static int get_heat_map_addr(void); -static void print_frame(void); -static void st_tp_disable_heat_map(void); -static void st_tp_enable_heat_map(void); -static int st_tp_read_frame(void); -static void st_tp_interrupt_send(void); -DECLARE_DEFERRED(st_tp_interrupt_send); -#endif - - -/* Function implementations */ - -static void set_bits(int *lvalue, int rvalue, int mask) -{ - *lvalue &= ~mask; - *lvalue |= rvalue & mask; -} - -/* - * Parse a finger report from ST event and save it to (report)->finger. - * - * @param report: pointer to a USB HID touchpad report. - * @param event: a pointer event from ST. - * @param i: array index for next finger. - * - * @return array index of next finger (i.e. (i + 1) if a finger is added). - */ -static int st_tp_parse_finger(struct usb_hid_touchpad_report *report, - struct st_tp_event_t *event, - int i) -{ - const int id = event->finger.touch_id; - - /* This is not a finger */ - if (event->finger.touch_type == ST_TP_TOUCH_TYPE_INVALID) - return i; - - if (event->evt_id == ST_TP_EVENT_ID_ENTER_POINTER) - touch_slot |= 1 << id; - else if (event->evt_id == ST_TP_EVENT_ID_LEAVE_POINTER) - touch_slot &= ~BIT(id); - - /* We cannot report more fingers */ - if (i >= ARRAY_SIZE(report->finger)) { - CPRINTS("WARN: ST reports more than %d fingers", i); - return i; - } - - switch (event->evt_id) { - case ST_TP_EVENT_ID_ENTER_POINTER: - case ST_TP_EVENT_ID_MOTION_POINTER: - /* Pressure == 255 is a palm. */ - report->finger[i].confidence = (event->finger.z < 255); - report->finger[i].tip = 1; - report->finger[i].inrange = 1; - report->finger[i].id = id; - report->finger[i].pressure = event->finger.z; - report->finger[i].width = (event->finger.minor | - (event->minor_high << 4)) << 5; - report->finger[i].height = (event->finger.major | - (event->major_high << 4)) << 5; - - report->finger[i].x = (CONFIG_USB_HID_TOUCHPAD_LOGICAL_MAX_X - - event->finger.x); - report->finger[i].y = (CONFIG_USB_HID_TOUCHPAD_LOGICAL_MAX_Y - - event->finger.y); - break; - case ST_TP_EVENT_ID_LEAVE_POINTER: - report->finger[i].id = id; - /* When a finger is leaving, it's not a palm */ - report->finger[i].confidence = 1; - break; - } - return i + 1; -} - -/* - * Read domeswitch level from touchpad, and save in `system_state`. - * - * After calling this function, use - * `system_state & SYSTEM_STATE_DOME_SWITCH_LEVEL` - * to get current value. - * - * @return error code on failure. - */ -static int st_tp_check_domeswitch_state(void) -{ - int ret = st_tp_read_host_buffer_header(); - - if (ret) - return ret; - - ret = rx_buf.buffer_header.flags & ST_TP_BUFFER_HEADER_DOMESWITCH_LVL; - /* - * Domeswitch level from device is inverted. - * That is, 0 => pressed, 1 => released. - */ - set_bits(&system_state, - ret ? 0 : SYSTEM_STATE_DOME_SWITCH_LEVEL, - SYSTEM_STATE_DOME_SWITCH_LEVEL); - return 0; -} - -static int st_tp_write_hid_report(void) -{ - int ret, i, num_finger, num_events; - const int old_system_state = system_state; - int domeswitch_changed; - struct usb_hid_touchpad_report report; - - ret = st_tp_check_domeswitch_state(); - if (ret) - return ret; - - domeswitch_changed = ((old_system_state ^ system_state) & - SYSTEM_STATE_DOME_SWITCH_LEVEL); - - num_events = st_tp_read_all_events(1); - if (tp_control) - return 1; - - memset(&report, 0, sizeof(report)); - report.id = REPORT_ID_TOUCHPAD; - num_finger = 0; - - for (i = 0; i < num_events; i++) { - struct st_tp_event_t *e = &rx_buf.events[i]; - - switch (e->evt_id) { - case ST_TP_EVENT_ID_ENTER_POINTER: - case ST_TP_EVENT_ID_MOTION_POINTER: - case ST_TP_EVENT_ID_LEAVE_POINTER: - num_finger = st_tp_parse_finger(&report, e, num_finger); - break; - default: - break; - } - } - - if (!num_finger && !domeswitch_changed) /* nothing changed */ - return 0; - - /* Don't report 0 finger click. */ - if (num_finger && (system_state & SYSTEM_STATE_DOME_SWITCH_LEVEL)) - report.button = 1; - report.count = num_finger; - report.timestamp = irq_ts / USB_HID_TOUCHPAD_TIMESTAMP_UNIT; - - set_touchpad_report(&report); - return 0; -} - -static int st_tp_read_report(void) -{ - if (system_state & SYSTEM_STATE_ENABLE_HEAT_MAP) { -#ifdef CONFIG_USB_ISOCHRONOUS - /* - * Because we are using double buffering, so, if - * usb_buffer_index = N - * - * 1. spi_buffer_index == N => ok, both slots are empty - * 2. spi_buffer_index == N + 1 => ok, second slot is empty - * 3. spi_buffer_index == N + 2 => not ok, need to wait for USB - */ - if (spi_buffer_index - usb_buffer_index <= 1) { - if (st_tp_read_frame() == EC_SUCCESS) { - spi_buffer_index++; - if (system_state & SYSTEM_STATE_DEBUG_MODE) { - print_frame(); - usb_buffer_index++; - } - } - } - if (spi_buffer_index > usb_buffer_index) - hook_call_deferred(&st_tp_interrupt_send_data, 0); -#endif - } else { - st_tp_write_hid_report(); - } - return st_tp_send_ack(); -} - -static int st_tp_read_host_buffer_header(void) -{ - const uint8_t tx_buf[] = { ST_TP_CMD_READ_SPI_HOST_BUFFER, 0x00, 0x00 }; - int rx_len = ST_TP_EXTRA_BYTE + sizeof(rx_buf.buffer_header); - - return spi_transaction(SPI, tx_buf, sizeof(tx_buf), - (uint8_t *)&rx_buf, rx_len); -} - -static int st_tp_send_ack(void) -{ - uint8_t tx_buf[] = { ST_TP_CMD_SPI_HOST_BUFFER_ACK }; - - return spi_transaction(SPI, tx_buf, sizeof(tx_buf), NULL, 0); -} - -static int st_tp_update_system_state(int new_state, int mask) -{ - int ret = EC_SUCCESS; - int need_locked_scan_mode = 0; - - /* copy reserved bits */ - set_bits(&new_state, system_state, ~mask); - - mask = SYSTEM_STATE_DEBUG_MODE; - if ((new_state & mask) != (system_state & mask)) - set_bits(&system_state, new_state, mask); - - mask = SYSTEM_STATE_ENABLE_HEAT_MAP | SYSTEM_STATE_ENABLE_DOME_SWITCH; - if ((new_state & mask) != (system_state & mask)) { - uint8_t tx_buf[] = { - ST_TP_CMD_WRITE_FEATURE_SELECT, - 0x05, - 0 - }; - if (new_state & SYSTEM_STATE_ENABLE_HEAT_MAP) { - CPRINTS("Heatmap enabled"); - tx_buf[2] |= BIT(0); - need_locked_scan_mode = 1; - } else { - CPRINTS("Heatmap disabled"); - } - - if (new_state & SYSTEM_STATE_ENABLE_DOME_SWITCH) - tx_buf[2] |= BIT(1); - ret = spi_transaction(SPI, tx_buf, sizeof(tx_buf), NULL, 0); - if (ret) - return ret; - set_bits(&system_state, new_state, mask); - } - - mask = SYSTEM_STATE_ACTIVE_MODE; - if ((new_state & mask) != (system_state & mask)) { - uint8_t tx_buf[] = { - ST_TP_CMD_WRITE_SCAN_MODE_SELECT, - ST_TP_SCAN_MODE_ACTIVE, - !!(new_state & SYSTEM_STATE_ACTIVE_MODE), - }; - CPRINTS("Enable Multi-Touch: %d", tx_buf[2]); - ret = spi_transaction(SPI, tx_buf, sizeof(tx_buf), NULL, 0); - if (ret) - return ret; - set_bits(&system_state, new_state, mask); - } - - /* - * We need to lock scan mode to prevent scan rate drop when heat map - * mode is enabled. - */ - if (need_locked_scan_mode) { - uint8_t tx_buf[] = { - ST_TP_CMD_WRITE_SCAN_MODE_SELECT, - ST_TP_SCAN_MODE_LOCKED, - 0x0, - }; - - ret = spi_transaction(SPI, tx_buf, sizeof(tx_buf), NULL, 0); - if (ret) - return ret; - } - return ret; -} - -static void st_tp_enable_interrupt(int enable) -{ - uint8_t tx_buf[] = { - ST_TP_CMD_WRITE_SYSTEM_COMMAND, 0x01, enable ? 1 : 0}; - if (enable) - gpio_enable_interrupt(GPIO_TOUCHPAD_INT); - spi_transaction(SPI, tx_buf, sizeof(tx_buf), NULL, 0); - if (!enable) - gpio_disable_interrupt(GPIO_TOUCHPAD_INT); -} - -static int st_tp_start_scan(void) -{ - int new_state = (SYSTEM_STATE_ACTIVE_MODE | - SYSTEM_STATE_ENABLE_DOME_SWITCH); - int mask = new_state; - int ret; - - CPRINTS("ST: Start scanning"); - ret = st_tp_update_system_state(new_state, mask); - if (ret) - return ret; - st_tp_send_ack(); - st_tp_enable_interrupt(1); - - return ret; -} - -static int st_tp_read_host_data_memory(uint16_t addr, void *rx_buf, int len) -{ - uint8_t tx_buf[] = { - ST_TP_CMD_READ_HOST_DATA_MEMORY, addr >> 8, addr & 0xFF - }; - - return spi_transaction(SPI, tx_buf, sizeof(tx_buf), rx_buf, len); -} - -static int st_tp_stop_scan(void) -{ - int new_state = 0; - int mask = SYSTEM_STATE_ACTIVE_MODE; - int ret; - - CPRINTS("ST: Stop scanning"); - ret = st_tp_update_system_state(new_state, mask); - st_tp_enable_interrupt(0); - - return ret; -} - -static int st_tp_load_host_data(uint8_t mem_id) -{ - uint8_t tx_buf[] = { - ST_TP_CMD_WRITE_SYSTEM_COMMAND, 0x06, mem_id - }; - int retry, ret; - uint16_t count; - struct st_tp_host_data_header_t *header = &rx_buf.data_header; - int rx_len = sizeof(*header) + ST_TP_EXTRA_BYTE; - - st_tp_read_host_data_memory(0x0000, &rx_buf, rx_len); - if (header->host_data_mem_id == mem_id) - return EC_SUCCESS; /* already loaded no need to reload */ - - count = header->count; - - ret = spi_transaction(SPI, tx_buf, sizeof(tx_buf), NULL, 0); - if (ret) - return ret; - - ret = EC_ERROR_TIMEOUT; - retry = 5; - while (retry--) { - st_tp_read_host_data_memory(0x0000, &rx_buf, rx_len); - if (header->magic == ST_TP_HEADER_MAGIC && - header->host_data_mem_id == mem_id && - header->count != count) { - ret = EC_SUCCESS; - break; - } - msleep(10); - } - return ret; -} - -/* - * Read System Info from Host Data Memory. - * - * @param reload: true to force reloading system info into host data memory - * before reading. - */ -static int st_tp_read_system_info(int reload) -{ - int ret = EC_SUCCESS; - int rx_len = ST_TP_EXTRA_BYTE + ST_TP_SYSTEM_INFO_LEN; - uint8_t *ptr = rx_buf.bytes; - - if (reload) - ret = st_tp_load_host_data(ST_TP_MEM_ID_SYSTEM_INFO); - if (ret) - return ret; - ret = st_tp_read_host_data_memory(0x0000, &rx_buf, rx_len); - if (ret) - return ret; - - /* Parse the content */ - memcpy(&system_info, ptr, ST_TP_SYSTEM_INFO_PART_1_SIZE); - - /* Check header */ - if (system_info.header.magic != ST_TP_HEADER_MAGIC || - system_info.header.host_data_mem_id != ST_TP_MEM_ID_SYSTEM_INFO) - return EC_ERROR_UNKNOWN; - - ptr += ST_TP_SYSTEM_INFO_PART_1_SIZE; - ptr += ST_TP_SYSTEM_INFO_PART_1_RESERVED; - memcpy(&system_info.scr_res_x, ptr, ST_TP_SYSTEM_INFO_PART_2_SIZE); - -#define ST_TP_SHOW(attr) CPRINTS(#attr ": %04x", system_info.attr) - ST_TP_SHOW(chip0_id[0]); - ST_TP_SHOW(chip0_id[1]); - ST_TP_SHOW(chip0_ver); - ST_TP_SHOW(scr_tx_len); - ST_TP_SHOW(scr_rx_len); -#define ST_TP_SHOW64(attr) CPRINTS(#attr ": %04llx", system_info.attr) - ST_TP_SHOW64(release_info); -#undef ST_TP_SHOW -#undef ST_TP_SHOW64 - return ret; -} - -/* - * Enable / disable deep sleep on memory and bus. - * - * Before calling dump_error() and dump_error(), deep sleep should be disabled, - * otherwise response data might be garbage. - */ -static void enable_deep_sleep(int enable) -{ - uint8_t cmd[] = {0xFA, 0x20, 0x00, 0x00, 0x68, enable ? 0x0B : 0x08}; - - spi_transaction(SPI, cmd, sizeof(cmd), NULL, 0); -} - -static void dump_error(void) -{ - uint8_t tx_buf[] = {0xFB, 0x20, 0x01, 0xEF, 0x80}; - int rx_len = sizeof(rx_buf.dump_info) + ST_TP_EXTRA_BYTE; - int i; - - spi_transaction(SPI, tx_buf, sizeof(tx_buf), - (uint8_t *)&rx_buf, rx_len); - - for (i = 0; i < ARRAY_SIZE(rx_buf.dump_info); i += 4) - CPRINTS("%08x %08x %08x %08x", - rx_buf.dump_info[i + 0], rx_buf.dump_info[i + 1], - rx_buf.dump_info[i + 2], rx_buf.dump_info[i + 3]); - msleep(8); -} - -/* - * Dump entire 64K memory on touchpad. - * - * This is very time consuming. For now, let's disable this in production - * build. - */ -static void dump_memory(void) -{ - uint32_t size = 0x10000, rx_len = 512 + ST_TP_EXTRA_BYTE; - uint32_t offset, i; - uint8_t cmd[] = {0xFB, 0x00, 0x10, 0x00, 0x00}; - - if (!dump_memory_on_error) - return; - - for (offset = 0; offset < size; offset += 512) { - cmd[3] = (offset >> 8) & 0xFF; - cmd[4] = (offset >> 0) & 0xFF; - spi_transaction(SPI, cmd, sizeof(cmd), - (uint8_t *)&rx_buf, rx_len); - - for (i = 0; i < rx_len - ST_TP_EXTRA_BYTE; i += 32) { - CPRINTF("%ph %ph %ph %ph " - "%ph %ph %ph %ph\n", - HEX_BUF(rx_buf.bytes + i + 4 * 0, 4), - HEX_BUF(rx_buf.bytes + i + 4 * 1, 4), - HEX_BUF(rx_buf.bytes + i + 4 * 2, 4), - HEX_BUF(rx_buf.bytes + i + 4 * 3, 4), - HEX_BUF(rx_buf.bytes + i + 4 * 4, 4), - HEX_BUF(rx_buf.bytes + i + 4 * 5, 4), - HEX_BUF(rx_buf.bytes + i + 4 * 6, 4), - HEX_BUF(rx_buf.bytes + i + 4 * 7, 4)); - msleep(8); - } - } - CPRINTF("===============================\n"); - msleep(8); -} - -/* - * Set `tp_control` if there are any actions should be taken. - */ -static void st_tp_handle_error(uint8_t error_type) -{ - tp_control |= TP_CONTROL_SHALL_DUMP_ERROR; - - /* - * Suggest action: memory dump and power cycle. - */ - if (error_type <= 0x06 || - error_type == 0xF1 || - error_type == 0xF2 || - error_type == 0xF3 || - (error_type >= 0x47 && error_type <= 0x4E)) { - tp_control |= TP_CONTROL_SHALL_RESET; - return; - } - - /* - * Suggest action: FW shall halt, consult ST. - */ - if ((error_type >= 0x20 && error_type <= 0x23) || - error_type == 0x25 || - (error_type >= 0x2E && error_type <= 0x46)) { - CPRINTS("tp shall halt"); - tp_control |= TP_CONTROL_SHALL_HALT; - return; - } - - /* - * Corrupted panel configuration, a panel init should fix it. - */ - if (error_type >= 0x28 && error_type <= 0x29) { - tp_control |= TP_CONTROL_SHALL_INIT; - return; - } - - /* - * Corrupted CX section, a full panel init should fix it. - */ - if (error_type >= 0xA0 && error_type <= 0xA6) { - tp_control |= TP_CONTROL_SHALL_INIT_FULL; - return; - } - - /* - * When 0xFF is received, it's very likely ST touchpad is down. - * Try if touchpad can be recovered by reset. - */ - if (error_type == 0xFF) { - if (tp_reset_retry_count < MAX_TP_RESET_RETRY_COUNT) { - tp_control |= TP_CONTROL_SHALL_RESET; - tp_reset_retry_count++; - } else { - tp_control |= TP_CONTROL_SHALL_HALT; - } - return; - } -} - -/* - * Handles error reports. - */ -static void st_tp_handle_error_report(struct st_tp_event_t *e) -{ - uint8_t error_type = e->report.report_type; - - CPRINTS("Touchpad error: %x %x", error_type, - ((e->report.info[0] << 0) | (e->report.info[1] << 8) | - (e->report.info[2] << 16) | (e->report.info[3] << 24))); - - st_tp_handle_error(error_type); -} - -static void st_tp_handle_status_report(struct st_tp_event_t *e) -{ - static uint32_t prev_idle_count; - uint32_t info = ((e->report.info[0] << 0) | - (e->report.info[1] << 8) | - (e->report.info[2] << 16) | - (e->report.info[3] << 24)); - - if (e->report.report_type == ST_TP_STATUS_FCAL || - e->report.report_type == ST_TP_STATUS_FRAME_DROP) - CPRINTS("TP STATUS REPORT: %02x %08x", - e->report.report_type, info); - - /* - * Idle count might not change if ST FW is busy (for example, when the - * user puts a big palm on touchpad). Therefore if idle count doesn't - * change, we need to double check with touch count. - * - * If touch count is 0, and idle count doesn't change, it means that: - * - * 1) ST doesn't think there are any fingers. - * 2) ST is busy on something, can't get into idle mode, and this - * might cause (1). - * - * Resetting touchpad should be the correct action. - */ - if (e->report.report_type == ST_TP_STATUS_BEACON) { -#if 0 - const uint8_t touch_count = e->report.reserved; - - CPRINTS("BEACON: idle count=%08x", info); - CPRINTS(" touch count=%d touch slot=%04x", - touch_count, touch_slot); -#endif - if (prev_idle_count == info && touch_slot == 0) { - CPRINTS(" idle count=%08x not changed", info); - tp_control |= TP_CONTROL_SHALL_RESET; - return; - } - prev_idle_count = info; - } -} - -/* - * Read all events, and handle errors. - * - * When there are error events, suggested action will be saved in `tp_control`. - * - * @param show_error: whether EC should read and dump error or not. - * ***If this is true, rx_buf.events[] will be cleared.*** - * - * @return number of events available - */ -static int st_tp_read_all_events(int show_error) -{ - uint8_t cmd = ST_TP_CMD_READ_ALL_EVENTS; - int rx_len = sizeof(rx_buf.events) + ST_TP_EXTRA_BYTE; - int i; - - if (spi_transaction(SPI, &cmd, 1, (uint8_t *)&rx_buf, rx_len)) - return 0; - - for (i = 0; i < ARRAY_SIZE(rx_buf.events); i++) { - struct st_tp_event_t *e = &rx_buf.events[i]; - - if (e->magic != ST_TP_EVENT_MAGIC) - break; - - switch (e->evt_id) { - case ST_TP_EVENT_ID_ERROR_REPORT: - st_tp_handle_error_report(e); - break; - case ST_TP_EVENT_ID_STATUS_REPORT: - st_tp_handle_status_report(e); - break; - } - } - - if (show_error && (tp_control & TP_CONTROL_SHALL_DUMP_ERROR)) { - enable_deep_sleep(0); - dump_error(); - dump_memory(); - enable_deep_sleep(1); - /* rx_buf.events[] is invalid now */ - i = 0; - } - tp_control &= ~TP_CONTROL_SHALL_DUMP_ERROR; - - return i; -} - -/* - * Reset touchpad. This function will wait for "controller ready" event after - * the touchpad is reset. - */ -static int st_tp_reset(void) -{ - int i, num_events, retry = 100; - - board_touchpad_reset(); - - while (retry--) { - num_events = st_tp_read_all_events(0); - - /* - * We are not doing full panel initialization, and error code - * suggest us to reset or halt. - */ - if (!(tp_control & (TP_CONTROL_INIT | TP_CONTROL_INIT_FULL)) && - (tp_control & (TP_CONTROL_SHALL_HALT | - TP_CONTROL_SHALL_RESET))) - break; - - for (i = 0; i < num_events; i++) { - struct st_tp_event_t *e = &rx_buf.events[i]; - - if (e->evt_id == ST_TP_EVENT_ID_CONTROLLER_READY) { - CPRINTS("Touchpad ready"); - tp_reset_retry_count = 0; - return 0; - } - } - - msleep(10); - } - CPRINTS("Timeout waiting for controller ready."); - return EC_ERROR_TIMEOUT; -} - -/* Initialize the controller ICs after reset */ -static void st_tp_init(void) -{ - tp_control = 0; - system_state = 0; - - if (st_tp_reset()) - return; - - if (tp_control) { - CPRINTS("tp_control = %x", tp_control); - return; - } - /* - * On boot, ST firmware will load system info to host data memory, - * So we don't need to reload it. - */ - st_tp_read_system_info(0); - - system_state = SYSTEM_STATE_READY; - touch_slot = 0; - - touchpad_power_control(); -} -DECLARE_DEFERRED(st_tp_init); - -#ifdef CONFIG_USB_UPDATE -int touchpad_get_info(struct touchpad_info *tp) -{ - if (st_tp_read_system_info(1)) { - tp->status = EC_RES_SUCCESS; - tp->vendor = ST_VENDOR_ID; - /* - * failed to get system info, FW corrupted, return some default - * values. - */ - tp->st.id = 0x3936; - tp->st.fw_version = 0; - tp->st.fw_checksum = 0; - return sizeof(*tp); - } - - tp->status = EC_RES_SUCCESS; - tp->vendor = ST_VENDOR_ID; - tp->st.id = (system_info.chip0_id[0] << 8) | system_info.chip0_id[1]; - tp->st.fw_version = system_info.release_info; - tp->st.fw_checksum = system_info.fw_crc; - - return sizeof(*tp); -} - -/* - * Helper functions for firmware update - * - * There is no documentation about ST_TP_CMD_WRITE_HW_REG (0xFA). - * All implementations below are based on sample code from ST. - */ -static int write_hwreg_cmd32(uint32_t address, uint32_t data) -{ - uint8_t tx_buf[] = { - ST_TP_CMD_WRITE_HW_REG, - (address >> 24) & 0xFF, - (address >> 16) & 0xFF, - (address >> 8) & 0xFF, - (address >> 0) & 0xFF, - (data >> 24) & 0xFF, - (data >> 16) & 0xFF, - (data >> 8) & 0xFF, - (data >> 0) & 0xFF, - }; - - return spi_transaction(SPI, tx_buf, sizeof(tx_buf), NULL, 0); -} - -static int write_hwreg_cmd8(uint32_t address, uint8_t data) -{ - uint8_t tx_buf[] = { - ST_TP_CMD_WRITE_HW_REG, - (address >> 24) & 0xFF, - (address >> 16) & 0xFF, - (address >> 8) & 0xFF, - (address >> 0) & 0xFF, - data, - }; - - return spi_transaction(SPI, tx_buf, sizeof(tx_buf), NULL, 0); -} - -static int wait_for_flash_ready(uint8_t type) -{ - uint8_t tx_buf[] = { - ST_TP_CMD_READ_HW_REG, - 0x20, 0x00, 0x00, type, - }; - int ret = EC_SUCCESS, retry = 200; - - while (retry--) { - ret = spi_transaction(SPI, tx_buf, sizeof(tx_buf), - (uint8_t *)&rx_buf, 1 + ST_TP_EXTRA_BYTE); - if (ret == EC_SUCCESS && !(rx_buf.bytes[0] & 0x80)) - break; - msleep(50); - } - return retry >= 0 ? ret : EC_ERROR_TIMEOUT; -} - -static int erase_flash(int full_init_required) -{ - int ret; - - if (full_init_required) - ret = write_hwreg_cmd32(0x20000128, 0xFFFFFFFF); - else - /* Erase everything, except CX */ - ret = write_hwreg_cmd32(0x20000128, 0xFFFFFF83); - if (ret) - return ret; - ret = write_hwreg_cmd8(0x2000006B, 0x00); - if (ret) - return ret; - ret = write_hwreg_cmd8(0x2000006A, 0xA0); - if (ret) - return ret; - return wait_for_flash_ready(0x6A); -} - -static int st_tp_prepare_for_update(int full_init_required) -{ - /* hold m3 */ - write_hwreg_cmd8(0x20000024, 0x01); - /* unlock flash */ - write_hwreg_cmd8(0x20000025, 0x20); - /* unlock flash erase */ - write_hwreg_cmd8(0x200000DE, 0x03); - erase_flash(full_init_required); - - return EC_SUCCESS; -} - -static int st_tp_start_flash_dma(void) -{ - int ret; - - ret = write_hwreg_cmd8(0x20000071, 0xC0); - if (ret) - return ret; - ret = wait_for_flash_ready(0x71); - return ret; -} - -static int st_tp_write_one_chunk(const uint8_t *head, - uint32_t addr, uint32_t chunk_size) -{ - uint8_t tx_buf[ST_TP_DMA_CHUNK_SIZE + 5]; - uint32_t index = 0; - int ret; - - index = 0; - - tx_buf[index++] = ST_TP_CMD_WRITE_HW_REG; - tx_buf[index++] = (addr >> 24) & 0xFF; - tx_buf[index++] = (addr >> 16) & 0xFF; - tx_buf[index++] = (addr >> 8) & 0xFF; - tx_buf[index++] = (addr >> 0) & 0xFF; - memcpy(tx_buf + index, head, chunk_size); - ret = spi_transaction(SPI, tx_buf, chunk_size + 5, NULL, 0); - - return ret; -} - -/* - * @param offset: offset in memory to copy the data (in bytes). - * @param size: length of data (in bytes). - * @param data: pointer to data bytes. - */ -static int st_tp_write_flash(int offset, int size, const uint8_t *data) -{ - uint8_t tx_buf[12] = {0}; - const uint8_t *head = data, *tail = data + size; - uint32_t addr, index, chunk_size; - uint32_t flash_buffer_size; - int ret; - - offset >>= 2; /* offset should be count in words */ - /* - * To write to flash, the data has to be separated into several chunks. - * Each chunk will be no more than `ST_TP_DMA_CHUNK_SIZE` bytes. - * The chunks will first be saved into a buffer, the buffer can only - * holds `ST_TP_FLASH_BUFFER_SIZE` bytes. We have to flush the buffer - * when the capacity is reached. - */ - while (head < tail) { - addr = 0x00100000; - flash_buffer_size = 0; - while (flash_buffer_size < ST_TP_FLASH_BUFFER_SIZE) { - chunk_size = MIN(ST_TP_DMA_CHUNK_SIZE, tail - head); - ret = st_tp_write_one_chunk(head, addr, chunk_size); - if (ret) - return ret; - - flash_buffer_size += chunk_size; - addr += chunk_size; - head += chunk_size; - - if (head >= tail) - break; - } - - /* configuring the DMA */ - flash_buffer_size = flash_buffer_size / 4 - 1; - index = 0; - - tx_buf[index++] = ST_TP_CMD_WRITE_HW_REG; - tx_buf[index++] = 0x20; - tx_buf[index++] = 0x00; - tx_buf[index++] = 0x00; - tx_buf[index++] = 0x72; /* flash DMA config */ - tx_buf[index++] = 0x00; - tx_buf[index++] = 0x00; - - tx_buf[index++] = offset & 0xFF; - tx_buf[index++] = (offset >> 8) & 0xFF; - tx_buf[index++] = flash_buffer_size & 0xFF; - tx_buf[index++] = (flash_buffer_size >> 8) & 0xFF; - tx_buf[index++] = 0x00; - - ret = spi_transaction(SPI, tx_buf, index, NULL, 0); - if (ret) - return ret; - ret = st_tp_start_flash_dma(); - if (ret) - return ret; - - offset += ST_TP_FLASH_BUFFER_SIZE / 4; - } - return EC_SUCCESS; -} - -static int st_tp_check_command_echo(const uint8_t *cmd, const size_t len) -{ - int num_events, i; - num_events = st_tp_read_all_events(0); - - for (i = 0; i < num_events; i++) { - struct st_tp_event_t *e = &rx_buf.events[i]; - - if (e->evt_id == ST_TP_EVENT_ID_STATUS_REPORT && - e->report.report_type == ST_TP_STATUS_CMD_ECHO && - memcmp(e->report.info, cmd, MIN(4, len)) == 0) - return EC_SUCCESS; - } - return EC_ERROR_BUSY; -} - -static uint8_t get_cx_version(uint8_t tp_version) -{ - /* - * CX version is tracked by ST release note: go/whiskers-st-release-note - */ - - if (tp_version >= 32) - return 3; - - if (tp_version >= 20) - return 2; - - if (tp_version >= 18) - return 1; - return 0; -} - -/* - * Perform panel initialization. - * - * This function will wait until the initialization is done, or 10 second - * timeout is reached. - * - * @param full: 1 => force "full" panel initialization. Otherwise, tp_control - * will be checked to decide if full panel initialization is - * required. - * - * @return EC_SUCCESS or error code. - */ -static int st_tp_panel_init(int full) -{ - uint8_t tx_buf[] = { - ST_TP_CMD_WRITE_SYSTEM_COMMAND, 0x00, 0x02 - }; - int ret, retry; - - if (tp_control & (TP_CONTROL_INIT | TP_CONTROL_INIT_FULL)) - return EC_ERROR_BUSY; - - st_tp_stop_scan(); - ret = st_tp_reset(); - /* - * TODO(b:118312397): Figure out how to handle st_tp_reset errors (if - * needed at all). - */ - CPRINTS("st_tp_reset ret=%d", ret); - - full |= tp_control & TP_CONTROL_SHALL_INIT_FULL; - if (full) { - /* should perform full panel initialization */ - tx_buf[2] = 0x3; - tp_control = TP_CONTROL_INIT_FULL; - } else { - tp_control = TP_CONTROL_INIT; - } - - CPRINTS("Start panel initialization (full=%d)", full); - spi_transaction(SPI, tx_buf, sizeof(tx_buf), NULL, 0); - - retry = 100; - while (retry--) { - watchdog_reload(); - msleep(100); - - ret = st_tp_check_command_echo(tx_buf, sizeof(tx_buf)); - if (ret == EC_SUCCESS) { - CPRINTS("Panel initialization completed."); - tp_control &= ~(TP_CONTROL_INIT | TP_CONTROL_INIT_FULL); - st_tp_init(); - return EC_SUCCESS; - } else if (ret == EC_ERROR_BUSY) { - CPRINTS("Panel initialization on going..."); - } else if (tp_control & ~(TP_CONTROL_INIT | - TP_CONTROL_INIT_FULL)) { - /* there are other kind of errors. */ - CPRINTS("Panel initialization failed, tp_control: %x", - tp_control); - return EC_ERROR_UNKNOWN; - } - } - return EC_ERROR_TIMEOUT; -} - -/* - * @param offset: should be address between 0 to 1M, aligned with - * ST_TP_DMA_CHUNK_SIZE. - * @param size: length of `data` array. - * @param data: content of new touchpad firmware. - */ -int touchpad_update_write(int offset, int size, const uint8_t *data) -{ - static int full_init_required; - int ret, flash_offset; - - CPRINTS("%s %08x %d", __func__, offset, size); - if (offset == 0) { - const struct st_tp_fw_header_t *header; - uint8_t old_cx_version; - uint8_t new_cx_version; - int retry; - - header = (const struct st_tp_fw_header_t *)data; - if (header->signature != 0xAA55AA55) - return EC_ERROR_INVAL; - - for (retry = 50; retry > 0; retry--) { - watchdog_reload(); - if (system_state & SYSTEM_STATE_READY) - break; - if (retry % 10 == 0) - CPRINTS("TP not ready for update, " - "will check again"); - msleep(100); - } - - old_cx_version = get_cx_version(system_info.release_info); - new_cx_version = get_cx_version(header->release_info); - - full_init_required = old_cx_version != new_cx_version; - - /* stop scanning, interrupt, etc... */ - st_tp_stop_scan(); - - ret = st_tp_prepare_for_update(full_init_required); - if (ret) - return ret; - return EC_SUCCESS; - } - - flash_offset = offset - CONFIG_UPDATE_PDU_SIZE; - if (flash_offset % ST_TP_DMA_CHUNK_SIZE) - return EC_ERROR_INVAL; - - if (flash_offset >= ST_TP_FLASH_OFFSET_PANEL_CFG && - flash_offset < ST_TP_FLASH_OFFSET_CONFIG) - /* don't update CX section && panel config section */ - return EC_SUCCESS; - - ret = st_tp_write_flash(flash_offset, size, data); - if (ret) - return ret; - - if (offset + size == CONFIG_TOUCHPAD_VIRTUAL_SIZE) { - CPRINTS("%s: End update, wait for reset.", __func__); - - ret = st_tp_panel_init(full_init_required); - task_set_event(TASK_ID_TOUCHPAD, TASK_EVENT_TP_UPDATED); - return ret; - } - - return EC_SUCCESS; -} - -int touchpad_debug(const uint8_t *param, unsigned int param_size, - uint8_t **data, unsigned int *data_size) -{ - static uint8_t buf[8]; - int num_events; - - if (param_size != 1) - return EC_RES_INVALID_PARAM; - - switch (*param) { - case ST_TP_DEBUG_CMD_RESET_TOUCHPAD: - *data = NULL; - *data_size = 0; - st_tp_stop_scan(); - hook_call_deferred(&st_tp_init_data, 100 * MSEC); - return EC_SUCCESS; - case ST_TP_DEBUG_CMD_CALIBRATE: - /* no return value */ - *data = NULL; - *data_size = 0; - st_tp_panel_init(1); - return EC_SUCCESS; - case ST_TP_DEBUG_CMD_START_SCAN: - *data = NULL; - *data_size = 0; - st_tp_start_scan(); - return EC_SUCCESS; - case ST_TP_DEBUG_CMD_STOP_SCAN: - *data = NULL; - *data_size = 0; - st_tp_stop_scan(); - return EC_SUCCESS; - case ST_TP_DEBUG_CMD_READ_BUF_HEADER: - *data = buf; - *data_size = 8; - st_tp_read_host_buffer_header(); - memcpy(buf, rx_buf.bytes, *data_size); - CPRINTS("header: %ph", HEX_BUF(buf, *data_size)); - return EC_SUCCESS; - case ST_TP_DEBUG_CMD_READ_EVENTS: - num_events = st_tp_read_all_events(0); - if (num_events) { - int i; - - for (i = 0; i < num_events; i++) { - CPRINTS("event[%d]: id=%d, type=%d", - i, rx_buf.events[i].evt_id, - rx_buf.events[i].report.report_type); - } - } - *data = buf; - *data_size = 1; - *data[0] = num_events; - st_tp_send_ack(); - return EC_SUCCESS; - } - return EC_RES_INVALID_PARAM; -} -#endif - -void touchpad_interrupt(enum gpio_signal signal) -{ - irq_ts = __hw_clock_source_read(); - - task_wake(TASK_ID_TOUCHPAD); -} - -static int touchpad_should_enable(void) -{ - /* touchpad is not ready. */ - if (tp_control) - return 0; - -#ifdef CONFIG_USB_SUSPEND - if (usb_is_suspended() && !usb_is_remote_wakeup_enabled()) - return 0; -#endif - -#ifdef CONFIG_TABLET_MODE - if (tablet_get_mode()) - return 0; -#endif - return 1; -} - -/* Make a decision on touchpad power, based on USB and tablet mode status. */ -static void touchpad_power_control(void) -{ - const int enabled = !!(system_state & SYSTEM_STATE_ACTIVE_MODE); - int enable = touchpad_should_enable(); - - if (enabled == enable) - return; - - if (enable) - st_tp_start_scan(); - else - st_tp_stop_scan(); -} - -static void touchpad_read_idle_count(void) -{ - static uint32_t prev_count; - uint32_t count; - int ret; - int rx_len = 2 + ST_TP_EXTRA_BYTE; - uint8_t cmd_read_counter[] = { - 0xFB, 0x00, 0x10, 0xff, 0xff - }; - - /* Find address of idle count. */ - ret = st_tp_load_host_data(ST_TP_MEM_ID_SYSTEM_INFO); - if (ret) - return; - st_tp_read_host_data_memory(0x0082, &rx_buf, rx_len); - - /* Fill in address of idle count, the byte order is reversed. */ - cmd_read_counter[3] = rx_buf.bytes[1]; - cmd_read_counter[4] = rx_buf.bytes[0]; - - /* Read idle count */ - spi_transaction(SPI, cmd_read_counter, sizeof(cmd_read_counter), - (uint8_t *)&rx_buf, 4 + ST_TP_EXTRA_BYTE); - - count = rx_buf.dump_info[0]; - - CPRINTS("idle_count = %08x", count); - if (count == prev_count) - CPRINTS("counter doesn't change..."); - else - prev_count = count; -} - -/* - * Try to collect symptoms of type B error. - * - * There are three possible symptoms: - * 1. error dump section is corrupted / contains error. - * 2. memory stack is corrupted (not 0xCC). - * 3. idle count is not changing. - */ -static void touchpad_collect_error(void) -{ - const uint8_t tx_dump_error[] = { - 0xFB, 0x20, 0x01, 0xEF, 0x80 - }; - uint32_t dump_info[2]; - const uint8_t tx_dump_memory[] = { - 0xFB, 0x00, 0x10, 0x00, 0x00 - }; - uint32_t dump_memory[16]; - int i; - - enable_deep_sleep(0); - spi_transaction(SPI, tx_dump_error, sizeof(tx_dump_error), - (uint8_t *)&rx_buf, - sizeof(dump_info) + ST_TP_EXTRA_BYTE); - memcpy(dump_info, rx_buf.bytes, sizeof(dump_info)); - - spi_transaction(SPI, tx_dump_memory, sizeof(tx_dump_memory), - (uint8_t *)&rx_buf, - sizeof(dump_memory) + ST_TP_EXTRA_BYTE); - memcpy(dump_memory, rx_buf.bytes, sizeof(dump_memory)); - - CPRINTS("check error dump: %08x %08x", dump_info[0], dump_info[1]); - CPRINTS("check memory dump:"); - for (i = 0; i < ARRAY_SIZE(dump_memory); i += 8) { - CPRINTF("%08x %08x %08x %08x %08x %08x %08x %08x\n", - dump_memory[i + 0], - dump_memory[i + 1], - dump_memory[i + 2], - dump_memory[i + 3], - dump_memory[i + 4], - dump_memory[i + 5], - dump_memory[i + 6], - dump_memory[i + 7]); - } - - for (i = 0; i < 3; i++) - touchpad_read_idle_count(); - enable_deep_sleep(1); - - tp_control |= TP_CONTROL_SHALL_RESET; -} - -void touchpad_task(void *u) -{ - uint32_t event; - - while (1) { - uint32_t retry; - - for (retry = 0; retry < 3; retry++) { - CPRINTS("st_tp_init: trial %d", retry + 1); - st_tp_init(); - - if (system_state & SYSTEM_STATE_READY) - break; - /* - * React on touchpad errors. - */ - if (tp_control & TP_CONTROL_SHALL_INIT_FULL) { - /* suppress other handlers */ - tp_control = TP_CONTROL_SHALL_INIT_FULL; - st_tp_panel_init(1); - } else if (tp_control & TP_CONTROL_SHALL_INIT) { - /* suppress other handlers */ - tp_control = TP_CONTROL_SHALL_INIT; - st_tp_panel_init(0); - } else if (tp_control & TP_CONTROL_SHALL_RESET) { - /* suppress other handlers */ - tp_control = TP_CONTROL_SHALL_RESET; - } else if (tp_control & TP_CONTROL_SHALL_HALT) { - CPRINTS("shall halt"); - tp_control = 0; - break; - } - } - - if (system_state & SYSTEM_STATE_READY) - break; - - /* failed to init, mark it as ready to allow upgrade */ - system_state = SYSTEM_STATE_READY; - /* wait for upgrade complete */ - task_wait_event_mask(TASK_EVENT_TP_UPDATED, -1); - } - touchpad_power_control(); - - while (1) { - /* wait for at most 3 seconds */ - event = task_wait_event(3 * 1000 * 1000); - - if ((event & TASK_EVENT_TIMER) && - (system_state & SYSTEM_STATE_ACTIVE_MODE)) - /* - * Haven't received anything for 3 seconds, and we are - * supposed to be in active mode. This is not normal, - * check for errors and reset. - */ - touchpad_collect_error(); - - if (event & TASK_EVENT_WAKE) - while (!tp_control && - !gpio_get_level(GPIO_TOUCHPAD_INT)) - st_tp_read_report(); - - /* - * React on touchpad errors. - */ - if (tp_control & TP_CONTROL_SHALL_INIT_FULL) { - /* suppress other handlers */ - tp_control = TP_CONTROL_SHALL_INIT_FULL; - st_tp_panel_init(1); - } else if (tp_control & TP_CONTROL_SHALL_INIT) { - /* suppress other handlers */ - tp_control = TP_CONTROL_SHALL_INIT; - st_tp_panel_init(0); - } else if (tp_control & TP_CONTROL_SHALL_RESET) { - /* suppress other handlers */ - tp_control = TP_CONTROL_SHALL_RESET; - st_tp_init(); - } else if (tp_control & TP_CONTROL_SHALL_HALT) { - tp_control = 0; - st_tp_stop_scan(); - } - - if (event & TASK_EVENT_POWER) - touchpad_power_control(); - } -} - -/* - * When USB PM status changes, or tablet mode changes, call in the main task to - * decide whether to turn touchpad on or off. - */ -#if defined(CONFIG_USB_SUSPEND) || defined(CONFIG_TABLET_MODE) -static void touchpad_power_change(void) -{ - task_set_event(TASK_ID_TOUCHPAD, TASK_EVENT_POWER); -} -#endif -#ifdef CONFIG_USB_SUSPEND -DECLARE_HOOK(HOOK_USB_PM_CHANGE, touchpad_power_change, HOOK_PRIO_DEFAULT); -#endif -#ifdef CONFIG_TABLET_MODE -DECLARE_HOOK(HOOK_TABLET_MODE_CHANGE, touchpad_power_change, HOOK_PRIO_DEFAULT); -#endif - -#ifdef CONFIG_USB_ISOCHRONOUS -static void st_tp_enable_heat_map(void) -{ - int new_state = (SYSTEM_STATE_ENABLE_HEAT_MAP | - SYSTEM_STATE_ENABLE_DOME_SWITCH | - SYSTEM_STATE_ACTIVE_MODE); - int mask = new_state; - - st_tp_update_system_state(new_state, mask); -} -DECLARE_DEFERRED(st_tp_enable_heat_map); - -static void st_tp_disable_heat_map(void) -{ - int new_state = 0; - int mask = SYSTEM_STATE_ENABLE_HEAT_MAP; - - st_tp_update_system_state(new_state, mask); -} -DECLARE_DEFERRED(st_tp_disable_heat_map); - -static void print_frame(void) -{ - char debug_line[ST_TOUCH_COLS + 5]; - int i, j, index; - int v; - struct st_tp_usb_packet_t *packet = &usb_packet[usb_buffer_index & 1]; - - if (usb_buffer_index == spi_buffer_index) - /* buffer is empty. */ - return; - - /* We will have ~150 FPS, let's print ~4 frames per second */ - if (usb_buffer_index % 37 == 0) { - /* move cursor back to top left corner */ - CPRINTF("\x1b[H"); - CPUTS("==============\n"); - for (i = 0; i < ST_TOUCH_ROWS; i++) { - for (j = 0; j < ST_TOUCH_COLS; j++) { - index = i * ST_TOUCH_COLS; - index += (ST_TOUCH_COLS - j - 1); // flip X - v = packet->frame[index]; - - if (v > 0) - debug_line[j] = '0' + v * 10 / 256; - else - debug_line[j] = ' '; - } - debug_line[j++] = '\n'; - debug_line[j++] = '\0'; - CPRINTF(debug_line); - } - CPUTS("==============\n"); - } -} - -static int st_tp_read_frame(void) -{ - int ret = EC_SUCCESS; - int rx_len = ST_TOUCH_FRAME_SIZE + ST_TP_EXTRA_BYTE; - int heat_map_addr = get_heat_map_addr(); - uint8_t tx_buf[] = { - ST_TP_CMD_READ_SPI_HOST_BUFFER, - (heat_map_addr >> 8) & 0xFF, - (heat_map_addr >> 0) & 0xFF, - }; - - /* - * Since usb_packet.frame is already ane uint8_t byte array, we can just - * make it the RX buffer for SPI transaction. - * - * When there is a extra byte, since we know that flags is a one byte - * value, and we will override it later, it's okay for SPI transaction - * to write the extra byte to flags address. - */ -#if ST_TP_EXTRA_BYTE == 1 - BUILD_ASSERT(sizeof(usb_packet[0].flags) == 1); - uint8_t *rx_buf = &usb_packet[spi_buffer_index & 1].flags; -#else - uint8_t *rx_buf = usb_packet[spi_buffer_index & 1].frame; -#endif - - st_tp_read_all_events(1); - if (tp_control) { - ret = EC_ERROR_UNKNOWN; - goto failed; - } - - if (heat_map_addr < 0) - goto failed; - - ret = st_tp_check_domeswitch_state(); - if (ret) - goto failed; - - /* - * Theoretically, we should read host buffer header to check if data is - * valid, but the data should always be ready when interrupt pin is low. - * Let's skip this check for now. - */ - ret = spi_transaction(SPI, tx_buf, sizeof(tx_buf), - (uint8_t *)rx_buf, rx_len); - if (ret == EC_SUCCESS) { - int i; - uint8_t *dest = usb_packet[spi_buffer_index & 1].frame; - uint8_t max_value = 0; - - for (i = 0; i < ST_TOUCH_COLS * ST_TOUCH_ROWS; i++) - max_value |= dest[i]; - if (max_value == 0) // empty frame - return -1; - - usb_packet[spi_buffer_index & 1].flags = 0; - if (system_state & SYSTEM_STATE_DOME_SWITCH_LEVEL) - usb_packet[spi_buffer_index & 1].flags |= - USB_FRAME_FLAGS_BUTTON; - } -failed: - return ret; -} - -/* Define USB interface for heat_map */ - -/* function prototypes */ -static int st_tp_usb_set_interface(usb_uint alternate_setting, - usb_uint interface); -static int heatmap_send_packet(struct usb_isochronous_config const *config); -static void st_tp_usb_tx_callback(struct usb_isochronous_config const *config); - -/* USB descriptors */ -USB_ISOCHRONOUS_CONFIG_FULL(usb_st_tp_heatmap_config, - USB_IFACE_ST_TOUCHPAD, - USB_CLASS_VENDOR_SPEC, - USB_SUBCLASS_GOOGLE_HEATMAP, - USB_PROTOCOL_GOOGLE_HEATMAP, - USB_STR_HEATMAP_NAME, /* interface name */ - USB_EP_ST_TOUCHPAD, - USB_ISO_PACKET_SIZE, - st_tp_usb_tx_callback, - st_tp_usb_set_interface, - 1 /* 1 extra EP for interrupts */) - -/* ***This function will be executed in interrupt context*** */ -void st_tp_usb_tx_callback(struct usb_isochronous_config const *config) -{ - task_wake(TASK_ID_HEATMAP); -} - -void heatmap_task(void *unused) -{ - struct usb_isochronous_config const *config; - - config = &usb_st_tp_heatmap_config; - - while (1) { - /* waiting st_tp_usb_tx_callback() */ - task_wait_event(-1); - - if (system_state & SYSTEM_STATE_DEBUG_MODE) - continue; - - if (usb_buffer_index == spi_buffer_index) - /* buffer is empty */ - continue; - - while (heatmap_send_packet(config)) - /* We failed to write a packet, try again later. */ - task_wait_event(100); - } -} - -/* USB interface has completed TX, it's asking for more data */ -static int heatmap_send_packet(struct usb_isochronous_config const *config) -{ - size_t num_byte_available; - size_t offset = 0; - int ret, buffer_id = -1; - struct st_tp_usb_packet_t *packet = &usb_packet[usb_buffer_index & 1]; - - packet_header.flags = 0; - num_byte_available = sizeof(*packet) - transmit_report_offset; - if (num_byte_available > 0) { - if (transmit_report_offset == 0) - packet_header.flags |= HEADER_FLAGS_NEW_FRAME; - ret = usb_isochronous_write_buffer( - config, - (uint8_t *)&packet_header, - sizeof(packet_header), - offset, - &buffer_id, - 0); - /* - * Since USB_ISO_PACKET_SIZE > sizeof(packet_header), this must - * be true. - */ - if (ret != sizeof(packet_header)) - return -1; - - offset += ret; - packet_header.index++; - - ret = usb_isochronous_write_buffer( - config, - (uint8_t *)packet + transmit_report_offset, - num_byte_available, - offset, - &buffer_id, - 1); - if (ret < 0) { - /* - * TODO(b/70482333): handle this error, it might be: - * 1. timeout (buffer_id changed) - * 2. invalid offset - * - * For now, let's just return an error and try again. - */ - CPRINTS("%s %d: %d", __func__, __LINE__, -ret); - return ret; - } - - /* We should have sent some bytes, update offset */ - transmit_report_offset += ret; - if (transmit_report_offset == sizeof(*packet)) { - transmit_report_offset = 0; - usb_buffer_index++; - } - } - return 0; -} - -static int st_tp_usb_set_interface(usb_uint alternate_setting, - usb_uint interface) -{ - if (alternate_setting == 1) { - if ((system_info.release_info & 0xFF) < - ST_TP_MIN_HEATMAP_VERSION) { - CPRINTS("release version %04llx doesn't support heatmap", - system_info.release_info); - /* Heatmap mode is not supported in this version. */ - return -1; - } - - hook_call_deferred(&st_tp_enable_heat_map_data, 0); - return 0; - } else if (alternate_setting == 0) { - hook_call_deferred(&st_tp_disable_heat_map_data, 0); - return 0; - } else /* we only have two settings. */ - return -1; -} - -static int get_heat_map_addr(void) -{ - /* - * TODO(stimim): drop this when we are sure all trackpads are having the - * same config (e.g. after EVT). - */ - if (system_info.release_info >= 0x3) - return 0x0120; - else if (system_info.release_info == 0x1) - return 0x20; - else - return -1; /* Unknown version */ -} - -struct st_tp_interrupt_t { -#define ST_TP_INT_FRAME_AVAILABLE BIT(0) - uint8_t flags; -} __packed; - -static usb_uint st_tp_usb_int_buffer[ - DIV_ROUND_UP(sizeof(struct st_tp_interrupt_t), 2)] __usb_ram; - -const struct usb_endpoint_descriptor USB_EP_DESC(USB_IFACE_ST_TOUCHPAD, 81) = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 0x80 | USB_EP_ST_TOUCHPAD_INT, - .bmAttributes = 0x03 /* Interrupt endpoint */, - .wMaxPacketSize = sizeof(struct st_tp_interrupt_t), - .bInterval = 1 /* ms */, -}; - -static void st_tp_interrupt_send(void) -{ - struct st_tp_interrupt_t report; - - memset(&report, 0, sizeof(report)); - - if (usb_buffer_index < spi_buffer_index) - report.flags |= ST_TP_INT_FRAME_AVAILABLE; - memcpy_to_usbram((void *)usb_sram_addr(st_tp_usb_int_buffer), - &report, sizeof(report)); - /* enable TX */ - STM32_TOGGLE_EP(USB_EP_ST_TOUCHPAD_INT, EP_TX_MASK, EP_TX_VALID, 0); - usb_wake(); -} - -static void st_tp_interrupt_tx(void) -{ - STM32_USB_EP(USB_EP_ST_TOUCHPAD_INT) &= EP_MASK; - - if (usb_buffer_index < spi_buffer_index) - /* pending frames */ - hook_call_deferred(&st_tp_interrupt_send_data, 0); -} - -static void st_tp_interrupt_event(enum usb_ep_event evt) -{ - int ep = USB_EP_ST_TOUCHPAD_INT; - - if (evt == USB_EVENT_RESET) { - btable_ep[ep].tx_addr = usb_sram_addr(st_tp_usb_int_buffer); - btable_ep[ep].tx_count = sizeof(struct st_tp_interrupt_t); - - STM32_USB_EP(ep) = ((ep << 0) | - EP_TX_VALID | - (3 << 9) /* interrupt EP */ | - EP_RX_DISAB); - } -} - -USB_DECLARE_EP(USB_EP_ST_TOUCHPAD_INT, st_tp_interrupt_tx, st_tp_interrupt_tx, - st_tp_interrupt_event); - -#endif - -/* Debugging commands */ -static int command_touchpad_st(int argc, char **argv) -{ - if (argc < 2) - return EC_ERROR_PARAM_COUNT; - if (strcasecmp(argv[1], "version") == 0) { - st_tp_read_system_info(1); - return EC_SUCCESS; - } else if (strcasecmp(argv[1], "calibrate") == 0) { - st_tp_panel_init(1); - return EC_SUCCESS; - } else if (strcasecmp(argv[1], "enable") == 0) { -#ifdef CONFIG_USB_ISOCHRONOUS - set_bits(&system_state, SYSTEM_STATE_DEBUG_MODE, - SYSTEM_STATE_DEBUG_MODE); - hook_call_deferred(&st_tp_enable_heat_map_data, 0); - return 0; -#else - return EC_ERROR_NOT_HANDLED; -#endif - } else if (strcasecmp(argv[1], "disable") == 0) { -#ifdef CONFIG_USB_ISOCHRONOUS - set_bits(&system_state, 0, SYSTEM_STATE_DEBUG_MODE); - hook_call_deferred(&st_tp_disable_heat_map_data, 0); - return 0; -#else - return EC_ERROR_NOT_HANDLED; -#endif - } else if (strcasecmp(argv[1], "dump") == 0) { - enable_deep_sleep(0); - dump_error(); - dump_memory(); - enable_deep_sleep(1); - return EC_SUCCESS; - } else if (strcasecmp(argv[1], "memory_dump") == 0) { - if (argc == 3 && !parse_bool(argv[2], &dump_memory_on_error)) - return EC_ERROR_PARAM2; - - ccprintf("memory_dump: %d\n", dump_memory_on_error); - return EC_SUCCESS; - } else { - return EC_ERROR_PARAM1; - } -} -DECLARE_CONSOLE_COMMAND(touchpad_st, command_touchpad_st, - "<enable | disable | version | calibrate | dump | " - "memory_dump <enable|disable>>", - "Read write spi. id is spi_devices array index"); diff --git a/driver/touchpad_st.h b/driver/touchpad_st.h deleted file mode 100644 index a6534f278f..0000000000 --- a/driver/touchpad_st.h +++ /dev/null @@ -1,274 +0,0 @@ -/* Copyright 2018 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. - */ - -#ifndef __CROS_EC_TOUCHPAD_ST_H -#define __CROS_EC_TOUCHPAD_ST_H - -#include <stdint.h> - -#include "common.h" - -#define ST_VENDOR_ID 0x0483 - -#define ST_TP_EXTRA_BYTE 1 - -#define ST_TP_CMD_READ_ALL_EVENTS 0x87 -#define ST_TP_CMD_WRITE_SCAN_MODE_SELECT 0xA0 -#define ST_TP_CMD_WRITE_FEATURE_SELECT 0xA2 -#define ST_TP_CMD_WRITE_SYSTEM_COMMAND 0xA4 -#define ST_TP_CMD_WRITE_HOST_DATA_MEMORY 0xA6 -#define ST_TP_CMD_READ_HOST_DATA_MEMORY 0xA7 -#define ST_TP_CMD_WRITE_FW_CONFIG 0xA8 -#define ST_TP_CMD_READ_FW_CONFIG 0xA9 -#define ST_TP_CMD_SPI_HOST_BUFFER_ACK 0xC0 -#define ST_TP_CMD_READ_SPI_HOST_BUFFER 0xC1 - -#define ST_TP_CMD_WRITE_HW_REG 0xFA -#define ST_TP_CMD_READ_HW_REG 0xFB - -/* Max number of bytes that the DMA can burn on the flash in one shot in FTI */ -#define ST_TP_FLASH_BUFFER_SIZE (64 * 1024) -/* Max number of bytes that can be written in I2C to the DMA */ -#define ST_TP_DMA_CHUNK_SIZE 32 - -#define ST_HOST_BUFFER_DATA_VALID BIT(0) -#define ST_HOST_BUFFER_MT_READY BIT(3) -#define ST_HOST_BUFFER_SF_READY BIT(4) -#define ST_HOST_BUFFER_SS_READY BIT(5) - -#define ST_TP_SCAN_MODE_ACTIVE 0x00 -#define ST_TP_SCAN_MODE_LOW_POWER 0x01 -#define ST_TP_SCAN_MODE_TUNING_WIZARD 0x02 -#define ST_TP_SCAN_MODE_LOCKED 0x03 - -#define ST_TOUCH_ROWS (18) /* force len */ -#define ST_TOUCH_COLS (25) /* sense len */ - -#define ST_TOUCH_HEADER_SIZE 32 - -#define BYTES_PER_PIXEL 1 -/* Number of bits per pixel, this value is decided by experiments. */ -#define BITS_PER_PIXEL 8 - -#define ST_TOUCH_FRAME_SIZE (ST_TOUCH_ROWS * ST_TOUCH_COLS * \ - BYTES_PER_PIXEL) -#define ST_TOUCH_FORCE_SIZE (ST_TOUCH_ROWS * BYTES_PER_PIXEL) -#define ST_TOUCH_SENSE_SIZE (ST_TOUCH_COLS * BYTES_PER_PIXEL) - -#define ST_TP_MEM_ID_SYSTEM_INFO 0x01 - -#define ST_TP_FLASH_OFFSET_CODE (0x0000 << 2) -#define ST_TP_FLASH_OFFSET_PANEL_CFG (0x6800 << 2) -#define ST_TP_FLASH_OFFSET_CX (0x7000 << 2) -#define ST_TP_FLASH_OFFSET_CONFIG (0x7C00 << 2) - - -struct st_tp_host_data_header_t { -#define ST_TP_HEADER_MAGIC 0xA5 - uint8_t magic; /* this should always be ST_TP_HEADER_MAGIC */ - uint8_t host_data_mem_id; - uint16_t count; -} __packed; - -/* Compute offset of end of a member in given type */ -#define endof(type, member) (offsetof(type, member) + \ - sizeof(((type *)NULL)->member)) - -struct st_tp_system_info_t { - /* Part 1, basic info */ - struct st_tp_host_data_header_t header; - uint16_t api_ver_rev; - uint8_t api_ver_minor; - uint8_t api_ver_major; - uint16_t chip0_ver; - uint8_t chip0_id[2]; /* should be 0x3936 */ - uint16_t chip1_ver; - uint16_t chip1_id; - uint16_t fw_ver; - uint16_t svn_rev; - uint16_t cfg_ver; - uint16_t cfg_project_id; - uint16_t cx_ver; - uint16_t cx_project_id; - uint8_t cfg_afe_ver; - uint8_t cx_afe_ver; - uint8_t panel_cfg_afe_ver; - uint8_t protocol; - uint8_t die_id[16]; - uint64_t release_info; /* unsigned little endian 64 bit integer */ - uint32_t fw_crc; - uint32_t cfg_crc; -#define ST_TP_SYSTEM_INFO_PART_1_SIZE endof(struct st_tp_system_info_t, cfg_crc) -#define ST_TP_SYSTEM_INFO_PART_1_RESERVED 16 - - uint16_t scr_res_x; - uint16_t scr_res_y; - uint8_t scr_tx_len; - uint8_t scr_rx_len; - uint8_t key_len; - uint8_t frc_len; -#define ST_TP_SYSTEM_INFO_PART_2_SIZE (endof(struct st_tp_system_info_t, \ - frc_len) - \ - offsetof(struct st_tp_system_info_t, \ - scr_res_x)) -#define ST_TP_SYSTEM_INFO_PART_2_RESERVED 40 - -#if 0 /* the following parts are defined in spec, but not currently used. */ - - uint16_t dbg_frame_addr; -#define ST_TP_SYSTEM_INFO_PART_3_SIZE (endof(struct st_tp_system_info_t, \ - dbg_frame_addr) - \ - offsetof(struct st_tp_system_info_t, \ - dbg_frame_addr)) -#define ST_TP_SYSTEM_INFO_PART_3_RESERVED 6 - - uint16_t ms_scr_raw_addr; - uint16_t ms_scr_filter_addr; - uint16_t ms_scr_str_addr; - uint16_t ms_scr_bl_addr; - uint16_t ss_tch_tx_raw_addr; - uint16_t ss_tch_tx_filter_addr; - uint16_t ss_tch_tx_str_addr; - uint16_t ss_tch_tx_bl_addr; - uint16_t ss_tch_rx_raw_addr; - uint16_t ss_tch_rx_filter_addr; - uint16_t ss_tch_rx_str_addr; - uint16_t ss_tch_rx_bl_addr; - uint16_t key_raw_addr; - uint16_t key_filter_addr; - uint16_t key_str_addr; - uint16_t key_bl_addr; - uint16_t frc_raw_addr; - uint16_t frc_filter_addr; - uint16_t frc_str_addr; - uint16_t frc_bl_addr; - uint16_t ss_hvr_tx_raw_addr; - uint16_t ss_hvr_tx_filter_addr; - uint16_t ss_hvr_tx_str_addr; - uint16_t ss_hvr_tx_bl_addr; - uint16_t ss_hvr_rx_raw_addr; - uint16_t ss_hvr_rx_filter_addr; - uint16_t ss_hvr_rx_str_addr; - uint16_t ss_hvr_rx_bl_addr; - uint16_t ss_prx_tx_raw_addr; - uint16_t ss_prx_tx_filter_addr; - uint16_t ss_prx_tx_str_addr; - uint16_t ss_prx_tx_bl_addr; - uint16_t ss_prx_rx_raw_addr; - uint16_t ss_prx_rx_filter_addr; - uint16_t ss_prx_rx_str_addr; - uint16_t ss_prx_rx_bl_addr; -#define ST_TP_SYSTEM_INFO_PART_4_SIZE (endof(struct st_tp_system_info_t, \ - ss_prx_rx_bl_addr) - \ - offsetof(struct st_tp_system_info_t, \ - ms_scr_raw_addr)) -#endif /* if 0 */ -} __packed; - -#define ST_TP_SYSTEM_INFO_LEN (sizeof(struct st_tp_system_info_t) + \ - ST_TP_SYSTEM_INFO_PART_1_RESERVED) - -struct st_tp_host_buffer_header_t { -#define ST_TP_BUFFER_HEADER_DATA_VALID BIT(0) -#define ST_TP_BUFFER_HEADER_EVT_FIFO_NOT_EMPTY BIT(1) -#define ST_TP_BUFFER_HEADER_SYS_FAULT BIT(2) -#define ST_TP_BUFFER_HEADER_HEAT_MAP_MT_RDY BIT(3) -#define ST_TP_BUFFER_HEADER_HEAT_MAP_SF_RDY BIT(4) -#define ST_TP_BUFFER_HEADER_HEAT_MAP_SS_RDY BIT(5) -#define ST_TP_BUFFER_HEADER_DOMESWITCH_LVL BIT(6) - uint8_t flags; - uint8_t reserved[3]; - uint8_t heatmap_miss_count; - uint8_t event_count; - uint8_t event_miss_count; -} __packed; - -struct st_tp_host_buffer_heat_map_t { - uint8_t frame[ST_TOUCH_FRAME_SIZE]; -#if 0 /* we are not using these now */ - uint8_t force[ST_TOUCH_FORCE_SIZE]; - uint8_t sense[ST_TOUCH_SENSE_SIZE]; -#endif -} __packed; - -struct st_tp_event_t { -#define ST_TP_EVENT_MAGIC 0x3 - unsigned magic:2; /* should always be 0x3 */ - unsigned major_high:2; -#define ST_TP_EVENT_ID_CONTROLLER_READY 0x0 -#define ST_TP_EVENT_ID_ENTER_POINTER 0x1 -#define ST_TP_EVENT_ID_MOTION_POINTER 0x2 -#define ST_TP_EVENT_ID_LEAVE_POINTER 0x3 -#define ST_TP_EVENT_ID_STATUS_REPORT 0x4 -#define ST_TP_EVENT_ID_USER_REPORT 0x5 -#define ST_TP_EVENT_ID_DEBUG_REPORT 0xe -#define ST_TP_EVENT_ID_ERROR_REPORT 0xf - unsigned evt_id:4; - - union { - struct { -#define ST_TP_TOUCH_TYPE_INVALID 0x0 -#define ST_TP_TOUCH_TYPE_FINGER 0x1 -#define ST_TP_TOUCH_TYPE_GLOVE 0x2 -#define ST_TP_TOUCH_TYPE_STYLUS 0x3 -#define ST_TP_TOUCH_TYPE_PALM 0x4 - unsigned touch_type:4; - unsigned touch_id:4; - unsigned y:12; - unsigned x:12; - uint8_t z; - uint8_t minor:4; // need to be concat with minor_high - uint8_t major:4; // need to be concat with major_high - } __packed finger; - - struct { -#define ST_TP_STATUS_CMD_ECHO 0x1 -#define ST_TP_STATUS_FRAME_DROP 0x3 -#define ST_TP_STATUS_FCAL 0x5 -#define ST_TP_STATUS_BEACON 0x9 - uint8_t report_type; - uint8_t info[4]; - uint8_t reserved; - } __packed report; - } __packed ; /* anonymous */ - - unsigned minor_high:2; - unsigned reserved:1; - unsigned evt_left:5; -} __packed; - -struct st_tp_fw_header_t { - uint32_t signature; - uint32_t ftb_ver; - uint32_t chip_id; - uint32_t svn_ver; - uint32_t fw_ver; - uint32_t config_id; - uint32_t config_ver; - uint8_t reserved[8]; - uint64_t release_info; - uint32_t sec_size[4]; - uint32_t crc; -} __packed; - -enum ST_TP_MODE { - X_Y_MODE = 0, - HEAT_MAP_MODE, -}; - -#define ST_TP_DEBUG_CMD_RESET_TOUCHPAD 0x00 -#define ST_TP_DEBUG_CMD_CALIBRATE 0x01 -#define ST_TP_DEBUG_CMD_START_SCAN 0x02 -#define ST_TP_DEBUG_CMD_STOP_SCAN 0x03 -#define ST_TP_DEBUG_CMD_READ_BUF_HEADER 0x04 -#define ST_TP_DEBUG_CMD_READ_EVENTS 0x05 - -#define ST_TP_HEAT_MAP_THRESHOLD 10 - -/* A minimum version that supports heatmap mode. */ -#define ST_TP_MIN_HEATMAP_VERSION 0x12 - -#endif /* __CROS_EC_TOUCHPAD_ST_H */ - diff --git a/driver/usb_mux/amd_fp5.c b/driver/usb_mux/amd_fp5.c deleted file mode 100644 index b77edf2826..0000000000 --- a/driver/usb_mux/amd_fp5.c +++ /dev/null @@ -1,162 +0,0 @@ -/* Copyright 2019 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. - * - * AMD FP5 USB/DP Mux. - */ - -#include "amd_fp5.h" -#include "chipset.h" -#include "common.h" -#include "hooks.h" -#include "i2c.h" -#include "queue.h" -#include "timer.h" -#include "usb_mux.h" - -static mux_state_t saved_mux_state[CONFIG_USB_PD_PORT_MAX_COUNT]; - -static inline int amd_fp5_mux_read(const struct usb_mux *me, uint8_t *val) -{ - uint8_t buf[3] = { 0 }; - int rv; - - rv = i2c_xfer(me->i2c_port, me->i2c_addr_flags, - NULL, 0, buf, 3); - if (rv) - return rv; - - *val = buf[me->usb_port + 1]; - - return EC_SUCCESS; -} - -static inline int amd_fp5_mux_write(const struct usb_mux *me, uint8_t val) -{ - return i2c_write8(me->i2c_port, me->i2c_addr_flags, - me->usb_port, val); -} - -static int amd_fp5_init(const struct usb_mux *me) -{ - return EC_SUCCESS; -} - -static int amd_fp5_set_mux(const struct usb_mux *me, mux_state_t mux_state, - bool *ack_required) -{ - uint8_t val = 0; - - /* This driver does not use host command ACKs */ - *ack_required = false; - - saved_mux_state[me->usb_port] = mux_state; - - /* - * This MUX is on the FP5 SoC. If that device is not powered then - * we either have to complain that it is not powered or if we were - * setting the state to OFF, then go ahead and report that we did - * it because a powered down MUX is off. - */ - if (chipset_in_state(CHIPSET_STATE_HARD_OFF)) - return (mux_state == USB_PD_MUX_NONE) - ? EC_SUCCESS - : EC_ERROR_NOT_POWERED; - - if ((mux_state & USB_PD_MUX_USB_ENABLED) && - (mux_state & USB_PD_MUX_DP_ENABLED)) - val = (mux_state & USB_PD_MUX_POLARITY_INVERTED) - ? AMD_FP5_MUX_DOCK_INVERTED : AMD_FP5_MUX_DOCK; - else if (mux_state & USB_PD_MUX_USB_ENABLED) - val = (mux_state & USB_PD_MUX_POLARITY_INVERTED) - ? AMD_FP5_MUX_USB_INVERTED : AMD_FP5_MUX_USB; - else if (mux_state & USB_PD_MUX_DP_ENABLED) - val = (mux_state & USB_PD_MUX_POLARITY_INVERTED) - ? AMD_FP5_MUX_DP_INVERTED : AMD_FP5_MUX_DP; - - return amd_fp5_mux_write(me, val); -} - -static int amd_fp5_get_mux(const struct usb_mux *me, mux_state_t *mux_state) -{ - uint8_t val = AMD_FP5_MUX_SAFE; - - /* - * This MUX is on the FP5 SoC. Only access the device if we - * have power. If that device is not powered then claim the - * state to be NONE, which is SAFE. - */ - if (!chipset_in_state(CHIPSET_STATE_HARD_OFF)) { - int rv; - - rv = amd_fp5_mux_read(me, &val); - if (rv) - return rv; - } - - switch (val) { - case AMD_FP5_MUX_USB: - *mux_state = USB_PD_MUX_USB_ENABLED; - break; - case AMD_FP5_MUX_USB_INVERTED: - *mux_state = USB_PD_MUX_USB_ENABLED | - USB_PD_MUX_POLARITY_INVERTED; - break; - case AMD_FP5_MUX_DOCK: - *mux_state = USB_PD_MUX_USB_ENABLED | USB_PD_MUX_DP_ENABLED; - break; - case AMD_FP5_MUX_DOCK_INVERTED: - *mux_state = USB_PD_MUX_USB_ENABLED | USB_PD_MUX_DP_ENABLED - | USB_PD_MUX_POLARITY_INVERTED; - break; - case AMD_FP5_MUX_DP: - *mux_state = USB_PD_MUX_DP_ENABLED; - break; - case AMD_FP5_MUX_DP_INVERTED: - *mux_state = USB_PD_MUX_DP_ENABLED | - USB_PD_MUX_POLARITY_INVERTED; - break; - case AMD_FP5_MUX_SAFE: - default: - *mux_state = USB_PD_MUX_NONE; - break; - } - - return EC_SUCCESS; -} - -static struct queue const chipset_reset_queue - = QUEUE_NULL(CONFIG_USB_PD_PORT_MAX_COUNT, struct usb_mux *); - -static void amd_fp5_chipset_reset_delay(void) -{ - struct usb_mux *me; - int rv; - bool unused; - - while (queue_remove_unit(&chipset_reset_queue, &me)) { - rv = amd_fp5_set_mux(me, saved_mux_state[me->usb_port], - &unused); - if (rv) - ccprints("C%d restore mux rv:%d", me->usb_port, rv); - } -} -DECLARE_DEFERRED(amd_fp5_chipset_reset_delay); - -/* - * The AP's internal USB-C mux is reset when AP resets, so wait for - * it to be ready and then restore the previous setting. - */ -static int amd_fp5_chipset_reset(const struct usb_mux *me) -{ - queue_add_unit(&chipset_reset_queue, &me); - hook_call_deferred(&amd_fp5_chipset_reset_delay_data, 200 * MSEC); - return EC_SUCCESS; -} - -const struct usb_mux_driver amd_fp5_usb_mux_driver = { - .init = &amd_fp5_init, - .set = &amd_fp5_set_mux, - .get = &amd_fp5_get_mux, - .chipset_reset = &amd_fp5_chipset_reset, -}; diff --git a/driver/usb_mux/amd_fp5.h b/driver/usb_mux/amd_fp5.h deleted file mode 100644 index 7534ea0d8a..0000000000 --- a/driver/usb_mux/amd_fp5.h +++ /dev/null @@ -1,21 +0,0 @@ -/* Copyright 2019 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. - * - * AMD FP5 USB/DP Mux. - */ - -#ifndef __CROS_EC_USB_MUX_AMD_FP5_H -#define __CROS_EC_USB_MUX_AMD_FP5_H - -#define AMD_FP5_MUX_I2C_ADDR_FLAGS 0x5C - -#define AMD_FP5_MUX_SAFE 0x00 -#define AMD_FP5_MUX_USB 0x02 -#define AMD_FP5_MUX_USB_INVERTED 0x11 -#define AMD_FP5_MUX_DOCK 0x06 -#define AMD_FP5_MUX_DOCK_INVERTED 0x19 -#define AMD_FP5_MUX_DP 0x0C -#define AMD_FP5_MUX_DP_INVERTED 0x1C - -#endif /* __CROS_EC_USB_MUX_AMD_FP5_H */ diff --git a/driver/usb_mux/amd_fp6.c b/driver/usb_mux/amd_fp6.c deleted file mode 100644 index b2d5ae1fb4..0000000000 --- a/driver/usb_mux/amd_fp6.c +++ /dev/null @@ -1,233 +0,0 @@ -/* Copyright 2021 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. - * - * AMD FP6 USB/DP Mux. - */ - -#include "amd_fp6.h" -#include "chipset.h" -#include "common.h" -#include "hooks.h" -#include "i2c.h" -#include "queue.h" -#include "timer.h" -#include "usb_mux.h" - -#define CPRINTSUSB(format, args...) cprints(CC_USBCHARGE, format, ## args) -#define CPRINTFUSB(format, args...) cprintf(CC_USBCHARGE, format, ## args) - -/* - * The recommendation from "3.3.2 Command Timeout" is 250ms, - * however empirical testing found that a 100ms timeout is sufficient. - */ -#define WRITE_CMD_TIMEOUT_MS 100 - -/* Command retry interval */ -#define CMD_RETRY_INTERVAL_MS 1000 - -/* - * Local data structure for saving mux state so it can be restored after - * an AP reset. - */ -static struct { - const struct usb_mux *mux; - uint8_t val; - bool write_pending; -} saved_mux_state[USBC_PORT_COUNT]; - -static int amd_fp6_mux_port0_read(const struct usb_mux *me, uint8_t *val) -{ - uint8_t payload[3] = { 0 }; - bool mux_ready; - - RETURN_ERROR(i2c_xfer(me->i2c_port, me->i2c_addr_flags, NULL, 0, - payload, 3)); - - /* - * payload[0]: Status/ID - * payload[1]: Port 0 Control/Status - * payload[2]: Port 1 Control/Status (unused on FP6) - */ - mux_ready = !!((payload[0] >> AMD_FP6_MUX_PD_STATUS_OFFSET) - & AMD_FP6_MUX_PD_STATUS_READY); - - if (!mux_ready) - return EC_ERROR_BUSY; - *val = payload[1]; - - return EC_SUCCESS; -} - -static int amd_fp6_mux_port0_write(const struct usb_mux *me, uint8_t write_val) -{ - uint8_t read_val; - uint8_t port_status; - timestamp_t start; - - /* Check if mux is ready */ - RETURN_ERROR(amd_fp6_mux_port0_read(me, &read_val)); - - /* Write control register */ - RETURN_ERROR( - i2c_write8(me->i2c_port, me->i2c_addr_flags, 0, write_val)); - - /* - * Read status until write command finishes or times out. - * The mux has an internal opaque timeout, which we wrap with our own - * timeout to be safe. - */ - start = get_time(); - while (time_since32(start) < WRITE_CMD_TIMEOUT_MS * MSEC) { - - RETURN_ERROR(amd_fp6_mux_port0_read(me, &read_val)); - port_status = read_val >> AMD_FP6_MUX_PORT_STATUS_OFFSET; - - if (port_status == AMD_FP6_MUX_PORT_CMD_COMPLETE) - return EC_SUCCESS; - else if (port_status == AMD_FP6_MUX_PORT_CMD_TIMEOUT) - return EC_ERROR_TIMEOUT; - else if (port_status == AMD_FP6_MUX_PORT_CMD_BUSY) - msleep(5); - else - return EC_ERROR_UNKNOWN; - } - - return EC_ERROR_TIMEOUT; -} - -/* - * Keep trying to write the saved mux state until successful or SOC leaves - * S0 power state. - */ -static void amd_fp6_set_mux_retry(void); -DECLARE_DEFERRED(amd_fp6_set_mux_retry); -static void amd_fp6_set_mux_retry(void) -{ - int rv; - bool try_again = false; - - /* - * Mux can only be written in S0, stop trying. - * Will try again on chipset_resume. - */ - if (!chipset_in_state(CHIPSET_STATE_ON)) - return; - - for (int i = 0; i < ARRAY_SIZE(saved_mux_state); i++) { - /* Make sure mux_state is initialized */ - if (saved_mux_state[i].mux == NULL || - !saved_mux_state[i].write_pending) - continue; - - rv = amd_fp6_mux_port0_write(saved_mux_state[i].mux, - saved_mux_state[i].val); - - if (rv) - try_again = true; - else - saved_mux_state[i].write_pending = false; - } - if (try_again) - hook_call_deferred(&amd_fp6_set_mux_retry_data, - CMD_RETRY_INTERVAL_MS * MSEC); -} - - -static int amd_fp6_set_mux(const struct usb_mux *me, mux_state_t mux_state, - bool *ack_required) -{ - uint8_t val; - - /* This driver does not use host command ACKs */ - *ack_required = false; - - if (mux_state == USB_PD_MUX_NONE) - /* - * LOW_POWER must be set when connection mode is - * set to 00b (safe state) - */ - val = AMD_FP6_MUX_MODE_SAFE | AMD_FP6_MUX_LOW_POWER; - else if ((mux_state & USB_PD_MUX_USB_ENABLED) && - (mux_state & USB_PD_MUX_DP_ENABLED)) - val = AMD_FP6_MUX_MODE_DOCK; - else if (mux_state & USB_PD_MUX_USB_ENABLED) - val = AMD_FP6_MUX_MODE_USB; - else if (mux_state & USB_PD_MUX_DP_ENABLED) - val = AMD_FP6_MUX_MODE_DP; - else { - CPRINTSUSB("C%d: unhandled mux_state %x\n", me->usb_port, - mux_state); - return EC_ERROR_INVAL; - } - - if (mux_state & USB_PD_MUX_POLARITY_INVERTED) - val |= AMD_FP6_MUX_ORIENTATION; - - saved_mux_state[me->usb_port].mux = me; - saved_mux_state[me->usb_port].val = val; - - /* Mux is not powered in Z1 */ - if (chipset_in_state(CHIPSET_STATE_HARD_OFF)) - return (mux_state == USB_PD_MUX_NONE) ? EC_SUCCESS - : EC_ERROR_NOT_POWERED; - - saved_mux_state[me->usb_port].write_pending = true; - amd_fp6_set_mux_retry(); - - return EC_SUCCESS; -} - -static int amd_fp6_get_mux(const struct usb_mux *me, mux_state_t *mux_state) -{ - uint8_t val; - bool inverted; - uint8_t mode; - - /* Mux is not powered in Z1 */ - if (chipset_in_state(CHIPSET_STATE_HARD_OFF)) - return USB_PD_MUX_NONE; - - RETURN_ERROR(amd_fp6_mux_port0_read(me, &val)); - - mode = (val & AMD_FP6_MUX_MODE_MASK); - inverted = !!(val & AMD_FP6_MUX_ORIENTATION); - - if (mode == AMD_FP6_MUX_MODE_USB) - *mux_state = USB_PD_MUX_USB_ENABLED; - else if (mode == AMD_FP6_MUX_MODE_DP) - *mux_state = USB_PD_MUX_DP_ENABLED; - else if (mode == AMD_FP6_MUX_MODE_DOCK) - *mux_state = USB_PD_MUX_USB_ENABLED | USB_PD_MUX_DP_ENABLED; - else /* AMD_FP6_MUX_MODE_SAFE */ - *mux_state = USB_PD_MUX_NONE; - - if (inverted) - *mux_state |= USB_PD_MUX_POLARITY_INVERTED; - - return EC_SUCCESS; -} - -/* - * The FP6 USB Mux will not be ready for writing until *sometime* after S0. - */ -static void amd_fp6_chipset_resume(void) -{ - for (int i = 0; i < ARRAY_SIZE(saved_mux_state); i++) - saved_mux_state[i].write_pending = true; - hook_call_deferred(&amd_fp6_set_mux_retry_data, - CMD_RETRY_INTERVAL_MS * MSEC); -} -DECLARE_HOOK(HOOK_CHIPSET_RESUME, amd_fp6_chipset_resume, HOOK_PRIO_DEFAULT); - -static int amd_fp6_chipset_reset(const struct usb_mux *me) -{ - amd_fp6_chipset_resume(); - return EC_SUCCESS; -} - -const struct usb_mux_driver amd_fp6_usb_mux_driver = { - .set = &amd_fp6_set_mux, - .get = &amd_fp6_get_mux, - .chipset_reset = &amd_fp6_chipset_reset -}; diff --git a/driver/usb_mux/amd_fp6.h b/driver/usb_mux/amd_fp6.h deleted file mode 100644 index 913903e4c4..0000000000 --- a/driver/usb_mux/amd_fp6.h +++ /dev/null @@ -1,31 +0,0 @@ -/* Copyright 2021 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. - * - * AMD FP6 USB/DP Mux. - */ - -#ifndef __CROS_EC_USB_MUX_AMD_FP6_H -#define __CROS_EC_USB_MUX_AMD_FP6_H - -#define AMD_FP6_C0_MUX_I2C_ADDR 0x5C -#define AMD_FP6_C4_MUX_I2C_ADDR 0x52 - -#define AMD_FP6_MUX_MODE_SAFE 0x0 -#define AMD_FP6_MUX_MODE_USB 0x1 -#define AMD_FP6_MUX_MODE_DP 0x2 -#define AMD_FP6_MUX_MODE_DOCK 0x3 -#define AMD_FP6_MUX_MODE_MASK GENMASK(1, 0) - -#define AMD_FP6_MUX_ORIENTATION BIT(4) -#define AMD_FP6_MUX_LOW_POWER BIT(5) - -#define AMD_FP6_MUX_PORT_STATUS_OFFSET 6 -#define AMD_FP6_MUX_PORT_CMD_BUSY 0x0 -#define AMD_FP6_MUX_PORT_CMD_COMPLETE 0x1 -#define AMD_FP6_MUX_PORT_CMD_TIMEOUT 0x2 - -#define AMD_FP6_MUX_PD_STATUS_READY BIT(5) -#define AMD_FP6_MUX_PD_STATUS_OFFSET 1 - -#endif /* __CROS_EC_USB_MUX_AMD_FP6_H */ diff --git a/driver/usb_mux/anx3443.c b/driver/usb_mux/anx3443.c deleted file mode 100644 index 2e57f4d30c..0000000000 --- a/driver/usb_mux/anx3443.c +++ /dev/null @@ -1,162 +0,0 @@ -/* Copyright 2021 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. - * - * ANX3443: 10G Active Mux (6x4) with - * Integrated Re-timers for USB3.2/DisplayPort - */ - -#include "anx3443.h" -#include "chipset.h" -#include "common.h" -#include "console.h" -#include "i2c.h" -#include "time.h" -#include "usb_mux.h" -#include "util.h" - -/* - * Empirical testing found it takes ~12ms to wake mux. - * Setting timeout to 20ms for some buffer. - */ -#define ANX3443_I2C_WAKE_TIMEOUT_MS 20 -#define ANX3443_I2C_WAKE_RETRY_DELAY_US 500 - -#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args) - -static inline int anx3443_read(const struct usb_mux *me, - uint8_t reg, int *val) -{ - return i2c_read8(me->i2c_port, me->i2c_addr_flags, reg, val); -} - -static inline int anx3443_write(const struct usb_mux *me, - uint8_t reg, uint8_t val) -{ - return i2c_write8(me->i2c_port, me->i2c_addr_flags, reg, val); -} - -static int anx3443_power_off(const struct usb_mux *me) -{ - /* - * The mux will not send an acknowledgment when powered off, so ignore - * response and always return success. - */ - anx3443_write(me, ANX3443_REG_POWER_CNTRL, ANX3443_POWER_CNTRL_OFF); - return EC_SUCCESS; -} - -static int anx3443_wake_up(const struct usb_mux *me) -{ - timestamp_t start; - int rv; - int val; - - if (chipset_in_state(CHIPSET_STATE_HARD_OFF)) - return EC_ERROR_NOT_POWERED; - - /* Keep reading top register until mux wakes up or timesout */ - start = get_time(); - do { - rv = anx3443_read(me, 0x0, &val); - if (!rv) - break; - usleep(ANX3443_I2C_WAKE_RETRY_DELAY_US); - } while (time_since32(start) < ANX3443_I2C_WAKE_TIMEOUT_MS * MSEC); - if (rv) { - CPRINTS("ANX3443: Failed to wake mux rv:%d", rv); - return EC_ERROR_TIMEOUT; - } - - /* ULTRA_LOW_POWER must always be disabled (Fig 2-2) */ - RETURN_ERROR(anx3443_write(me, ANX3443_REG_ULTRA_LOW_POWER, - ANX3443_ULTRA_LOW_POWER_DIS)); - - return EC_SUCCESS; -} - -static int anx3443_set_mux(const struct usb_mux *me, mux_state_t mux_state, - bool *ack_required) -{ - int reg; - - /* This driver does not use host command ACKs */ - *ack_required = false; - - /* Mux is not powered in Z1 */ - if (chipset_in_state(CHIPSET_STATE_HARD_OFF)) - return (mux_state == USB_PD_MUX_NONE) ? EC_SUCCESS - : EC_ERROR_NOT_POWERED; - - /* To disable both DP and USB the mux must be powered off. */ - if (!(mux_state & (USB_PD_MUX_USB_ENABLED | USB_PD_MUX_DP_ENABLED))) - return anx3443_power_off(me); - - RETURN_ERROR(anx3443_wake_up(me)); - - /* ULP_CFG_MODE_EN overrides pin control. Always set it */ - reg = ANX3443_ULP_CFG_MODE_EN; - if (mux_state & USB_PD_MUX_USB_ENABLED) - reg |= ANX3443_ULP_CFG_MODE_USB_EN; - if (mux_state & USB_PD_MUX_DP_ENABLED) - reg |= ANX3443_ULP_CFG_MODE_DP_EN; - if (mux_state & USB_PD_MUX_POLARITY_INVERTED) - reg |= ANX3443_ULP_CFG_MODE_FLIP; - - return anx3443_write(me, ANX3443_REG_ULP_CFG_MODE, reg); -} - -static int anx3443_get_mux(const struct usb_mux *me, mux_state_t *mux_state) -{ - int reg; - - /* Mux is not powered in Z1 */ - if (chipset_in_state(CHIPSET_STATE_HARD_OFF)) - return USB_PD_MUX_NONE; - - RETURN_ERROR(anx3443_wake_up(me)); - - *mux_state = 0; - RETURN_ERROR(anx3443_read(me, ANX3443_REG_ULP_CFG_MODE, ®)); - - if (reg & ANX3443_ULP_CFG_MODE_USB_EN) - *mux_state |= USB_PD_MUX_USB_ENABLED; - if (reg & ANX3443_ULP_CFG_MODE_DP_EN) - *mux_state |= USB_PD_MUX_DP_ENABLED; - if (reg & ANX3443_ULP_CFG_MODE_FLIP) - *mux_state |= USB_PD_MUX_POLARITY_INVERTED; - - return EC_SUCCESS; -} - -static int anx3443_init(const struct usb_mux *me) -{ - uint64_t now; - bool unused; - - /* - * ANX3443 requires 30ms to power on. EC and ANX3443 are on the same - * power rail, so just wait 30ms since EC boot. - */ - now = get_time().val; - if (now < ANX3443_I2C_READY_DELAY) - usleep(ANX3443_I2C_READY_DELAY - now); - - RETURN_ERROR(anx3443_wake_up(me)); - - /* - * Note that bypassing the usb_mux API is okay for internal driver calls - * since the task calling init already holds this port's mux lock. - */ - /* Default to USB mode */ - RETURN_ERROR(anx3443_set_mux(me, USB_PD_MUX_USB_ENABLED, &unused)); - - return EC_SUCCESS; -} - -const struct usb_mux_driver anx3443_usb_mux_driver = { - .init = anx3443_init, - .set = anx3443_set_mux, - .get = anx3443_get_mux, -}; diff --git a/driver/usb_mux/anx3443.h b/driver/usb_mux/anx3443.h deleted file mode 100644 index b505f993ea..0000000000 --- a/driver/usb_mux/anx3443.h +++ /dev/null @@ -1,40 +0,0 @@ -/* Copyright 2021 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. - * - * ANX3443: 10G Active Mux (6x4) with - * Integrated Re-timers for USB3.2/DisplayPort - */ - -#ifndef __CROS_EC_USB_MUX_ANX3443_H -#define __CROS_EC_USB_MUX_ANX3443_H - -#define ANX3443_I2C_READY_DELAY (30 * MSEC) - -/* I2C interface addresses */ -#define ANX3443_I2C_ADDR0_FLAGS 0x10 -#define ANX3443_I2C_ADDR1_FLAGS 0x14 -#define ANX3443_I2C_ADDR2_FLAGS 0x16 -#define ANX3443_I2C_ADDR3_FLAGS 0x11 - -/* This register is not documented in datasheet. */ -#define ANX3443_REG_POWER_CNTRL 0x2B -#define ANX3443_POWER_CNTRL_OFF 0xFF - - -/* Ultra low power control register */ -#define ANX3443_REG_ULTRA_LOW_POWER 0xE6 -#define ANX3443_ULTRA_LOW_POWER_EN 0x06 -#define ANX3443_ULTRA_LOW_POWER_DIS 0x00 - -/* Mux control register */ -#define ANX3443_REG_ULP_CFG_MODE 0xF8 -#define ANX3443_ULP_CFG_MODE_EN BIT(4) -#define ANX3443_ULP_CFG_MODE_SWAP BIT(3) -#define ANX3443_ULP_CFG_MODE_FLIP BIT(2) -#define ANX3443_ULP_CFG_MODE_DP_EN BIT(1) -#define ANX3443_ULP_CFG_MODE_USB_EN BIT(0) - -extern const struct usb_mux_driver anx3443_usb_mux_driver; - -#endif /* __CROS_EC_USB_MUX_ANX3443_H */ diff --git a/driver/usb_mux/anx7440.c b/driver/usb_mux/anx7440.c deleted file mode 100644 index 89e593217d..0000000000 --- a/driver/usb_mux/anx7440.c +++ /dev/null @@ -1,112 +0,0 @@ -/* Copyright 2019 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. - * - * Analogix ANX7440 USB Type-C Active mux with - * Integrated Re-timers for USB3.1/DisplayPort. - */ - -#include "anx7440.h" -#include "common.h" -#include "console.h" -#include "i2c.h" -#include "usb_mux.h" -#include "util.h" - -#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args) - -static inline int anx7440_read(const struct usb_mux *me, - uint8_t reg, int *val) -{ - return i2c_read8(me->i2c_port, me->i2c_addr_flags, reg, val); -} - -static inline int anx7440_write(const struct usb_mux *me, - uint8_t reg, uint8_t val) -{ - return i2c_write8(me->i2c_port, me->i2c_addr_flags, reg, val); -} - -struct anx7440_id_t { - uint8_t val; - uint8_t reg; -}; - -static const struct anx7440_id_t anx7440_device_ids[] = { - { ANX7440_VENDOR_ID_L, ANX7440_REG_VENDOR_ID_L }, - { ANX7440_VENDOR_ID_H, ANX7440_REG_VENDOR_ID_H }, - { ANX7440_DEVICE_ID_L, ANX7440_REG_DEVICE_ID_L }, - { ANX7440_DEVICE_ID_H, ANX7440_REG_DEVICE_ID_H }, - { ANX7440_DEVICE_VERSION, ANX7440_REG_DEVICE_VERSION }, -}; - -static int anx7440_init(const struct usb_mux *me) -{ - int i; - int val; - int res; - - /* Verify device id / version registers */ - for (i = 0; i < ARRAY_SIZE(anx7440_device_ids); i++) { - res = anx7440_read(me, anx7440_device_ids[i].reg, &val); - if (res) - return res; - - if (val != anx7440_device_ids[i].val) - return EC_ERROR_UNKNOWN; - } - - return EC_SUCCESS; -} - -/* Writes control register to set switch mode */ -static int anx7440_set_mux(const struct usb_mux *me, mux_state_t mux_state, - bool *ack_required) -{ - int reg, res; - - /* This driver does not use host command ACKs */ - *ack_required = false; - - res = anx7440_read(me, ANX7440_REG_CHIP_CTRL, ®); - if (res) - return res; - - reg &= ~ANX7440_CHIP_CTRL_SW_OP_MODE_CLEAR; - if (mux_state & USB_PD_MUX_USB_ENABLED) - reg |= ANX7440_CHIP_CTRL_SW_OP_MODE_USB; - if (mux_state & USB_PD_MUX_DP_ENABLED) - reg |= ANX7440_CHIP_CTRL_SW_OP_MODE_DP; - if (mux_state & USB_PD_MUX_POLARITY_INVERTED) - reg |= ANX7440_CHIP_CTRL_SW_FLIP; - - return anx7440_write(me, ANX7440_REG_CHIP_CTRL, reg); -} - -/* Reads control register and updates mux_state accordingly */ -static int anx7440_get_mux(const struct usb_mux *me, mux_state_t *mux_state) -{ - int reg, res; - - *mux_state = 0; - res = anx7440_read(me, ANX7440_REG_CHIP_CTRL, ®); - if (res) - return res; - - if (reg & ANX7440_CHIP_CTRL_OP_MODE_FINAL_USB) - *mux_state |= USB_PD_MUX_USB_ENABLED; - if (reg & ANX7440_CHIP_CTRL_OP_MODE_FINAL_DP) - *mux_state |= USB_PD_MUX_DP_ENABLED; - if (reg & ANX7440_CHIP_CTRL_FINAL_FLIP) - *mux_state |= USB_PD_MUX_POLARITY_INVERTED; - - return EC_SUCCESS; -} - -const struct usb_mux_driver anx7440_usb_mux_driver = { - .init = anx7440_init, - .set = anx7440_set_mux, - .get = anx7440_get_mux, - /* TODO(b/146683781): add low power mode */ -}; diff --git a/driver/usb_mux/anx7440.h b/driver/usb_mux/anx7440.h deleted file mode 100644 index 2147e3146a..0000000000 --- a/driver/usb_mux/anx7440.h +++ /dev/null @@ -1,40 +0,0 @@ -/* Copyright 2019 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. - * - * Analogix ANX7440 USB Type-C Active mux with - * Integrated Re-timers for USB3.1/DisplayPort. - */ - -#ifndef __CROS_EC_USB_MUX_ANX7440_H -#define __CROS_EC_USB_MUX_ANX7440_H - -/* I2C interface address */ -#define ANX7440_I2C_ADDR1_FLAGS 0x10 -#define ANX7440_I2C_ADDR2_FLAGS 0x12 -#define I2C_ADDR_USB_MUX0_FLAGS ANX7440_I2C_ADDR1_FLAGS -#define I2C_ADDR_USB_MUX1_FLAGS ANX7440_I2C_ADDR2_FLAGS - -/* Vendor / Device Id registers and expected fused values */ -#define ANX7440_REG_VENDOR_ID_L 0x00 -#define ANX7440_VENDOR_ID_L 0xaa -#define ANX7440_REG_VENDOR_ID_H 0x01 -#define ANX7440_VENDOR_ID_H 0xaa -#define ANX7440_REG_DEVICE_ID_L 0x02 -#define ANX7440_DEVICE_ID_L 0x40 -#define ANX7440_REG_DEVICE_ID_H 0x03 -#define ANX7440_DEVICE_ID_H 0x74 -#define ANX7440_REG_DEVICE_VERSION 0x04 -#define ANX7440_DEVICE_VERSION 0xCB - -/* Chip control register for checking mux state */ -#define ANX7440_REG_CHIP_CTRL 0x05 -#define ANX7440_CHIP_CTRL_FINAL_FLIP BIT(6) -#define ANX7440_CHIP_CTRL_OP_MODE_FINAL_DP BIT(5) -#define ANX7440_CHIP_CTRL_OP_MODE_FINAL_USB BIT(4) -#define ANX7440_CHIP_CTRL_SW_FLIP BIT(2) -#define ANX7440_CHIP_CTRL_SW_OP_MODE_DP BIT(1) -#define ANX7440_CHIP_CTRL_SW_OP_MODE_USB BIT(0) -#define ANX7440_CHIP_CTRL_SW_OP_MODE_CLEAR 0x7 - -#endif /* __CROS_EC_USB_MUX_ANX7440_H */ diff --git a/driver/usb_mux/anx7451.c b/driver/usb_mux/anx7451.c deleted file mode 100644 index 42fdb1f078..0000000000 --- a/driver/usb_mux/anx7451.c +++ /dev/null @@ -1,153 +0,0 @@ -/* Copyright 2021 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. - * - * ANX7451: 10G Active Mux (4x4) with - * Integrated Re-timers for USB3.2/DisplayPort - */ - -#include "anx7451.h" -#include "chipset.h" -#include "common.h" -#include "console.h" -#include "i2c.h" -#include "time.h" -#include "usb_mux.h" -#include "util.h" - -/* - * Empirical testing found it takes ~12ms to wake mux. - * Setting timeout to 20ms for some buffer. - */ -#define ANX7451_I2C_WAKE_TIMEOUT_MS 20 -#define ANX7451_I2C_WAKE_RETRY_DELAY_US 500 - -#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args) - -static inline int anx7451_read(const struct usb_mux *me, - uint8_t reg, int *val) -{ - return i2c_read8(me->i2c_port, me->i2c_addr_flags, reg, val); -} - -static inline int anx7451_write(const struct usb_mux *me, - uint8_t reg, uint8_t val) -{ - return i2c_write8(me->i2c_port, me->i2c_addr_flags, reg, val); -} - -static int anx7451_power_off(const struct usb_mux *me) -{ - /* - * The mux will not send an acknowledgment when powered off, so ignore - * response and always return success. - */ - anx7451_write(me, ANX7451_REG_POWER_CNTRL, ANX7451_POWER_CNTRL_OFF); - return EC_SUCCESS; -} - -static int anx7451_wake_up(const struct usb_mux *me) -{ - timestamp_t start; - int rv; - int val; - uint16_t usb_i2c_addr = board_anx7451_get_usb_i2c_addr(me); - - if (chipset_in_state(CHIPSET_STATE_HARD_OFF)) - return EC_ERROR_NOT_POWERED; - - /* Keep reading top register until mux wakes up or timesout */ - start = get_time(); - do { - rv = anx7451_read(me, 0x0, &val); - if (!rv) - break; - usleep(ANX7451_I2C_WAKE_RETRY_DELAY_US); - } while (time_since32(start) < ANX7451_I2C_WAKE_TIMEOUT_MS * MSEC); - if (rv) { - CPRINTS("ANX7451: Failed to wake mux rv:%d", rv); - return EC_ERROR_TIMEOUT; - } - - /* ULTRA_LOW_POWER must always be disabled (Fig 2-2) */ - RETURN_ERROR(anx7451_write(me, ANX7451_REG_ULTRA_LOW_POWER, - ANX7451_ULTRA_LOW_POWER_DIS)); - - /* - * Configure ANX7451 USB I2C address. - * Shift 1 bit to make 7 bit address an 8 bit address. - */ - RETURN_ERROR( - anx7451_write(me, ANX7451_REG_USB_I2C_ADDR, usb_i2c_addr << 1)); - - /* b/185276137: Fix ANX7451 upstream AUX FLIP */ - RETURN_ERROR(i2c_write8(me->i2c_port, usb_i2c_addr, - ANX7451_REG_USB_AUX_FLIP_CTRL, - ANX7451_USB_AUX_FLIP_EN)); - - return EC_SUCCESS; -} - -static int anx7451_set_mux(const struct usb_mux *me, mux_state_t mux_state, - bool *ack_required) -{ - int reg; - - /* This driver does not use host command ACKs */ - *ack_required = false; - - /* - * Mux is not powered in Z1, and will start up in USB mode. Ensure any - * mux sets when off get run again so we don't leave the retimer on with - * the None mode set - */ - if (chipset_in_state(CHIPSET_STATE_HARD_OFF)) - return EC_ERROR_NOT_POWERED; - - /* To disable both DP and USB the mux must be powered off. */ - if (!(mux_state & (USB_PD_MUX_USB_ENABLED | USB_PD_MUX_DP_ENABLED))) - return anx7451_power_off(me); - - RETURN_ERROR(anx7451_wake_up(me)); - - /* ULP_CFG_MODE_EN overrides pin control. Always set it */ - reg = ANX7451_ULP_CFG_MODE_EN; - if (mux_state & USB_PD_MUX_USB_ENABLED) - reg |= ANX7451_ULP_CFG_MODE_USB_EN; - if (mux_state & USB_PD_MUX_DP_ENABLED) - reg |= ANX7451_ULP_CFG_MODE_DP_EN; - if (mux_state & USB_PD_MUX_POLARITY_INVERTED) - reg |= ANX7451_ULP_CFG_MODE_FLIP; - - return anx7451_write(me, ANX7451_REG_ULP_CFG_MODE, reg); -} - -static int anx7451_get_mux(const struct usb_mux *me, mux_state_t *mux_state) -{ - int reg; - - /* Mux is not powered in Z1 */ - if (chipset_in_state(CHIPSET_STATE_HARD_OFF)) - return USB_PD_MUX_NONE; - - RETURN_ERROR(anx7451_wake_up(me)); - - *mux_state = 0; - RETURN_ERROR(anx7451_read(me, ANX7451_REG_ULP_CFG_MODE, ®)); - - if (reg & ANX7451_ULP_CFG_MODE_USB_EN) - *mux_state |= USB_PD_MUX_USB_ENABLED; - if (reg & ANX7451_ULP_CFG_MODE_DP_EN) - *mux_state |= USB_PD_MUX_DP_ENABLED; - if (reg & ANX7451_ULP_CFG_MODE_FLIP) - *mux_state |= USB_PD_MUX_POLARITY_INVERTED; - - return EC_SUCCESS; -} - -const struct usb_mux_driver anx7451_usb_mux_driver = { - .set = anx7451_set_mux, - .get = anx7451_get_mux, - /* Low power mode is not supported on ANX7451 */ -}; diff --git a/driver/usb_mux/anx7451.h b/driver/usb_mux/anx7451.h deleted file mode 100644 index 7eefb6e79e..0000000000 --- a/driver/usb_mux/anx7451.h +++ /dev/null @@ -1,58 +0,0 @@ -/* Copyright 2021 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. - * - * ANX7451: 10G Active Mux (4x4) with - * Integrated Re-timers for USB3.2/DisplayPort - */ - -#ifndef __CROS_EC_USB_MUX_ANX7451_H -#define __CROS_EC_USB_MUX_ANX7451_H - -#include "usb_mux.h" - -/* I2C interface addresses */ -#define ANX7451_I2C_ADDR0_FLAGS 0x10 -#define ANX7451_I2C_ADDR1_FLAGS 0x14 -#define ANX7451_I2C_ADDR2_FLAGS 0x16 -#define ANX7451_I2C_ADDR3_FLAGS 0x11 - -/* This register is not documented in datasheet. */ -#define ANX7451_REG_POWER_CNTRL 0x2B -#define ANX7451_POWER_CNTRL_OFF 0xFF - -/* - * Ultra low power control register. - * On ANX7451, this register should always be 0 (disabled). - * See figure 2-2 in family programming guide. - */ -#define ANX7451_REG_ULTRA_LOW_POWER 0xE6 -/* #define ANX7451_ULTRA_LOW_POWER_EN 0x06 */ -#define ANX7451_ULTRA_LOW_POWER_DIS 0x00 - -/* Mux control register */ -#define ANX7451_REG_ULP_CFG_MODE 0xF8 -#define ANX7451_ULP_CFG_MODE_EN BIT(4) -#define ANX7451_ULP_CFG_MODE_SWAP BIT(3) -#define ANX7451_ULP_CFG_MODE_FLIP BIT(2) -#define ANX7451_ULP_CFG_MODE_DP_EN BIT(1) -#define ANX7451_ULP_CFG_MODE_USB_EN BIT(0) - -/* Register to set USB I2C address, defaults to 0x29 (7-bit) */ -#define ANX7451_REG_USB_I2C_ADDR 0x38 - -/* ANX7451 AUX FLIP control */ -#define ANX7451_REG_USB_AUX_FLIP_CTRL 0xA4 -#define ANX7451_USB_AUX_FLIP_EN 0x20 - -extern const struct usb_mux_driver anx7451_usb_mux_driver; - -/* - * ANX7451 uses a separate i2c address for USB configuration registers. - * This address is not controlled by address straps and defaults to 0x29. - * This address may conflict with other ANX74* parts. Implement - * board_anx7451_get_usb_i2c_addr to set a non-conflicting 7-bit address. - */ -uint16_t board_anx7451_get_usb_i2c_addr(const struct usb_mux *me); - -#endif /* __CROS_EC_USB_MUX_ANX7451_H */ diff --git a/driver/usb_mux/it5205.c b/driver/usb_mux/it5205.c deleted file mode 100644 index 0cfecdeda0..0000000000 --- a/driver/usb_mux/it5205.c +++ /dev/null @@ -1,172 +0,0 @@ -/* Copyright 2017 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. - * - * ITE IT5205 Type-C USB alternate mode mux. - */ - -#include "common.h" -#include "i2c.h" -#include "it5205.h" -#include "util.h" - -#define MUX_STATE_DP_USB_MASK (USB_PD_MUX_USB_ENABLED | USB_PD_MUX_DP_ENABLED) - -static int it5205_read(const struct usb_mux *me, uint8_t reg, int *val) -{ - return i2c_read8(me->i2c_port, me->i2c_addr_flags, reg, val); -} - -static int it5205_write(const struct usb_mux *me, uint8_t reg, uint8_t val) -{ - return i2c_write8(me->i2c_port, me->i2c_addr_flags, reg, val); -} - -static int it5205h_sbu_update(const struct usb_mux *me, uint8_t reg, - uint8_t mask, enum mask_update_action action) -{ - return i2c_update8(me->i2c_port, IT5205H_SBU_I2C_ADDR_FLAGS, - reg, mask, action); -} - -static int it5205h_sbu_field_update(const struct usb_mux *me, uint8_t reg, - uint8_t field_mask, uint8_t set_value) -{ - return i2c_field_update8(me->i2c_port, IT5205H_SBU_I2C_ADDR_FLAGS, - reg, field_mask, set_value); -} - -struct mux_chip_id_t { - uint8_t chip_id; - uint8_t reg; -}; - -static const struct mux_chip_id_t mux_chip_id_verify[] = { - { '5', IT5205_REG_CHIP_ID3}, - { '2', IT5205_REG_CHIP_ID2}, - { '0', IT5205_REG_CHIP_ID1}, - { '5', IT5205_REG_CHIP_ID0}, -}; - -static int it5205_init(const struct usb_mux *me) -{ - int i, val, ret; - - /* bit[0]: mux power on, bit[7-1]: reserved. */ - ret = it5205_write(me, IT5205_REG_MUXPDR, 0); - if (ret) - return ret; - /* Verify chip ID registers. */ - for (i = 0; i < ARRAY_SIZE(mux_chip_id_verify); i++) { - ret = it5205_read(me, mux_chip_id_verify[i].reg, &val); - if (ret) - return ret; - - if (val != mux_chip_id_verify[i].chip_id) - return EC_ERROR_UNKNOWN; - } - - if (IS_ENABLED(CONFIG_USB_MUX_IT5205H_SBU_OVP)) { - RETURN_ERROR(it5205h_sbu_field_update(me, IT5205H_REG_VSR, - IT5205H_VREF_SELECT_MASK, - IT5205H_VREF_SELECT_3_3V)); - - RETURN_ERROR(it5205h_sbu_field_update(me, IT5205H_REG_CSBUOVPSR, - IT5205H_OVP_SELECT_MASK, - IT5205H_OVP_3_68V)); - - RETURN_ERROR(it5205h_sbu_update(me, IT5205H_REG_ISR, - IT5205H_ISR_CSBU_MASK, MASK_CLR)); - - RETURN_ERROR(it5205h_enable_csbu_switch(me, true)); - } - - return EC_SUCCESS; -} - -enum ec_error_list it5205h_enable_csbu_switch(const struct usb_mux *me, bool en) -{ - return it5205h_sbu_update(me, IT5205H_REG_CSBUSR, - IT5205H_CSBUSR_SWITCH, en ? MASK_SET : MASK_CLR); -} - -/* Writes control register to set switch mode */ -static int it5205_set_mux(const struct usb_mux *me, mux_state_t mux_state, - bool *ack_required) -{ - uint8_t reg; - - /* This driver does not use host command ACKs */ - *ack_required = false; - - switch (mux_state & MUX_STATE_DP_USB_MASK) { - case USB_PD_MUX_USB_ENABLED: - reg = IT5205_USB; - break; - case USB_PD_MUX_DP_ENABLED: - reg = IT5205_DP; - break; - case MUX_STATE_DP_USB_MASK: - reg = IT5205_DP_USB; - break; - default: - reg = 0; - break; - } - - if (mux_state & USB_PD_MUX_POLARITY_INVERTED) - reg |= IT5205_POLARITY_INVERTED; - - return it5205_write(me, IT5205_REG_MUXCR, reg); -} - -/* Reads control register and updates mux_state accordingly */ -static int it5205_get_mux(const struct usb_mux *me, mux_state_t *mux_state) -{ - int reg, ret; - - ret = it5205_read(me, IT5205_REG_MUXCR, ®); - if (ret) - return ret; - - switch (reg & IT5205_DP_USB_CTRL_MASK) { - case IT5205_USB: - *mux_state = USB_PD_MUX_USB_ENABLED; - break; - case IT5205_DP: - *mux_state = USB_PD_MUX_DP_ENABLED; - break; - case IT5205_DP_USB: - *mux_state = MUX_STATE_DP_USB_MASK; - break; - default: - *mux_state = 0; - break; - } - - if (reg & IT5205_POLARITY_INVERTED) - *mux_state |= USB_PD_MUX_POLARITY_INVERTED; - - return EC_SUCCESS; -} - -static int it5205_enter_low_power_mode(const struct usb_mux *me) -{ - int rv; - - /* Turn off all switches */ - rv = it5205_write(me, IT5205_REG_MUXCR, 0); - - if (rv) - return rv; - - /* Power down mux */ - return it5205_write(me, IT5205_REG_MUXPDR, IT5205_MUX_POWER_DOWN); -} - -const struct usb_mux_driver it5205_usb_mux_driver = { - .init = &it5205_init, - .set = &it5205_set_mux, - .get = &it5205_get_mux, - .enter_low_power_mode = &it5205_enter_low_power_mode, -}; diff --git a/driver/usb_mux/it5205.h b/driver/usb_mux/it5205.h deleted file mode 100644 index 0fb9f009f6..0000000000 --- a/driver/usb_mux/it5205.h +++ /dev/null @@ -1,66 +0,0 @@ -/* Copyright 2017 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. - * - * ITE IT5205 Type-C USB alternate mode mux. - */ - -#ifndef __CROS_EC_IT5205_H -#define __CROS_EC_IT5205_H - -#include "stdbool.h" -#include "usb_mux.h" -#include "usb_mux/it5205_public.h" - -/* Chip ID registers */ -#define IT5205_REG_CHIP_ID3 0x4 -#define IT5205_REG_CHIP_ID2 0x5 -#define IT5205_REG_CHIP_ID1 0x6 -#define IT5205_REG_CHIP_ID0 0x7 - -/* MUX power down register */ -#define IT5205_REG_MUXPDR 0x10 -#define IT5205_MUX_POWER_DOWN BIT(0) - -/* MUX control register */ -#define IT5205_REG_MUXCR 0x11 -#define IT5205_POLARITY_INVERTED BIT(4) - -#define IT5205_DP_USB_CTRL_MASK 0x0f -#define IT5205_DP 0x0f -#define IT5205_DP_USB 0x03 -#define IT5205_USB 0x07 - - -/* IT5205-H SBU module */ - -/* I2C address for SBU switch control */ -#define IT5205H_SBU_I2C_ADDR_FLAGS 0x6a - -/* Vref Select Register */ -#define IT5205H_REG_VSR 0x10 -#define IT5205H_VREF_SELECT_MASK 0x30 -#define IT5205H_VREF_SELECT_3_3V 0x00 -#define IT5205H_VREF_SELECT_OFF 0x20 - -/* CSBU OVP Select Register */ -#define IT5205H_REG_CSBUOVPSR 0x1e -#define IT5205H_OVP_SELECT_MASK 0x30 -#define IT5205H_OVP_3_90V 0x00 -#define IT5205H_OVP_3_68V 0x10 -#define IT5205H_OVP_3_62V 0x20 -#define IT5205H_OVP_3_57V 0x30 - -/* CSBU Switch Register */ -#define IT5205H_REG_CSBUSR 0x22 -#define IT5205H_CSBUSR_SWITCH BIT(0) - -/* Interrupt Switch Register */ -#define IT5205H_REG_ISR 0x25 -#define IT5205H_ISR_CSBU_MASK BIT(4) -#define IT5205H_ISR_CSBU_OVP BIT(0) - -enum ec_error_list it5205h_enable_csbu_switch(const struct usb_mux *me, - bool en); - -#endif /* __CROS_EC_IT5205_H */ diff --git a/driver/usb_mux/pi3usb3x532.c b/driver/usb_mux/pi3usb3x532.c deleted file mode 100644 index 2435157967..0000000000 --- a/driver/usb_mux/pi3usb3x532.c +++ /dev/null @@ -1,132 +0,0 @@ -/* 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. - * - * Pericom PI3USB3X532 USB port switch driver. - */ - -#include "common.h" -#include "i2c.h" -#include "pi3usb3x532.h" -#include "usb_mux.h" -#include "util.h" - -static int pi3usb3x532_read(const struct usb_mux *me, - uint8_t reg, uint8_t *val) -{ - int read, res; - - /* - * First byte read will be i2c address (ignored). - * Second byte read will be vendor ID. - * Third byte read will be selection control. - */ - res = i2c_read16(me->i2c_port, me->i2c_addr_flags, 0, &read); - if (res) - return res; - - if (reg == PI3USB3X532_REG_VENDOR) - *val = read & 0xff; - else /* reg == PI3USB3X532_REG_CONTROL */ - *val = (read >> 8) & 0xff; - - return EC_SUCCESS; -} - -static int pi3usb3x532_write(const struct usb_mux *me, - uint8_t reg, uint8_t val) -{ - if (reg != PI3USB3X532_REG_CONTROL) - return EC_ERROR_UNKNOWN; - - return i2c_write8(me->i2c_port, me->i2c_addr_flags, 0, val); -} - -int pi3usb3x532_check_vendor(const struct usb_mux *me, int *val) -{ - int res; - uint8_t read; - - res = pi3usb3x532_read(me, PI3USB3X532_REG_VENDOR, &read); - if (res) - return res; - - *val = read; - - return EC_SUCCESS; -} - -static int pi3usb3x532_reset(const struct usb_mux *me) -{ - return pi3usb3x532_write( - me, - PI3USB3X532_REG_CONTROL, - (PI3USB3X532_MODE_POWERDOWN & PI3USB3X532_CTRL_MASK) | - PI3USB3X532_CTRL_RSVD); -} - -static int pi3usb3x532_init(const struct usb_mux *me) -{ - uint8_t val; - int res; - - res = pi3usb3x532_reset(me); - if (res) - return res; - res = pi3usb3x532_read(me, PI3USB3X532_REG_VENDOR, &val); - if (res) - return res; - if (val != PI3USB3X532_VENDOR_ID) - return EC_ERROR_UNKNOWN; - - return EC_SUCCESS; -} - -/* Writes control register to set switch mode */ -static int pi3usb3x532_set_mux(const struct usb_mux *me, - mux_state_t mux_state, - bool *ack_required) -{ - uint8_t reg = 0; - - /* This driver does not use host command ACKs */ - *ack_required = false; - - if (mux_state & USB_PD_MUX_USB_ENABLED) - reg |= PI3USB3X532_MODE_USB; - if (mux_state & USB_PD_MUX_DP_ENABLED) - reg |= PI3USB3X532_MODE_DP; - if (mux_state & USB_PD_MUX_POLARITY_INVERTED) - reg |= PI3USB3X532_BIT_SWAP; - - return pi3usb3x532_write(me, PI3USB3X532_REG_CONTROL, - reg | PI3USB3X532_CTRL_RSVD); -} - -/* Reads control register and updates mux_state accordingly */ -static int pi3usb3x532_get_mux(const struct usb_mux *me, - mux_state_t *mux_state) -{ - uint8_t reg = 0; - uint8_t res; - - *mux_state = 0; - res = pi3usb3x532_read(me, PI3USB3X532_REG_CONTROL, ®); - if (res) - return res; - - if (reg & PI3USB3X532_MODE_USB) - *mux_state |= USB_PD_MUX_USB_ENABLED; - if (reg & PI3USB3X532_MODE_DP) - *mux_state |= USB_PD_MUX_DP_ENABLED; - if (reg & PI3USB3X532_BIT_SWAP) - *mux_state |= USB_PD_MUX_POLARITY_INVERTED; - - return EC_SUCCESS; -} - -const struct usb_mux_driver pi3usb3x532_usb_mux_driver = { - .init = pi3usb3x532_init, - .set = pi3usb3x532_set_mux, - .get = pi3usb3x532_get_mux, -}; diff --git a/driver/usb_mux/pi3usb3x532.h b/driver/usb_mux/pi3usb3x532.h deleted file mode 100644 index 6b398fdace..0000000000 --- a/driver/usb_mux/pi3usb3x532.h +++ /dev/null @@ -1,78 +0,0 @@ -/* 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. - * - * Pericom PI3USB3X532 USB port switch driver. - * - * Supported switches: - * - PI3USB30532 - * - PI3USB31532 - */ - -#ifndef __CROS_EC_PI3USB3X532_H -#define __CROS_EC_PI3USB3X532_H - -#include "usb_pd.h" -#include "usb_mux.h" - -/* I2C Addresses */ -#define PI3USB3X532_I2C_ADDR0 0x54 -#define PI3USB3X532_I2C_ADDR1 0x55 -#define PI3USB3X532_I2C_ADDR2 0x56 -#define PI3USB3X532_I2C_ADDR3 0x57 - -/* USB switch registers */ -#define PI3USB3X532_REG_ADDR 0x00 -#define PI3USB3X532_REG_VENDOR 0x01 -#define PI3USB3X532_REG_CONTROL 0x02 -/* Control register field */ -#define PI3USB3X532_CTRL_MASK 0x7 -#define PI3USB3X532_CTRL_RSVD 0 -/* Switch vendor ID */ -#define PI3USB3X532_VENDOR_ID 0 - -/* PI3USB3X532 control flags */ -#define PI3USB3X532_BIT_SWAP BIT(0) -#define PI3USB3X532_BIT_DP BIT(1) -#define PI3USB3X532_BIT_USB BIT(2) - -/* PI3USB3X532 modes */ -/* Power down, switch open */ -#define PI3USB3X532_MODE_POWERDOWN 0 -/* Keep power on, switch open */ -#define PI3USB3X532_MODE_POWERON 1 -/* 4-lane DP 1.2 - * dp0~3 : rx2, tx2, tx1, rx1 - * hpd+/-: rfu1, rfu2 - */ -#define PI3USB3X532_MODE_DP PI3USB3X532_BIT_DP -/* 4-lane DP 1.2 swap - * dp0~3 : rx1, tx1, tx2, rx2 - * hpd+/-: rfu2, rfu1 - */ -#define PI3USB3X532_MODE_DP_SWAP (PI3USB3X532_MODE_DP | PI3USB3X532_BIT_SWAP) -/* USB3 - * tx/rx : tx1, rx1 - */ -#define PI3USB3X532_MODE_USB PI3USB3X532_BIT_USB -/* USB3 swap - * tx/rx : tx2, rx2 - */ -#define PI3USB3X532_MODE_USB_SWAP (PI3USB3X532_MODE_USB | PI3USB3X532_BIT_SWAP) -/* 2-lane DP 1.2 + USB3 - * tx/rx : tx1, rx1 - * dp0~1 : rx2, tx2 - * hpd+/-: rfu1, rfu2 - */ -#define PI3USB3X532_MODE_DP_USB (PI3USB3X532_BIT_DP | PI3USB3X532_BIT_USB) -/* 2-lane DP 1.2 + USB3, swap - * tx/rx : tx2, rx2 - * dp0-1 : rx1, tx1 - * hpd+/-: rfu2, rfu1 - */ -#define PI3USB3X532_MODE_DP_USB_SWAP (PI3USB3X532_MODE_DP_USB | \ - PI3USB3X532_BIT_SWAP) - -/* Get Vendor ID */ -int pi3usb3x532_check_vendor(const struct usb_mux *me, int *val); -#endif /* __CROS_EC_PI3USB3X532_H */ diff --git a/driver/usb_mux/ps8740.c b/driver/usb_mux/ps8740.c deleted file mode 100644 index 618c74cd65..0000000000 --- a/driver/usb_mux/ps8740.c +++ /dev/null @@ -1,127 +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. - * - * Parade PS8740 (and PS8742) - * USB Type-C Redriving Switch for USB Host / DisplayPort. - */ - -#include "common.h" -#include "i2c.h" -#include "ps8740.h" -#include "usb_mux.h" -#include "util.h" - -int ps8740_read(const struct usb_mux *me, uint8_t reg, int *val) -{ - return i2c_read8(me->i2c_port, me->i2c_addr_flags, - reg, val); -} - -int ps8740_write(const struct usb_mux *me, uint8_t reg, uint8_t val) -{ - return i2c_write8(me->i2c_port, me->i2c_addr_flags, - reg, val); -} - -static int ps8740_init(const struct usb_mux *me) -{ - int id1; - int id2; - int res; - - /* Reset chip back to power-on state */ - res = ps8740_write(me, PS8740_REG_MODE, PS8740_MODE_POWER_DOWN); - if (res) - return res; - - /* - * Verify chip ID registers. - */ - res = ps8740_read(me, PS8740_REG_CHIP_ID1, &id1); - if (res) - return res; - - res = ps8740_read(me, PS8740_REG_CHIP_ID2, &id2); - if (res) - return res; - - if (id1 != PS8740_CHIP_ID1 || id2 != PS8740_CHIP_ID2) - return EC_ERROR_UNKNOWN; - - /* - * Verify revision ID registers. - */ - res = ps8740_read(me, PS8740_REG_REVISION_ID1, &id1); - if (res) - return res; - - res = ps8740_read(me, PS8740_REG_REVISION_ID2, &id2); - if (res) - return res; - - if (id1 != PS8740_REVISION_ID1) - return EC_ERROR_UNKNOWN; - /* PS8740 may have REVISION_ID2 as 0xa or 0xb */ - if (id2 != PS8740_REVISION_ID2_0 && id2 != PS8740_REVISION_ID2_1) - return EC_ERROR_UNKNOWN; - - return EC_SUCCESS; -} - -/* Writes control register to set switch mode */ -static int ps8740_set_mux(const struct usb_mux *me, mux_state_t mux_state, - bool *ack_required) -{ - uint8_t reg = 0; - - /* This driver does not use host command ACKs */ - *ack_required = false; - - if (mux_state & USB_PD_MUX_USB_ENABLED) - reg |= PS8740_MODE_USB_ENABLED; - if (mux_state & USB_PD_MUX_DP_ENABLED) - reg |= PS8740_MODE_DP_ENABLED; - if (mux_state & USB_PD_MUX_POLARITY_INVERTED) - reg |= PS8740_MODE_POLARITY_INVERTED; - - return ps8740_write(me, PS8740_REG_MODE, reg); -} - -/* Reads control register and updates mux_state accordingly */ -static int ps8740_get_mux(const struct usb_mux *me, mux_state_t *mux_state) -{ - int reg; - int res; - - res = ps8740_read(me, PS8740_REG_STATUS, ®); - if (res) - return res; - - *mux_state = 0; - if (reg & PS8740_STATUS_USB_ENABLED) - *mux_state |= USB_PD_MUX_USB_ENABLED; - if (reg & PS8740_STATUS_DP_ENABLED) - *mux_state |= USB_PD_MUX_DP_ENABLED; - if (reg & PS8740_STATUS_POLARITY_INVERTED) - *mux_state |= USB_PD_MUX_POLARITY_INVERTED; - - return EC_SUCCESS; -} - -/* Tune USB Tx/Rx Equalization */ -int ps8740_tune_usb_eq(const struct usb_mux *me, uint8_t tx, uint8_t rx) -{ - int ret; - - ret = ps8740_write(me, PS8740_REG_USB_EQ_TX, tx); - ret |= ps8740_write(me, PS8740_REG_USB_EQ_RX, rx); - - return ret; -} - -const struct usb_mux_driver ps8740_usb_mux_driver = { - .init = ps8740_init, - .set = ps8740_set_mux, - .get = ps8740_get_mux, -}; diff --git a/driver/usb_mux/ps8740.h b/driver/usb_mux/ps8740.h deleted file mode 100644 index 3a669b5ad9..0000000000 --- a/driver/usb_mux/ps8740.h +++ /dev/null @@ -1,91 +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. - * - * Parade PS8740 (and PS8742) - * USB Type-C Redriving Switch for USB Host / DisplayPort. - */ - -#ifndef __CROS_EC_PS8740_H -#define __CROS_EC_PS8740_H - -#include "usb_mux.h" - -#define PS8740_I2C_ADDR0_FLAG 0x10 -#define PS8740_I2C_ADDR1_FLAG 0x11 -#define PS8740_I2C_ADDR2_FLAG 0x19 -#define PS8740_I2C_ADDR3_FLAG 0x1a - -/* Mode register for setting mux */ -#define PS8740_REG_MODE 0x00 -#define PS8740_MODE_POLARITY_INVERTED BIT(4) -#define PS8740_MODE_USB_ENABLED BIT(5) -#define PS8740_MODE_DP_ENABLED BIT(6) -#ifdef CONFIG_USB_MUX_PS8740 - #define PS8740_MODE_POWER_DOWN BIT(7) -#elif defined(CONFIG_USB_MUX_PS8742) - #define PS8740_MODE_CE_DP_ENABLED BIT(7) - /* To reset the state machine to default */ - #define PS8740_MODE_POWER_DOWN 0 -#endif - -/* Status register for checking mux state */ -#define PS8740_REG_STATUS 0x09 -#define PS8740_STATUS_POLARITY_INVERTED BIT(2) -#define PS8740_STATUS_USB_ENABLED BIT(3) -#define PS8740_STATUS_DP_ENABLED BIT(4) -#define PS8740_STATUS_HPD_ASSERTED BIT(7) - -/* Chip ID / revision registers and expected fused values */ -#define PS8740_REG_REVISION_ID1 0xf0 -#define PS8740_REG_REVISION_ID2 0xf1 -#define PS8740_REG_CHIP_ID1 0xf2 -#define PS8740_REG_CHIP_ID2 0xf3 -#ifdef CONFIG_USB_MUX_PS8740 - #define PS8740_REVISION_ID1 0x00 - #define PS8740_REVISION_ID2_0 0x0a - #define PS8740_REVISION_ID2_1 0x0b - #define PS8740_CHIP_ID1 0x40 -#elif defined(CONFIG_USB_MUX_PS8742) - #define PS8740_REVISION_ID1 0x01 - #define PS8740_REVISION_ID2_0 0x0a - #define PS8740_REVISION_ID2_1 0x0a - #define PS8740_CHIP_ID1 0x42 -#endif -#define PS8740_CHIP_ID2 0x87 - -/* USB equalization settings for Host to Mux */ -#define PS8740_REG_USB_EQ_TX 0x32 -#define PS8740_USB_EQ_TX_10_1_DB 0x00 -#define PS8740_USB_EQ_TX_14_3_DB 0x20 -#define PS8740_USB_EQ_TX_8_5_DB 0x40 -#define PS8740_USB_EQ_TX_6_5_DB 0x60 -#define PS8740_USB_EQ_TX_11_5_DB 0x80 -#define PS8740_USB_EQ_TX_9_5_DB 0xc0 -#define PS8740_USB_EQ_TX_7_5_DB 0xe0 -#define PS8740_USB_EQ_TERM_100_OHM (0 << 2) -#define PS8740_USB_EQ_TERM_85_OHM BIT(2) - -/* USB equalization settings for Connector to Mux */ -#define PS8740_REG_USB_EQ_RX 0x3b -#define PS8740_USB_EQ_RX_4_4_DB 0x00 -#define PS8740_USB_EQ_RX_7_0_DB 0x10 -#define PS8740_USB_EQ_RX_8_2_DB 0x20 -#define PS8740_USB_EQ_RX_9_4_DB 0x30 -#define PS8740_USB_EQ_RX_10_2_DB 0x40 -#define PS8740_USB_EQ_RX_11_4_DB 0x50 -#define PS8740_USB_EQ_RX_14_3_DB 0x60 -#define PS8740_USB_EQ_RX_14_8_DB 0x70 -#define PS8740_USB_EQ_RX_15_2_DB 0x80 -#define PS8740_USB_EQ_RX_15_5_DB 0x90 -#define PS8740_USB_EQ_RX_16_2_DB 0xa0 -#define PS8740_USB_EQ_RX_17_3_DB 0xb0 -#define PS8740_USB_EQ_RX_18_4_DB 0xc0 -#define PS8740_USB_EQ_RX_20_1_DB 0xd0 -#define PS8740_USB_EQ_RX_21_3_DB 0xe0 - -int ps8740_tune_usb_eq(const struct usb_mux *me, uint8_t tx, uint8_t rx); -int ps8740_write(const struct usb_mux *me, uint8_t reg, uint8_t val); -int ps8740_read(const struct usb_mux *me, uint8_t reg, int *val); - -#endif /* __CROS_EC_PS8740_H */ diff --git a/driver/usb_mux/ps8743.c b/driver/usb_mux/ps8743.c deleted file mode 100644 index f618bb009f..0000000000 --- a/driver/usb_mux/ps8743.c +++ /dev/null @@ -1,158 +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. - * - * Parade PS8743 USB Type-C Redriving Switch for USB Host / DisplayPort. - */ - -#include "common.h" -#include "i2c.h" -#include "ps8743.h" -#include "usb_mux.h" -#include "util.h" - -int ps8743_read(const struct usb_mux *me, uint8_t reg, int *val) -{ - return i2c_read8(me->i2c_port, me->i2c_addr_flags, - reg, val); -} - -int ps8743_write(const struct usb_mux *me, uint8_t reg, uint8_t val) -{ - return i2c_write8(me->i2c_port, me->i2c_addr_flags, - reg, val); -} - -int ps8743_check_chip_id(const struct usb_mux *me, int *val) -{ - int id1; - int id2; - int res; - - /* - * Verify chip ID registers. - */ - res = ps8743_read(me, PS8743_REG_CHIP_ID1, &id1); - if (res) - return res; - - res = ps8743_read(me, PS8743_REG_CHIP_ID2, &id2); - if (res) - return res; - - *val = (id2 << 8) + id1; - - return EC_SUCCESS; -} - -static int ps8743_init(const struct usb_mux *me) -{ - int id1; - int id2; - int res; - - /* Reset chip back to power-on state */ - res = ps8743_write(me, PS8743_REG_MODE, PS8743_MODE_POWER_DOWN); - if (res) - return res; - - /* - * Verify chip ID registers. - */ - res = ps8743_read(me, PS8743_REG_CHIP_ID1, &id1); - if (res) - return res; - - res = ps8743_read(me, PS8743_REG_CHIP_ID2, &id2); - if (res) - return res; - - if (id1 != PS8743_CHIP_ID1 || id2 != PS8743_CHIP_ID2) - return EC_ERROR_UNKNOWN; - - /* - * Verify revision ID registers. - */ - res = ps8743_read(me, PS8743_REG_REVISION_ID1, &id1); - if (res) - return res; - - res = ps8743_read(me, PS8743_REG_REVISION_ID2, &id2); - if (res) - return res; - - /* - * From Parade: PS8743 may have REVISION_ID1 as 0 or 1 - * Rev 1 is derived from Rev 0 and have same functionality. - */ - if (id1 != PS8743_REVISION_ID1_0 && id1 != PS8743_REVISION_ID1_1) - return EC_ERROR_UNKNOWN; - if (id2 != PS8743_REVISION_ID2) - return EC_ERROR_UNKNOWN; - - return EC_SUCCESS; -} - -/* Writes control register to set switch mode */ -static int ps8743_set_mux(const struct usb_mux *me, mux_state_t mux_state, - bool *ack_required) -{ - /* - * For CE_DP, CE_USB, and FLIP, disable pin control and enable I2C - * control. - */ - uint8_t reg = (PS8743_MODE_IN_HPD_CONTROL | - PS8743_MODE_DP_REG_CONTROL | - PS8743_MODE_USB_REG_CONTROL | - PS8743_MODE_FLIP_REG_CONTROL); - - /* This driver does not use host command ACKs */ - *ack_required = false; - - if (mux_state & USB_PD_MUX_USB_ENABLED) - reg |= PS8743_MODE_USB_ENABLE; - if (mux_state & USB_PD_MUX_DP_ENABLED) - reg |= PS8743_MODE_DP_ENABLE | PS8743_MODE_IN_HPD_ASSERT; - if (mux_state & USB_PD_MUX_POLARITY_INVERTED) - reg |= PS8743_MODE_FLIP_ENABLE; - - return ps8743_write(me, PS8743_REG_MODE, reg); -} - -/* Reads control register and updates mux_state accordingly */ -static int ps8743_get_mux(const struct usb_mux *me, mux_state_t *mux_state) -{ - int reg; - int res; - - res = ps8743_read(me, PS8743_REG_STATUS, ®); - if (res) - return res; - - *mux_state = 0; - if (reg & PS8743_STATUS_USB_ENABLED) - *mux_state |= USB_PD_MUX_USB_ENABLED; - if (reg & PS8743_STATUS_DP_ENABLED) - *mux_state |= USB_PD_MUX_DP_ENABLED; - if (reg & PS8743_STATUS_POLARITY_INVERTED) - *mux_state |= USB_PD_MUX_POLARITY_INVERTED; - - return EC_SUCCESS; -} - -/* Tune USB Tx/Rx Equalization */ -int ps8743_tune_usb_eq(const struct usb_mux *me, uint8_t tx, uint8_t rx) -{ - int ret; - - ret = ps8743_write(me, PS8743_REG_USB_EQ_TX, tx); - ret |= ps8743_write(me, PS8743_REG_USB_EQ_RX, rx); - - return ret; -} - -const struct usb_mux_driver ps8743_usb_mux_driver = { - .init = ps8743_init, - .set = ps8743_set_mux, - .get = ps8743_get_mux, -}; diff --git a/driver/usb_mux/ps8743.h b/driver/usb_mux/ps8743.h deleted file mode 100644 index 741b93e98a..0000000000 --- a/driver/usb_mux/ps8743.h +++ /dev/null @@ -1,32 +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. - * - * Parade PS8743 USB Type-C Redriving Switch for USB Host / DisplayPort. - */ - -#ifndef __CROS_EC_PS8743_H -#define __CROS_EC_PS8743_H - -#include "usb_mux.h" -#include "usb_mux/ps8743_public.h" - -/* Status register for checking mux state */ -#define PS8743_REG_STATUS 0x09 -#define PS8743_STATUS_POLARITY_INVERTED BIT(2) -#define PS8743_STATUS_USB_ENABLED BIT(3) -#define PS8743_STATUS_DP_ENABLED BIT(4) -#define PS8743_STATUS_HPD_ASSERTED BIT(7) - -/* Chip ID / revision registers and expected fused values */ -#define PS8743_REG_REVISION_ID1 0xf0 -#define PS8743_REG_REVISION_ID2 0xf1 -#define PS8743_REG_CHIP_ID1 0xf2 -#define PS8743_REG_CHIP_ID2 0xf3 -#define PS8743_REVISION_ID1_0 0x00 -#define PS8743_REVISION_ID1_1 0x01 -#define PS8743_REVISION_ID2 0x0b -#define PS8743_CHIP_ID1 0x41 -#define PS8743_CHIP_ID2 0x87 - -#endif /* __CROS_EC_PS8743_H */ diff --git a/driver/usb_mux/ps8822.c b/driver/usb_mux/ps8822.c deleted file mode 100644 index 7f25db37f4..0000000000 --- a/driver/usb_mux/ps8822.c +++ /dev/null @@ -1,134 +0,0 @@ -/* Copyright 2021 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. - * - * Parade PS8822 - * USB Type-C Redriving Switch for USB Host / DisplayPort. - */ - -#include "common.h" -#include "i2c.h" -#include "ps8822.h" -#include "usb_mux.h" -#include "util.h" - -static int ps8822_read(const struct usb_mux *me, int page, uint8_t reg, - int *val) -{ - return i2c_read8(me->i2c_port, me->i2c_addr_flags + page, - reg, val); -} - -static int ps8822_write(const struct usb_mux *me, int page, uint8_t reg, - int val) -{ - return i2c_write8(me->i2c_port, me->i2c_addr_flags + page, - reg, val); -} - -int ps8822_set_dp_rx_eq(const struct usb_mux *me, int db) -{ - int dpeq_reg; - int rv; - - /* Read DP EQ register */ - rv = ps8822_read(me, PS8822_REG_PAGE1, PS8822_REG_DP_EQ, - &dpeq_reg); - if (rv) - return rv; - - if (db < PS8822_DPEQ_LEVEL_UP_9DB || db > PS8822_DPEQ_LEVEL_UP_21DB) - return EC_ERROR_INVAL; - - /* Disable auto eq */ - dpeq_reg &= ~PS8822_DP_EQ_AUTO_EN; - - /* Set gain to the requested value */ - dpeq_reg &= ~(PS8822_DPEQ_LEVEL_UP_MASK << - PS8822_REG_DP_EQ_SHIFT); - dpeq_reg |= (db << PS8822_REG_DP_EQ_SHIFT); - - /* Apply new EQ setting */ - return ps8822_write(me, PS8822_REG_PAGE1, PS8822_REG_DP_EQ, - dpeq_reg); -} - -static int ps8822_init(const struct usb_mux *me) -{ - char id[PS8822_ID_LEN + 1]; - int reg; - int i; - int rv = 0; - - /* Read ID registers */ - for (i = 0; i < PS8822_ID_LEN; i++) { - rv |= ps8822_read(me, PS8822_REG_PAGE0, PS8822_REG_DEV_ID1 + i, - ®); - if (!rv) - id[i] = reg; - } - - if (!rv) { - id[PS8822_ID_LEN] = '\0'; - /* Set mode register to default value */ - rv = ps8822_write(me, PS8822_REG_PAGE0, PS8822_REG_MODE, 0); - rv |= strcasecmp("PS8822", id); - } - - return rv; -} - -/* Writes control register to set switch mode */ -static int ps8822_set_mux(const struct usb_mux *me, mux_state_t mux_state, - bool *ack_required) -{ - int reg; - int rv; - - /* This driver does not use host command ACKs */ - *ack_required = false; - - rv = ps8822_read(me, PS8822_REG_PAGE0, PS8822_REG_MODE, ®); - if (rv) - return rv; - - /* Assume standby, preserve PIN_E config bit */ - reg &= ~(PS8822_MODE_ALT_DP_EN | PS8822_MODE_USB_EN | PS8822_MODE_FLIP); - - if (mux_state & USB_PD_MUX_USB_ENABLED) - reg |= PS8822_MODE_USB_EN; - if (mux_state & USB_PD_MUX_DP_ENABLED) - reg |= PS8822_MODE_ALT_DP_EN; - if (mux_state & USB_PD_MUX_POLARITY_INVERTED) - reg |= PS8822_MODE_FLIP; - - return ps8822_write(me, PS8822_REG_PAGE0, PS8822_REG_MODE, reg); -} - -/* Reads control register and updates mux_state accordingly */ -static int ps8822_get_mux(const struct usb_mux *me, mux_state_t *mux_state) -{ - int reg; - int res; - - res = ps8822_read(me, PS8822_REG_PAGE0, PS8822_REG_MODE, ®); - if (res) - return res; - - *mux_state = 0; - if (reg & PS8822_MODE_USB_EN) - *mux_state |= USB_PD_MUX_USB_ENABLED; - if (reg & PS8822_MODE_ALT_DP_EN) - *mux_state |= USB_PD_MUX_DP_ENABLED; - if (reg & PS8822_MODE_FLIP) - *mux_state |= USB_PD_MUX_POLARITY_INVERTED; - - return EC_SUCCESS; -} - - -const struct usb_mux_driver ps8822_usb_mux_driver = { - .init = ps8822_init, - .set = ps8822_set_mux, - .get = ps8822_get_mux, -}; diff --git a/driver/usb_mux/ps8822.h b/driver/usb_mux/ps8822.h deleted file mode 100644 index 86b911db70..0000000000 --- a/driver/usb_mux/ps8822.h +++ /dev/null @@ -1,66 +0,0 @@ -/* Copyright 2021 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. - * - * Parade PS8822 - * USB Type-C Retiming Switch for USB Device / DisplayPort Sink - */ - -#ifndef __CROS_EC_PS8822_H -#define __CROS_EC_PS8822_H - -#include "usb_mux.h" - -#define PS8822_I2C_ADDR0_FLAG 0x10 -#define PS8822_I2C_ADDR1_FLAG 0x18 -#define PS8822_I2C_ADDR2_FLAG 0x58 -#define PS8822_I2C_ADDR3_FLAG 0x60 - -#define PS8822_REG_PAGE0 0x00 - -/* Mode register for setting mux */ -#define PS8822_REG_MODE 0x01 -#define PS8822_MODE_ALT_DP_EN BIT(7) -#define PS8822_MODE_USB_EN BIT(6) -#define PS8822_MODE_FLIP BIT(5) -#define PS8822_MODE_PIN_E BIT(4) - -#define PS8822_REG_CONFIG 0x02 -#define PS8822_CONFIG_HPD_IN_DIS BIT(7) -#define PS8822_CONFIG_DP_PLUG BIT(6) - -#define PS8822_REG_DEV_ID1 0x06 -#define PS8822_REG_DEV_ID2 0x07 -#define PS8822_REG_DEV_ID3 0x08 -#define PS8822_REG_DEV_ID4 0x09 -#define PS8822_REG_DEV_ID5 0x0A -#define PS8822_REG_DEV_ID6 0x0B - -#define PS8822_ID_LEN 6 - -#define PS8822_REG_PAGE1 0x01 -#define PS8822_REG_DP_EQ 0xB6 -#define PS8822_DP_EQ_AUTO_EN BIT(7) - -#define PS8822_DPEQ_LEVEL_UP_9DB 0x00 -#define PS8822_DPEQ_LEVEL_UP_11DB 0x01 -#define PS8822_DPEQ_LEVEL_UP_12DB 0x02 -#define PS8822_DPEQ_LEVEL_UP_14DB 0x03 -#define PS8822_DPEQ_LEVEL_UP_17DB 0x04 -#define PS8822_DPEQ_LEVEL_UP_18DB 0x05 -#define PS8822_DPEQ_LEVEL_UP_19DB 0x06 -#define PS8822_DPEQ_LEVEL_UP_20DB 0x07 -#define PS8822_DPEQ_LEVEL_UP_21DB 0x08 -#define PS8822_DPEQ_LEVEL_UP_MASK 0x0F -#define PS8822_REG_DP_EQ_SHIFT 3 - -/** - * Set DP Rx Equalization value - * - * @param *me pointer to usb_mux descriptor - * @param db requested gain setting for DP Rx path - * @return EC_SUCCESS if db param is valid and I2C is successful - */ -int ps8822_set_dp_rx_eq(const struct usb_mux *me, int db); - -#endif /* __CROS_EC_PS8822_H */ diff --git a/driver/usb_mux/tusb1064.c b/driver/usb_mux/tusb1064.c deleted file mode 100644 index 1c0f0e4701..0000000000 --- a/driver/usb_mux/tusb1064.c +++ /dev/null @@ -1,116 +0,0 @@ -/* Copyright 2021 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 "i2c.h" -#include "tusb1064.h" -#include "usb_mux.h" - -#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args) - -/* - * configuration bits which never change in the General Register - * e.g. REG_GENERAL_DP_EN_CTRL or REG_GENERAL_EQ_OVERRIDE - */ -#define REG_GENERAL_STATIC_BITS REG_GENERAL_EQ_OVERRIDE - -static int tusb1064_read(const struct usb_mux *me, uint8_t reg, uint8_t *val) -{ - int buffer = 0xee; - int res = i2c_read8(me->i2c_port, me->i2c_addr_flags, - (int)reg, &buffer); - *val = buffer; - return res; -} - -static int tusb1064_write(const struct usb_mux *me, uint8_t reg, uint8_t val) -{ - return i2c_write8(me->i2c_port, me->i2c_addr_flags, - (int)reg, (int)val); -} - -/* Writes control register to set switch mode */ -static int tusb1064_set_mux(const struct usb_mux *me, mux_state_t mux_state, - bool *ack_required) -{ - int reg = REG_GENERAL_STATIC_BITS; - - /* This driver does not use host command ACKs */ - *ack_required = false; - - if (mux_state & USB_PD_MUX_USB_ENABLED) - reg |= REG_GENERAL_CTLSEL_USB3; - if (mux_state & USB_PD_MUX_DP_ENABLED) - reg |= REG_GENERAL_CTLSEL_ANYDP; - if (mux_state & USB_PD_MUX_POLARITY_INVERTED) - reg |= REG_GENERAL_FLIPSEL; - - return tusb1064_write(me, TUSB1064_REG_GENERAL, reg); -} - -/* Reads control register and updates mux_state accordingly */ -static int tusb1064_get_mux(const struct usb_mux *me, mux_state_t *mux_state) -{ - uint8_t reg; - int res; - - res = tusb1064_read(me, TUSB1064_REG_GENERAL, ®); - if (res) - return EC_ERROR_INVAL; - - *mux_state = 0; - if (reg & REG_GENERAL_CTLSEL_USB3) - *mux_state |= USB_PD_MUX_USB_ENABLED; - if (reg & REG_GENERAL_CTLSEL_ANYDP) - *mux_state |= USB_PD_MUX_DP_ENABLED; - if (reg & REG_GENERAL_FLIPSEL) - *mux_state |= USB_PD_MUX_POLARITY_INVERTED; - - return EC_SUCCESS; -} - -/* Generic driver init function */ -static int tusb1064_init(const struct usb_mux *me) -{ - int res; - uint8_t reg; - bool unused; - - /* Default to "Floating Pin" DP Equalization */ - reg = TUSB1064_DP1EQ(TUSB1064_DP_EQ_RX_10_0_DB) | - TUSB1064_DP3EQ(TUSB1064_DP_EQ_RX_10_0_DB); - res = tusb1064_write(me, TUSB1064_REG_DP1DP3EQ_SEL, reg); - if (res) - return res; - - reg = TUSB1064_DP0EQ(TUSB1064_DP_EQ_RX_10_0_DB) | - TUSB1064_DP2EQ(TUSB1064_DP_EQ_RX_10_0_DB); - res = tusb1064_write(me, TUSB1064_REG_DP0DP2EQ_SEL, reg); - if (res) - return res; - - /* - * Note that bypassing the usb_mux API is okay for internal driver calls - * since the task calling init already holds this port's mux lock. - */ - /* Disconnect USB3.1 and DP */ - res = tusb1064_set_mux(me, USB_PD_MUX_NONE, &unused); - if (res) - return res; - - /* Disable AUX mux override */ - res = tusb1064_write(me, TUSB1064_REG_AUXDPCTRL, 0); - if (res) - return res; - - return EC_SUCCESS; -} - -const struct usb_mux_driver tusb1064_usb_mux_driver = { - /* CAUTION: This is an UFP/RX/SINK redriver mux */ - .init = tusb1064_init, - .set = tusb1064_set_mux, - .get = tusb1064_get_mux, -}; diff --git a/driver/usb_mux/tusb1064.h b/driver/usb_mux/tusb1064.h deleted file mode 100644 index e860cc539a..0000000000 --- a/driver/usb_mux/tusb1064.h +++ /dev/null @@ -1,130 +0,0 @@ -/* Copyright 2021 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. - */ - -#ifndef __CROS_EC_TUSB1064_H -#define __CROS_EC_TUSB1064_H - -#include <stdint.h> -#include "usb_mux.h" - -/* - * TUSB1064 Has 16 possible device addresses which are selected by A1|A0 lines - * using 4 level inputs. - * 0 -> tied directly to GND - * R -> tied to GND via a 20k pulldown - * F -> floating - * 1 -> tied to VCC - */ -#define TUSB1064_I2C_ADDR0_FLAGS 0x44 -#define TUSB1064_I2C_ADDR1_FLAGS 0x45 -#define TUSB1064_I2C_ADDR2_FLAGS 0x46 -#define TUSB1064_I2C_ADDR3_FLAGS 0x47 -#define TUSB1064_I2C_ADDR4_FLAGS 0x20 -#define TUSB1064_I2C_ADDR5_FLAGS 0x21 -#define TUSB1064_I2C_ADDR6_FLAGS 0x22 -#define TUSB1064_I2C_ADDR7_FLAGS 0x23 -#define TUSB1064_I2C_ADDR8_FLAGS 0x10 -#define TUSB1064_I2C_ADDR9_FLAGS 0x11 -#define TUSB1064_I2C_ADDR10_FLAGS 0x12 -#define TUSB1064_I2C_ADDR11_FLAGS 0x13 -#define TUSB1064_I2C_ADDR12_FLAGS 0x0C -#define TUSB1064_I2C_ADDR13_FLAGS 0x0D -#define TUSB1064_I2C_ADDR14_FLAGS 0x0E -#define TUSB1064_I2C_ADDR15_FLAGS 0x0F - -/* TUSB1064 General Register */ -#define TUSB1064_REG_GENERAL 0x0a -#define REG_GENERAL_CTLSEL_USB3 BIT(0) -#define REG_GENERAL_CTLSEL_ANYDP BIT(1) -#define REG_GENERAL_FLIPSEL BIT(2) -#define REG_GENERAL_DP_EN_CTRL BIT(3) -#define REG_GENERAL_EQ_OVERRIDE BIT(4) - -/* AUX and DP Lane Control Register */ -#define TUSB1064_REG_AUXDPCTRL 0x13 -#define TUSB1064_AUXDPCTRL_AUX_SNOOP_DISABLE BIT(7) -#define TUSB1064_AUXDPCTRL_AUX_SBU_OVR 0x30 -#define TUSB1064_AUXDPCTRL_DP3_DISABLE BIT(3) -#define TUSB1064_AUXDPCTRL_DP2_DISABLE BIT(2) -#define TUSB1064_AUXDPCTRL_DP1_DISABLE BIT(1) -#define TUSB1064_AUXDPCTRL_DP0_DISABLE BIT(0) - -/* Receiver Equalization GPIO Control */ -#define TUSB1064_REG_DP1DP3EQ_SEL 0x10 -#define TUSB1064_REG_DP0DP2EQ_SEL 0x11 - -/* DP Receiver equalization settings */ -#define TUSB1064_DP_EQ_RX_NEG_0_3_DB 0x0 -#define TUSB1064_DP_EQ_RX_1_6_DB 0x1 -#define TUSB1064_DP_EQ_RX_3_0_DB 0x2 -#define TUSB1064_DP_EQ_RX_4_4_DB 0x3 -#define TUSB1064_DP_EQ_RX_5_4_DB 0x4 -#define TUSB1064_DP_EQ_RX_6_5_DB 0x5 -#define TUSB1064_DP_EQ_RX_7_3_DB 0x6 -#define TUSB1064_DP_EQ_RX_8_1_DB 0x7 -#define TUSB1064_DP_EQ_RX_8_9_DB 0x8 -#define TUSB1064_DP_EQ_RX_9_5_DB 0x9 -#define TUSB1064_DP_EQ_RX_10_0_DB 0xA -#define TUSB1064_DP_EQ_RX_10_6_DB 0xB -#define TUSB1064_DP_EQ_RX_11_0_DB 0xC -#define TUSB1064_DP_EQ_RX_11_4_DB 0xD -#define TUSB1064_DP_EQ_RX_11_8_DB 0xE -#define TUSB1064_DP_EQ_RX_12_1_DB 0xF - -#ifndef TUSB1064_DP1EQ -#define TUSB1064_DP1EQ(nr) ((nr) << 4) -#endif -#ifndef TUSB1064_DP3EQ -#define TUSB1064_DP3EQ(nr) ((nr) << 0) -#endif -#ifndef TUSB1064_DP0EQ -#define TUSB1064_DP0EQ(nr) ((nr) << 4) -#endif -#ifndef TUSB1064_DP2EQ -#define TUSB1064_DP2EQ(nr) ((nr) << 0) -#endif - - -/* TUSB1064 Receiver Equalization GPIO Control */ -#define TUSB1064_REG_SSRX2RX1EQ_SEL 0x20 -#define TUSB1064_REG_SSTXEQ_SEL 0x21 - -/* USB equalization settings for Mux DFP (TX) */ -#define TUSB1064_USB_EQ_DFP_NEG_3_0_DB 0x0 -#define TUSB1064_USB_EQ_DFP_NEG_0_8_DB 0x1 -#define TUSB1064_USB_EQ_DFP_NEG_0_7_DB 0x2 -#define TUSB1064_USB_EQ_DFP_2_2_DB 0x3 -#define TUSB1064_USB_EQ_DFP_3_3_DB 0x4 -#define TUSB1064_USB_EQ_DFP_4_3_DB 0x5 -#define TUSB1064_USB_EQ_DFP_5_1_DB 0x6 -#define TUSB1064_USB_EQ_DFP_6_0_DB 0x7 -#define TUSB1064_USB_EQ_DFP_6_7_DB 0x8 -#define TUSB1064_USB_EQ_DFP_7_3_DB 0x9 -#define TUSB1064_USB_EQ_DFP_7_8_DB 0xA -#define TUSB1064_USB_EQ_DFP_8_3_DB 0xB -#define TUSB1064_USB_EQ_DFP_8_6_DB 0xC -#define TUSB1064_USB_EQ_DFP_9_0_DB 0xD -#define TUSB1064_USB_EQ_DFP_9_3_DB 0xE -#define TUSB1064_USB_EQ_DFP_9_7_DB 0xF - -/* USB equalization settings for Mux UFP (RX) */ -#define TUSB1064_USB_EQ_UFP_NEG_1_5_DB 0x0 -#define TUSB1064_USB_EQ_UFP_0_7_DB 0x1 -#define TUSB1064_USB_EQ_UFP_2_2_DB 0x2 -#define TUSB1064_USB_EQ_UFP_3_7_DB 0x3 -#define TUSB1064_USB_EQ_UFP_4_7_DB 0x4 -#define TUSB1064_USB_EQ_UFP_5_8_DB 0x5 -#define TUSB1064_USB_EQ_UFP_6_6_DB 0x6 -#define TUSB1064_USB_EQ_UFP_7_4_DB 0x7 -#define TUSB1064_USB_EQ_UFP_8_1_DB 0x8 -#define TUSB1064_USB_EQ_UFP_8_7_DB 0x9 -#define TUSB1064_USB_EQ_UFP_9_2_DB 0xA -#define TUSB1064_USB_EQ_UFP_9_7_DB 0xB -#define TUSB1064_USB_EQ_UFP_10_0_DB 0xC -#define TUSB1064_USB_EQ_UFP_10_4_DB 0xD -#define TUSB1064_USB_EQ_UFP_10_7_DB 0xE -#define TUSB1064_USB_EQ_UFP_11_1_DB 0xF - -#endif /* __CROS_EC_TUSB1064_H */ diff --git a/driver/usb_mux/usb_mux.c b/driver/usb_mux/usb_mux.c deleted file mode 100644 index 155ba8fb3e..0000000000 --- a/driver/usb_mux/usb_mux.c +++ /dev/null @@ -1,524 +0,0 @@ -/* 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. - */ - -/* USB mux high-level driver. */ - -#include "atomic.h" -#include "common.h" -#include "console.h" -#include "chipset.h" -#include "hooks.h" -#include "host_command.h" -#include "task.h" -#include "timer.h" -#include "usb_mux.h" -#include "usbc_ppc.h" -#include "util.h" - -#ifdef CONFIG_COMMON_RUNTIME -#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args) -#else -#define CPRINTS(format, args...) -#define CPRINTF(format, args...) -#endif - -static int enable_debug_prints; - -/* - * Flags will reset to 0 after sysjump; This works for current flags as LPM will - * get reset in the init method which is called during PD task startup. - */ -static uint32_t flags[CONFIG_USB_PD_PORT_MAX_COUNT]; - -/* Device is in low power mode. */ -#define USB_MUX_FLAG_IN_LPM BIT(0) - -/* Device initialized at least once */ -#define USB_MUX_FLAG_INIT BIT(1) - -/* Coordinate mux accesses by-port among the tasks */ -static mutex_t mux_lock[CONFIG_USB_PD_PORT_MAX_COUNT]; - -/* Coordinate which task requires an ACK event */ -static task_id_t ack_task[CONFIG_USB_PD_PORT_MAX_COUNT] = { - [0 ... CONFIG_USB_PD_PORT_MAX_COUNT - 1] = TASK_ID_INVALID }; - -enum mux_config_type { - USB_MUX_INIT, - USB_MUX_LOW_POWER, - USB_MUX_SET_MODE, - USB_MUX_GET_MODE, - USB_MUX_CHIPSET_RESET, - USB_MUX_HPD_UPDATE, -}; - -#ifdef CONFIG_ZEPHYR -static int init_mux_mutex(const struct device *dev) -{ - int port; - - ARG_UNUSED(dev); - for (port = 0; port < CONFIG_USB_PD_PORT_MAX_COUNT; port++) - k_mutex_init(&mux_lock[port]); - return 0; -} -SYS_INIT(init_mux_mutex, POST_KERNEL, 50); -#endif /* CONFIG_ZEPHYR */ - -/* Configure the MUX */ -static int configure_mux(int port, - enum mux_config_type config, - mux_state_t *mux_state) -{ - int rv = EC_SUCCESS; - const struct usb_mux *mux_ptr; - - if (config == USB_MUX_SET_MODE || - config == USB_MUX_GET_MODE) { - if (mux_state == NULL) - return EC_ERROR_INVAL; - - if (config == USB_MUX_GET_MODE) - *mux_state = USB_PD_MUX_NONE; - } - - /* - * a MUX for a particular port can be a linked list chain of - * MUXes. So when we change one, we traverse the whole list - * to make sure they are all updated appropriately. - */ - for (mux_ptr = &usb_muxes[port]; - rv == EC_SUCCESS && mux_ptr != NULL; - mux_ptr = mux_ptr->next_mux) { - mux_state_t lcl_state; - const struct usb_mux_driver *drv = mux_ptr->driver; - bool ack_required = false; - - /* Action time! Lock this mux */ - mutex_lock(&mux_lock[port]); - - switch (config) { - case USB_MUX_INIT: - if (drv && drv->init) { - rv = drv->init(mux_ptr); - if (rv) - break; - } - - /* Apply board specific initialization */ - if (mux_ptr->board_init) - rv = mux_ptr->board_init(mux_ptr); - - break; - - case USB_MUX_LOW_POWER: - if (drv && drv->enter_low_power_mode) - rv = drv->enter_low_power_mode(mux_ptr); - - break; - - case USB_MUX_CHIPSET_RESET: - if (drv && drv->chipset_reset) - rv = drv->chipset_reset(mux_ptr); - - break; - - case USB_MUX_SET_MODE: - lcl_state = *mux_state; - - if (mux_ptr->flags & USB_MUX_FLAG_SET_WITHOUT_FLIP) - lcl_state &= ~USB_PD_MUX_POLARITY_INVERTED; - - if (drv && drv->set) { - rv = drv->set(mux_ptr, lcl_state, - &ack_required); - if (rv) - break; - } - - if (ack_required) - ack_task[port] = task_get_current(); - - /* Apply board specific setting */ - if (mux_ptr->board_set) - rv = mux_ptr->board_set(mux_ptr, lcl_state); - - break; - - case USB_MUX_GET_MODE: - /* - * This is doing a GET_CC on all of the MUXes in the - * chain and ORing them together. This will make sure - * if one of the MUX values has FLIP turned off that - * we will end up with the correct value in the end. - */ - if (drv && drv->get) { - rv = drv->get(mux_ptr, &lcl_state); - if (rv) - break; - *mux_state |= lcl_state; - } - break; - - case USB_MUX_HPD_UPDATE: - if (mux_ptr->hpd_update) - mux_ptr->hpd_update(mux_ptr, *mux_state); - - } - - /* Unlock before any host command waits */ - mutex_unlock(&mux_lock[port]); - - if (ack_required) { - /* This should only be called from the PD task */ - assert(port == TASK_ID_TO_PD_PORT(task_get_current())); - - /* - * Note: This task event could be generalized for more - * purposes beyond host command ACKs. For now, these - * wait times are tuned for the purposes of the TCSS - * mux, but could be made configurable for other - * purposes. - */ - task_wait_event_mask(PD_EVENT_AP_MUX_DONE, 100*MSEC); - ack_task[port] = TASK_ID_INVALID; - - usleep(12.5 * MSEC); - } - } - - if (rv) - CPRINTS("mux config:%d, port:%d, rv:%d", - config, port, rv); - - return rv; -} - -static void enter_low_power_mode(int port) -{ - /* - * Set LPM flag regardless of method presence or method failure. We - * want know know that we tried to put the device in low power mode - * so we can re-initialize the device on the next access. - */ - atomic_or(&flags[port], USB_MUX_FLAG_IN_LPM); - - /* Apply any low power customization if present */ - configure_mux(port, USB_MUX_LOW_POWER, NULL); -} - -static int exit_low_power_mode(int port) -{ - /* If we are in low power, initialize device (which clears LPM flag) */ - if (flags[port] & USB_MUX_FLAG_IN_LPM) - usb_mux_init(port); - - if (!(flags[port] & USB_MUX_FLAG_INIT)) { - CPRINTS("C%d: USB_MUX_FLAG_INIT not set", port); - return EC_ERROR_UNKNOWN; - } - - if (flags[port] & USB_MUX_FLAG_IN_LPM) { - CPRINTS("C%d: USB_MUX_FLAG_IN_LPM not cleared", port); - return EC_ERROR_NOT_POWERED; - } - - return EC_SUCCESS; -} - -void usb_mux_init(int port) -{ - int rv; - - ASSERT(port >= 0 && port < CONFIG_USB_PD_PORT_MAX_COUNT); - - if (port >= board_get_usb_pd_port_count()) { - return; - } - - rv = configure_mux(port, USB_MUX_INIT, NULL); - - if (rv == EC_SUCCESS) - atomic_or(&flags[port], USB_MUX_FLAG_INIT); - - /* - * Mux may fail initialization if it's not powered. Mark this port - * as in LPM mode to try initialization again. - */ - if (rv == EC_ERROR_NOT_POWERED) - atomic_or(&flags[port], USB_MUX_FLAG_IN_LPM); - else - atomic_clear_bits(&flags[port], USB_MUX_FLAG_IN_LPM); -} - -/* - * TODO(crbug.com/505480): Setting muxes often involves I2C transcations, - * which can block. Consider implementing an asynchronous task. - */ -void usb_mux_set(int port, mux_state_t mux_mode, - enum usb_switch usb_mode, int polarity) -{ - mux_state_t mux_state; - const int should_enter_low_power_mode = - (mux_mode == USB_PD_MUX_NONE && - usb_mode == USB_SWITCH_DISCONNECT); - - if (port >= board_get_usb_pd_port_count()) { - return; - } - - /* Perform initialization if not initialized yet */ - if (!(flags[port] & USB_MUX_FLAG_INIT)) - usb_mux_init(port); - - /* Configure USB2.0 */ - if (IS_ENABLED(CONFIG_USB_CHARGER)) - usb_charger_set_switches(port, usb_mode); - - /* - * Don't wake device up just to put it back to sleep. Low power mode - * flag is only set if the mux set() operation succeeded previously for - * the same disconnected state. - */ - if (should_enter_low_power_mode && (flags[port] & USB_MUX_FLAG_IN_LPM)) - return; - - if (exit_low_power_mode(port) != EC_SUCCESS) - return; - - /* Configure superspeed lanes */ - mux_state = ((mux_mode != USB_PD_MUX_NONE) && polarity) - ? mux_mode | USB_PD_MUX_POLARITY_INVERTED - : mux_mode; - - if (configure_mux(port, USB_MUX_SET_MODE, &mux_state)) - return; - - if (enable_debug_prints) - CPRINTS( - "usb/dp mux: port(%d) typec_mux(%d) usb2(%d) polarity(%d)", - port, mux_mode, usb_mode, polarity); - - /* - * If we are completely disconnecting the mux, then we should put it in - * its lowest power state. - */ - if (should_enter_low_power_mode) - enter_low_power_mode(port); -} - -mux_state_t usb_mux_get(int port) -{ - mux_state_t mux_state; - int rv; - - if (port >= board_get_usb_pd_port_count()) { - return USB_PD_MUX_NONE; - } - - /* Perform initialization if not initialized yet */ - if (!(flags[port] & USB_MUX_FLAG_INIT)) - usb_mux_init(port); - - if (flags[port] & USB_MUX_FLAG_IN_LPM) - return USB_PD_MUX_NONE; - - rv = configure_mux(port, USB_MUX_GET_MODE, &mux_state); - - return rv ? USB_PD_MUX_NONE : mux_state; -} - -void usb_mux_flip(int port) -{ - mux_state_t mux_state; - - if (port >= board_get_usb_pd_port_count()) { - return; - } - - /* Perform initialization if not initialized yet */ - if (!(flags[port] & USB_MUX_FLAG_INIT)) - usb_mux_init(port); - - if (exit_low_power_mode(port) != EC_SUCCESS) - return; - - if (configure_mux(port, USB_MUX_GET_MODE, &mux_state)) - return; - - if (mux_state & USB_PD_MUX_POLARITY_INVERTED) - mux_state &= ~USB_PD_MUX_POLARITY_INVERTED; - else - mux_state |= USB_PD_MUX_POLARITY_INVERTED; - - configure_mux(port, USB_MUX_SET_MODE, &mux_state); -} - -void usb_mux_hpd_update(int port, mux_state_t hpd_state) -{ - if (port >= board_get_usb_pd_port_count()) { - return; - } - - /* Perform initialization if not initialized yet */ - if (!(flags[port] & USB_MUX_FLAG_INIT)) - usb_mux_init(port); - - if (exit_low_power_mode(port) != EC_SUCCESS) - return; - - configure_mux(port, USB_MUX_HPD_UPDATE, &hpd_state); -} - -int usb_mux_retimer_fw_update_port_info(void) -{ - int i; - int port_info = 0; - const struct usb_mux *mux_ptr; - - for (i = 0; i < CONFIG_USB_PD_PORT_MAX_COUNT; i++) { - mux_ptr = &usb_muxes[i]; - while (mux_ptr) { - if (mux_ptr->driver && - mux_ptr->driver->is_retimer_fw_update_capable && - mux_ptr->driver->is_retimer_fw_update_capable()) - port_info |= BIT(i); - mux_ptr = mux_ptr->next_mux; - } - } - return port_info; -} - -static void mux_chipset_reset(void) -{ - int port; - - for (port = 0; port < board_get_usb_pd_port_count(); ++port) - configure_mux(port, USB_MUX_CHIPSET_RESET, NULL); -} -DECLARE_HOOK(HOOK_CHIPSET_RESET, mux_chipset_reset, HOOK_PRIO_DEFAULT); - -/* - * For muxes which have powered off in G3, clear any cached INIT and LPM flags - * since the chip will need reset. - */ -static void usb_mux_reset_in_g3(void) -{ - int port; - const struct usb_mux *mux_ptr; - - for (port = 0; port < board_get_usb_pd_port_count(); port++) { - mux_ptr = &usb_muxes[port]; - - while (mux_ptr) { - if (mux_ptr->flags & USB_MUX_FLAG_RESETS_IN_G3) { - atomic_clear_bits(&flags[port], - USB_MUX_FLAG_INIT | - USB_MUX_FLAG_IN_LPM); - } - mux_ptr = mux_ptr->next_mux; - } - } -} -DECLARE_HOOK(HOOK_CHIPSET_HARD_OFF, usb_mux_reset_in_g3, HOOK_PRIO_DEFAULT); - -#ifdef CONFIG_CMD_TYPEC -static int command_typec(int argc, char **argv) -{ - const char * const mux_name[] = {"none", "usb", "dp", "dock"}; - char *e; - int port; - mux_state_t mux = USB_PD_MUX_NONE; - int i; - - if (argc == 2 && !strcasecmp(argv[1], "debug")) { - enable_debug_prints = 1; - return EC_SUCCESS; - } - - if (argc < 2) - return EC_ERROR_PARAM_COUNT; - - port = strtoi(argv[1], &e, 10); - if (*e || port >= board_get_usb_pd_port_count()) - return EC_ERROR_PARAM1; - - if (argc < 3) { - mux_state_t mux_state; - - mux_state = usb_mux_get(port); - ccprintf("Port %d: USB=%d DP=%d POLARITY=%s HPD_IRQ=%d " - "HPD_LVL=%d SAFE=%d TBT=%d USB4=%d\n", port, - !!(mux_state & USB_PD_MUX_USB_ENABLED), - !!(mux_state & USB_PD_MUX_DP_ENABLED), - mux_state & USB_PD_MUX_POLARITY_INVERTED ? - "INVERTED" : "NORMAL", - !!(mux_state & USB_PD_MUX_HPD_IRQ), - !!(mux_state & USB_PD_MUX_HPD_LVL), - !!(mux_state & USB_PD_MUX_SAFE_MODE), - !!(mux_state & USB_PD_MUX_TBT_COMPAT_ENABLED), - !!(mux_state & USB_PD_MUX_USB4_ENABLED)); - - return EC_SUCCESS; - } - - for (i = 0; i < ARRAY_SIZE(mux_name); i++) - if (!strcasecmp(argv[2], mux_name[i])) - mux = i; - usb_mux_set(port, mux, mux == USB_PD_MUX_NONE ? - USB_SWITCH_DISCONNECT : - USB_SWITCH_CONNECT, - polarity_rm_dts(pd_get_polarity(port))); - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(typec, command_typec, - "[port|debug] [none|usb|dp|dock]", - "Control type-C connector muxing"); -#endif - -static enum ec_status hc_usb_pd_mux_info(struct host_cmd_handler_args *args) -{ - const struct ec_params_usb_pd_mux_info *p = args->params; - struct ec_response_usb_pd_mux_info *r = args->response; - int port = p->port; - mux_state_t mux_state; - - if (port >= board_get_usb_pd_port_count()) - return EC_RES_INVALID_PARAM; - - if (configure_mux(port, USB_MUX_GET_MODE, &mux_state)) - return EC_RES_ERROR; - - r->flags = mux_state; - - /* Clear HPD IRQ event since we're about to inform host of it. */ - if (IS_ENABLED(CONFIG_USB_MUX_VIRTUAL) && - (r->flags & USB_PD_MUX_HPD_IRQ)) { - usb_mux_hpd_update(port, r->flags & USB_PD_MUX_HPD_LVL); - } - - args->response_size = sizeof(*r); - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_USB_PD_MUX_INFO, - hc_usb_pd_mux_info, - EC_VER_MASK(0)); - -static enum ec_status hc_usb_pd_mux_ack(struct host_cmd_handler_args *args) -{ - __maybe_unused const struct ec_params_usb_pd_mux_ack *p = args->params; - - if (!IS_ENABLED(CONFIG_USB_MUX_AP_ACK_REQUEST)) - return EC_RES_INVALID_COMMAND; - - if (ack_task[p->port] != TASK_ID_INVALID) - task_set_event(ack_task[p->port], PD_EVENT_AP_MUX_DONE); - - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_USB_PD_MUX_ACK, - hc_usb_pd_mux_ack, - EC_VER_MASK(0)); diff --git a/driver/usb_mux/virtual.c b/driver/usb_mux/virtual.c deleted file mode 100644 index dbece4faf9..0000000000 --- a/driver/usb_mux/virtual.c +++ /dev/null @@ -1,125 +0,0 @@ -/* Copyright 2016 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. - * - * Virtual USB mux driver for host-controlled USB muxes. - */ - -#include "common.h" -#include "console.h" -#include "host_command.h" -#include "task.h" -#include "timer.h" -#include "usb_mux.h" -#include "util.h" - -/* - * USB PD protocol configures the USB & DP mux state and USB PD policy - * configures the HPD mux state. Both states are independent of each other - * may differ when the PD role changes when in dock mode. - */ -#define USB_PD_MUX_HPD_STATE (USB_PD_MUX_HPD_LVL | USB_PD_MUX_HPD_IRQ) -#define USB_PD_MUX_USB_DP_STATE (USB_PD_MUX_USB_ENABLED | \ - USB_PD_MUX_DP_ENABLED | USB_PD_MUX_POLARITY_INVERTED | \ - USB_PD_MUX_SAFE_MODE | USB_PD_MUX_TBT_COMPAT_ENABLED | \ - USB_PD_MUX_USB4_ENABLED) - -static mux_state_t virtual_mux_state[CONFIG_USB_PD_PORT_MAX_COUNT]; - -static inline void virtual_mux_update_state(int port, mux_state_t mux_state, - bool *ack_required) -{ - mux_state_t previous_mux_state = virtual_mux_state[port]; - - virtual_mux_state[port] = mux_state; - - /* - * Initialize ack_required to false to start, and set on necessary - * conditions - */ - *ack_required = false; - - if (!IS_ENABLED(CONFIG_HOSTCMD_EVENTS)) - return; - - host_set_single_event(EC_HOST_EVENT_USB_MUX); - - if (!IS_ENABLED(CONFIG_USB_MUX_AP_ACK_REQUEST)) - return; - - /* - * EC waits for the ACK from kernel indicating that TCSS Mux - * configuration is completed. This mechanism is implemented for - * entering, exiting the safe mode and entering the disconnect mode - * This is needed to remove timing senstivity between BB retimer and - * TCSS Mux to allow better synchronization between them and thereby - * remain in the same state for achieving proper safe state - * terminations. - */ - - /* TODO(b/186777984): Wait for an ACK for all mux state change */ - - if ((!(previous_mux_state & USB_PD_MUX_SAFE_MODE) && - (mux_state & USB_PD_MUX_SAFE_MODE)) || - ((previous_mux_state & USB_PD_MUX_SAFE_MODE) && - !(mux_state & USB_PD_MUX_SAFE_MODE)) || - ((previous_mux_state != USB_PD_MUX_NONE) && - (mux_state == USB_PD_MUX_NONE))) - *ack_required = true; -} - -static int virtual_init(const struct usb_mux *me) -{ - return EC_SUCCESS; -} - -/* - * Set the state of our 'virtual' mux. The EC does not actually control this - * mux, so update the desired state, then notify the host of the update. - */ -static int virtual_set_mux(const struct usb_mux *me, mux_state_t mux_state, - bool *ack_required) -{ - int port = me->usb_port; - - /* Current USB & DP mux status + existing HPD related mux status */ - mux_state_t new_mux_state = (mux_state & ~USB_PD_MUX_HPD_STATE) | - (virtual_mux_state[port] & USB_PD_MUX_HPD_STATE); - - virtual_mux_update_state(port, new_mux_state, ack_required); - - return EC_SUCCESS; -} - -/* - * Get the state of our 'virtual' mux. Since we the EC does not actually - * control this mux, and the EC has no way of knowing its actual status, - * we return the desired state here. - */ -static int virtual_get_mux(const struct usb_mux *me, mux_state_t *mux_state) -{ - int port = me->usb_port; - - *mux_state = virtual_mux_state[port]; - - return EC_SUCCESS; -} - -void virtual_hpd_update(const struct usb_mux *me, mux_state_t mux_state) -{ - int port = me->usb_port; - bool unused; - - /* Current HPD related mux status + existing USB & DP mux status */ - mux_state_t new_mux_state = mux_state | - (virtual_mux_state[port] & USB_PD_MUX_USB_DP_STATE); - - /* HPD ACK isn't required for the EC to continue with its tasks */ - virtual_mux_update_state(port, new_mux_state, &unused); -} - -const struct usb_mux_driver virtual_usb_mux_driver = { - .init = virtual_init, - .set = virtual_set_mux, - .get = virtual_get_mux, -}; diff --git a/driver/wpc/p9221.c b/driver/wpc/p9221.c deleted file mode 100644 index 973d991240..0000000000 --- a/driver/wpc/p9221.c +++ /dev/null @@ -1,808 +0,0 @@ -/* Copyright 2019 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. - */ - -/* - * IDT P9221-R7 Wireless Power Receiver driver. - */ - -#include "p9221.h" -#include "charge_manager.h" -#include "chipset.h" -#include "common.h" -#include "console.h" -#include "gpio.h" -#include "hooks.h" -#include "power.h" -#include "tcpm/tcpm.h" -#include "timer.h" -#include "usb_charge.h" -#include "usb_pd.h" -#include "util.h" -#include <stdbool.h> -#include "printf.h" - -#define CPRINTS(format, args...) cprints(CC_USBPD, "WPC " format, ## args) - -#define P9221_TX_TIMEOUT_MS (20 * 1000*1000) -#define P9221_DCIN_TIMEOUT_MS (2 * 1000*1000) -#define P9221_VRECT_TIMEOUT_MS (2 * 1000*1000) -#define P9221_NOTIFIER_DELAY_MS (80*1000) -#define P9221R7_ILIM_MAX_UA (1600 * 1000) -#define P9221R7_OVER_CHECK_NUM 3 - -#define OVC_LIMIT 1 -#define OVC_THRESHOLD 1400000 -#define OVC_BACKOFF_LIMIT 900000 -#define OVC_BACKOFF_AMOUNT 100000 - -/* P9221 parameters */ -static struct wpc_charger_info p9221_charger_info = { - .online = false, - .i2c_port = I2C_PORT_WPC, - .pp_buf_valid = false, -}; - -static struct wpc_charger_info *wpc = &p9221_charger_info; - -static void p9221_set_offline(void); - -static const uint32_t p9221_ov_set_lut[] = { - 17000000, 20000000, 15000000, 13000000, - 11000000, 11000000, 11000000, 11000000 -}; - -static int p9221_reg_is_8_bit(uint16_t reg) -{ - switch (reg) { - case P9221_CHIP_REVISION_REG: - case P9221R7_VOUT_SET_REG: - case P9221R7_ILIM_SET_REG: - case P9221R7_CHARGE_STAT_REG: - case P9221R7_EPT_REG: - case P9221R7_SYSTEM_MODE_REG: - case P9221R7_COM_CHAN_RESET_REG: - case P9221R7_COM_CHAN_SEND_SIZE_REG: - case P9221R7_COM_CHAN_SEND_IDX_REG: - case P9221R7_COM_CHAN_RECV_SIZE_REG: - case P9221R7_COM_CHAN_RECV_IDX_REG: - case P9221R7_DEBUG_REG: - case P9221R7_EPP_Q_FACTOR_REG: - case P9221R7_EPP_TX_GUARANTEED_POWER_REG: - case P9221R7_EPP_TX_POTENTIAL_POWER_REG: - case P9221R7_EPP_TX_CAPABILITY_FLAGS_REG: - case P9221R7_EPP_RENEGOTIATION_REG: - case P9221R7_EPP_CUR_RPP_HEADER_REG: - case P9221R7_EPP_CUR_NEGOTIATED_POWER_REG: - case P9221R7_EPP_CUR_MAXIMUM_POWER_REG: - case P9221R7_EPP_CUR_FSK_MODULATION_REG: - case P9221R7_EPP_REQ_RPP_HEADER_REG: - case P9221R7_EPP_REQ_NEGOTIATED_POWER_REG: - case P9221R7_EPP_REQ_MAXIMUM_POWER_REG: - case P9221R7_EPP_REQ_FSK_MODULATION_REG: - case P9221R7_VRECT_TARGET_REG: - case P9221R7_VRECT_KNEE_REG: - case P9221R7_FOD_SECTION_REG: - case P9221R7_VRECT_ADJ_REG: - case P9221R7_ALIGN_X_ADC_REG: - case P9221R7_ALIGN_Y_ADC_REG: - case P9221R7_ASK_MODULATION_DEPTH_REG: - case P9221R7_OVSET_REG: - case P9221R7_EPP_TX_SPEC_REV_REG: - return true; - default: - return false; - } -} - -static int p9221_read8(uint16_t reg, int *val) -{ - return i2c_read_offset16(wpc->i2c_port, P9221_R7_ADDR_FLAGS, - reg, val, 1); -} - -static int p9221_write8(uint16_t reg, int val) -{ - return i2c_write_offset16(wpc->i2c_port, P9221_R7_ADDR_FLAGS, - reg, val, 1); -} - -static int p9221_read16(uint16_t reg, int *val) -{ - return i2c_read_offset16(wpc->i2c_port, P9221_R7_ADDR_FLAGS, - reg, val, 2); -} - -static int p9221_write16(uint16_t reg, int val) -{ - return i2c_write_offset16(wpc->i2c_port, P9221_R7_ADDR_FLAGS, - reg, val, 2); -} - -static int p9221_block_read(uint16_t reg, uint8_t *data, int len) -{ - return i2c_read_offset16_block(wpc->i2c_port, P9221_R7_ADDR_FLAGS, - reg, data, len); -} - -static int p9221_block_write(uint16_t reg, uint8_t *data, int len) -{ - return i2c_write_offset16_block(wpc->i2c_port, P9221_R7_ADDR_FLAGS, - reg, data, len); -} - -static int p9221_set_cmd_reg(uint8_t cmd) -{ - int cur_cmd; - int retry; - int ret; - - for (retry = 0; retry < P9221_COM_CHAN_RETRIES; retry++) { - ret = p9221_read8(P9221_COM_REG, &cur_cmd); - if (ret == EC_SUCCESS && cur_cmd == 0) - break; - msleep(25); - } - - if (retry >= P9221_COM_CHAN_RETRIES) { - CPRINTS("Failed to wait for cmd free %02x", cur_cmd); - return EC_ERROR_TIMEOUT; - } - - ret = p9221_write8(P9221_COM_REG, cmd); - if (ret) - CPRINTS("Failed to set cmd reg %02x: %d", cmd, ret); - - return ret; -} - -/* Convert a register value to uV, Hz, or uA */ -static int p9221_convert_reg_r7(uint16_t reg, uint16_t raw_data, uint32_t *val) -{ - switch (reg) { - case P9221R7_ALIGN_X_ADC_REG: /* raw */ - case P9221R7_ALIGN_Y_ADC_REG: /* raw */ - *val = raw_data; - break; - case P9221R7_VOUT_ADC_REG: /* 12-bit ADC raw */ - case P9221R7_IOUT_ADC_REG: /* 12-bit ADC raw */ - case P9221R7_DIE_TEMP_ADC_REG: /* 12-bit ADC raw */ - case P9221R7_EXT_TEMP_REG: - *val = raw_data & 0xFFF; - break; - case P9221R7_VOUT_SET_REG: /* 0.1V -> uV */ - *val = raw_data * 100 * 1000; - break; - case P9221R7_IOUT_REG: /* mA -> uA */ - case P9221R7_VRECT_REG: /* mV -> uV */ - case P9221R7_VOUT_REG: /* mV -> uV */ - case P9221R7_OP_FREQ_REG: /* kHz -> Hz */ - case P9221R7_TX_PINGFREQ_REG: /* kHz -> Hz */ - *val = raw_data * 1000; - break; - case P9221R7_ILIM_SET_REG: /* 100mA -> uA, 200mA offset */ - *val = ((raw_data * 100) + 200) * 1000; - break; - case P9221R7_OVSET_REG: /* uV */ - raw_data &= P9221R7_OVSET_MASK; - *val = p9221_ov_set_lut[raw_data]; - break; - default: - return -2; - } - - return 0; -} - -static int p9221_reg_read_converted(uint16_t reg, uint32_t *val) -{ - int ret; - int data; - - if (p9221_reg_is_8_bit(reg)) - ret = p9221_read8(reg, &data); - else - ret = p9221_read16(reg, &data); - - if (ret) - return ret; - - return p9221_convert_reg_r7(reg, data, val); -} - -static int p9221_is_online(void) -{ - int chip_id; - - if (p9221_read16(P9221_CHIP_ID_REG, &chip_id) - || chip_id != P9221_CHIP_ID) - return false; - else - return true; -} - -int wpc_chip_is_online(void) -{ - return p9221_is_online(); -} - - -void p9221_interrupt(enum gpio_signal signal) -{ - task_wake(TASK_ID_WPC); -} - -static int p9221r7_clear_interrupts(uint16_t mask) -{ - int ret; - - ret = p9221_write16(P9221R7_INT_CLEAR_REG, mask); - if (ret) { - CPRINTS("Failed to clear INT reg: %d", ret); - return ret; - } - - ret = p9221_set_cmd_reg(P9221_COM_CLEAR_INT_MASK); - if (ret) - CPRINTS("Failed to reset INT: %d", ret); - - return ret; -} - -/* - * Enable interrupts on the P9221 R7, note we don't really need to disable - * interrupts since when the device goes out of field, the P9221 is reset. - */ -static int p9221_enable_interrupts_r7(void) -{ - uint16_t mask = 0; - int ret; - - CPRINTS("Enable interrupts"); - - mask = P9221R7_STAT_LIMIT_MASK | P9221R7_STAT_CC_MASK - | P9221_STAT_VRECT; - - p9221r7_clear_interrupts(mask); - - ret = p9221_write8(P9221_INT_ENABLE_REG, mask); - if (ret) - CPRINTS("Failed to enable INTs: %d", ret); - return ret; -} - -static int p9221_send_csp(uint8_t status) -{ - int ret; - - CPRINTS("Send CSP=%d", status); - mutex_lock(&wpc->cmd_lock); - - ret = p9221_write8(P9221R7_CHARGE_STAT_REG, status); - if (ret == EC_SUCCESS) - ret = p9221_set_cmd_reg(P9221R7_COM_SENDCSP); - - mutex_unlock(&wpc->cmd_lock); - return ret; -} - -static int p9221_send_eop(uint8_t reason) -{ - int rv; - - CPRINTS("Send EOP reason=%d", reason); - mutex_lock(&wpc->cmd_lock); - - rv = p9221_write8(P9221R7_EPT_REG, reason); - if (rv == EC_SUCCESS) - rv = p9221_set_cmd_reg(P9221R7_COM_SENDEPT); - - mutex_unlock(&wpc->cmd_lock); - return rv; -} - -static void print_current_samples(uint32_t *iout_val, int count) -{ - int i; - char temp[P9221R7_OVER_CHECK_NUM * 9 + 1] = { 0 }; - - for (i = 0; i < count ; i++) - snprintf(temp + i * 9, sizeof(temp) - i * 9, - "%08x ", iout_val[i]); - CPRINTS("OVER IOUT_SAMPLES: %s", temp); -} - - -/* - * Number of times to poll the status to see if the current limit condition - * was transient or not. - */ -static void p9221_limit_handler_r7(uint16_t orign_irq_src) -{ - uint8_t reason; - int i; - int ret; - int ovc_count = 0; - uint32_t iout_val[P9221R7_OVER_CHECK_NUM] = { 0 }; - int irq_src = (int)orign_irq_src; - - CPRINTS("OVER INT: %02x", irq_src); - - if (irq_src & P9221R7_STAT_OVV) { - reason = P9221_EOP_OVER_VOLT; - goto send_eop; - } - - if (irq_src & P9221R7_STAT_OVT) { - reason = P9221_EOP_OVER_TEMP; - goto send_eop; - } - - if ((irq_src & P9221R7_STAT_UV) && !(irq_src & P9221R7_STAT_OVC)) - return; - - reason = P9221_EOP_OVER_CURRENT; - for (i = 0; i < P9221R7_OVER_CHECK_NUM; i++) { - ret = p9221r7_clear_interrupts( - irq_src & P9221R7_STAT_LIMIT_MASK); - msleep(50); - if (ret) - continue; - - ret = p9221_reg_read_converted(P9221R7_IOUT_REG, &iout_val[i]); - if (ret) { - CPRINTS("Failed to read IOUT[%d]: %d", i, ret); - continue; - } else if (iout_val[i] > OVC_THRESHOLD) { - ovc_count++; - } - - ret = p9221_read16(P9221_STATUS_REG, &irq_src); - if (ret) { - CPRINTS("Failed to read status: %d", ret); - continue; - } - - if ((irq_src & P9221R7_STAT_OVC) == 0) { - print_current_samples(iout_val, i + 1); - CPRINTS("OVER condition %04x cleared after %d tries", - irq_src, i); - return; - } - - CPRINTS("OVER status is still %04x, retry", irq_src); - } - - if (ovc_count < OVC_LIMIT) { - print_current_samples(iout_val, P9221R7_OVER_CHECK_NUM); - CPRINTS("ovc_threshold=%d, ovc_count=%d, ovc_limit=%d", - OVC_THRESHOLD, ovc_count, OVC_LIMIT); - return; - } - -send_eop: - CPRINTS("OVER is %04x, sending EOP %d", irq_src, reason); - - ret = p9221_send_eop(reason); - if (ret) - CPRINTS("Failed to send EOP %d: %d", reason, ret); -} - -static void p9221_abort_transfers(void) -{ - wpc->tx_busy = false; - wpc->tx_done = true; - wpc->rx_done = true; - wpc->rx_len = 0; -} - -/* Handler for r7 and R7 chips */ -static void p9221r7_irq_handler(uint16_t irq_src) -{ - int res; - - if (irq_src & P9221R7_STAT_LIMIT_MASK) - p9221_limit_handler_r7(irq_src); - - /* Receive complete */ - if (irq_src & P9221R7_STAT_CCDATARCVD) { - int rxlen = 0; - - res = p9221_read8(P9221R7_COM_CHAN_RECV_SIZE_REG, &rxlen); - if (res) - CPRINTS("Failed to read len: %d", res); - - if (rxlen) { - res = p9221_block_read(P9221R7_DATA_RECV_BUF_START, - wpc->rx_buf, rxlen); - if (res) { - CPRINTS("Failed to read CC data: %d", res); - rxlen = 0; - } - - wpc->rx_len = rxlen; - wpc->rx_done = true; - } - } - - /* Send complete */ - if (irq_src & P9221R7_STAT_CCSENDBUSY) { - wpc->tx_busy = false; - wpc->tx_done = true; - } - - /* Proprietary packet */ - if (irq_src & P9221R7_STAT_PPRCVD) { - res = p9221_block_read(P9221R7_DATA_RECV_BUF_START, - wpc->pp_buf, sizeof(wpc->pp_buf)); - if (res) { - CPRINTS("Failed to read PP: %d", res); - wpc->pp_buf_valid = false; - return; - } - - /* We only care about PP which come with 0x4F header */ - wpc->pp_buf_valid = (wpc->pp_buf[0] == 0x4F); - - hexdump(wpc->pp_buf, sizeof(wpc->pp_buf)); - } - - /* CC Reset complete */ - if (irq_src & P9221R7_STAT_CCRESET) - p9221_abort_transfers(); -} - -static int p9221_is_epp(void) -{ - int ret, reg; - uint32_t vout_uv; - - if (p9221_read8(P9221R7_SYSTEM_MODE_REG, ®) == EC_SUCCESS) - return reg & P9221R7_SYSTEM_MODE_EXTENDED_MASK; - - /* Check based on power supply voltage */ - ret = p9221_reg_read_converted(P9221R7_VOUT_ADC_REG, &vout_uv); - if (ret) { - CPRINTS("Failed to read VOUT_ADC: %d", ret); - return false; - } - - CPRINTS("Voltage is %duV", vout_uv); - if (vout_uv > P9221_EPP_THRESHOLD_UV) - return true; - - return false; -} - -static void p9221_config_fod(void) -{ - - int epp; - uint8_t *fod; - int fod_len; - int ret; - int retries = 3; - - CPRINTS("Config FOD"); - - epp = p9221_is_epp(); - fod_len = epp ? board_get_epp_fod(&fod) : board_get_fod(&fod); - if (!fod_len || !fod) { - CPRINTS("FOD data not found"); - return; - } - - while (retries) { - uint8_t fod_read[fod_len]; - - CPRINTS("Writing %s FOD (n=%d try=%d)", - epp ? "EPP" : "BPP", fod_len, retries); - - ret = p9221_block_write(P9221R7_FOD_REG, fod, fod_len); - if (ret) - goto no_fod; - - /* Verify the FOD has been written properly */ - ret = p9221_block_read(P9221R7_FOD_REG, fod_read, fod_len); - if (ret) - goto no_fod; - - if (memcmp(fod, fod_read, fod_len) == 0) - return; - - hexdump(fod_read, fod_len); - - retries--; - msleep(100); - } - -no_fod: - CPRINTS("Failed to set FOD. retries:%d ret:%d", retries, ret); -} - -static void p9221_set_online(void) -{ - int ret; - - CPRINTS("Set online"); - - wpc->online = true; - - wpc->tx_busy = false; - wpc->tx_done = true; - wpc->rx_done = false; - wpc->charge_supplier = CHARGE_SUPPLIER_WPC_BPP; - - ret = p9221_enable_interrupts_r7(); - if (ret) - CPRINTS("Failed to enable INT: %d", ret); - - /* NOTE: depends on _is_epp() which is not valid until DC_IN */ - p9221_config_fod(); -} - -static void p9221_vbus_check_timeout(void) -{ - CPRINTS("Timeout VBUS, online=%d", wpc->online); - if (wpc->online) - p9221_set_offline(); - -} -DECLARE_DEFERRED(p9221_vbus_check_timeout); - -static void p9221_set_offline(void) -{ - CPRINTS("Set offline"); - - wpc->online = false; - /* Reset PP buf so we can get a new serial number next time around */ - wpc->pp_buf_valid = false; - - p9221_abort_transfers(); - - hook_call_deferred(&p9221_vbus_check_timeout_data, -1); -} - -/* P9221_NOTIFIER_DELAY_MS from VRECTON */ -static int p9221_notifier_check_det(void) -{ - if (wpc->online) - goto done; - - /* send out a FOD but is_epp() is still invalid */ - p9221_set_online(); - - /* Give the vbus 2 seconds to come up. */ - CPRINTS("Waiting VBUS"); - hook_call_deferred(&p9221_vbus_check_timeout_data, -1); - hook_call_deferred(&p9221_vbus_check_timeout_data, - P9221_DCIN_TIMEOUT_MS); - -done: - wpc->p9221_check_det = false; - return 0; -} - -static int p9221_get_charge_supplier(void) -{ - if (!wpc->online) - return EC_ERROR_UNKNOWN; - - if (p9221_is_epp()) { - uint32_t tx_id; - int txmf_id; - int ret; - - wpc->charge_supplier = CHARGE_SUPPLIER_WPC_EPP; - - ret = p9221_read16(P9221R7_EPP_TX_MFG_CODE_REG, &txmf_id); - if (ret || txmf_id != P9221_GPP_TX_MF_ID) - return ret; - - ret = p9221_block_read(P9221R7_PROP_TX_ID_REG, - (uint8_t *) &tx_id, - P9221R7_PROP_TX_ID_SIZE); - if (ret) - return ret; - - if (tx_id & P9221R7_PROP_TX_ID_GPP_MASK) - wpc->charge_supplier = CHARGE_SUPPLIER_WPC_GPP; - - CPRINTS("txmf_id=0x%04x tx_id=0x%08x supplier=%d", - txmf_id, tx_id, wpc->charge_supplier); - } else { - wpc->charge_supplier = CHARGE_SUPPLIER_WPC_BPP; - CPRINTS("supplier=%d", wpc->charge_supplier); - } - - return EC_SUCCESS; -} - -static int p9221_get_icl(int charge_supplier) -{ - switch (charge_supplier) { - case CHARGE_SUPPLIER_WPC_EPP: - case CHARGE_SUPPLIER_WPC_GPP: - return P9221_DC_ICL_EPP_MA; - case CHARGE_SUPPLIER_WPC_BPP: - default: - return P9221_DC_ICL_BPP_MA; - } -} - -static int p9221_get_ivl(int charge_supplier) -{ - switch (charge_supplier) { - case CHARGE_SUPPLIER_WPC_EPP: - case CHARGE_SUPPLIER_WPC_GPP: - return P9221_DC_IVL_EPP_MV; - case CHARGE_SUPPLIER_WPC_BPP: - default: - return P9221_DC_IVL_BPP_MV; - } -} - -static void p9221_update_charger(int type, struct charge_port_info *chg) -{ - if (!chg) - charge_manager_update_dualrole(0, CAP_UNKNOWN); - else - charge_manager_update_dualrole(0, CAP_DEDICATED); - - charge_manager_update_charge(type, 0, chg); -} - -static int p9221_reg_write_converted_r7(uint16_t reg, uint32_t val) -{ - int ret = 0; - uint16_t data; - int i; - /* Do the appropriate conversion */ - switch (reg) { - case P9221R7_ILIM_SET_REG: - /* uA -> 0.1A, offset 0.2A */ - if ((val < 200000) || (val > 1600000)) - return -EC_ERROR_INVAL; - data = (val / (100 * 1000)) - 2; - break; - case P9221R7_VOUT_SET_REG: - /* uV -> 0.1V */ - val /= 1000; - if (val < 3500 || val > 9000) - return -EC_ERROR_INVAL; - data = val / 100; - break; - case P9221R7_OVSET_REG: - /* uV */ - for (i = 0; i < ARRAY_SIZE(p9221_ov_set_lut); i++) { - if (val == p9221_ov_set_lut[i]) - break; - } - if (i == ARRAY_SIZE(p9221_ov_set_lut)) - return -EC_ERROR_INVAL; - data = i; - break; - default: - return -EC_ERROR_INVAL; - } - if (p9221_reg_is_8_bit(reg)) - ret = p9221_write8(reg, data); - else - ret = p9221_write16(reg, data); - return ret; -} - -static int p9221_set_dc_icl(void) -{ - /* Increase the IOUT limit */ - if (p9221_reg_write_converted_r7(P9221R7_ILIM_SET_REG, - P9221R7_ILIM_MAX_UA)) - CPRINTS("%s set rx_iout limit fail.", __func__); - - return EC_SUCCESS; -} - - -static void p9221_notifier_check_vbus(void) -{ - struct charge_port_info chg; - - wpc->p9221_check_vbus = false; - - CPRINTS("%s online:%d vbus:%d", __func__, wpc->online, - wpc->vbus_status); - - /* - * We now have confirmation from DC_IN, kill the timer, p9221_online - * will be set by this function. - */ - hook_call_deferred(&p9221_vbus_check_timeout_data, -1); - - if (wpc->vbus_status) { - /* WPC VBUS on ,Always write FOD, check dc_icl, send CSP */ - p9221_set_dc_icl(); - p9221_config_fod(); - - p9221_send_csp(1); - - /* when wpc vbus attached after 2s, set wpc online */ - if (!wpc->online) - p9221_set_online(); - - /* WPC VBUS on , update charge voltage and current */ - p9221_get_charge_supplier(); - chg.voltage = p9221_get_ivl(wpc->charge_supplier); - chg.current = p9221_get_icl(wpc->charge_supplier); - - p9221_update_charger(wpc->charge_supplier, &chg); - } else { - /* - * Vbus detached, set wpc offline and update wpc charge voltage - * and current to zero. - */ - if (wpc->online) { - p9221_set_offline(); - p9221_update_charger(wpc->charge_supplier, NULL); - } - } - - CPRINTS("check_vbus changed on:%d vbus:%d", wpc->online, - wpc->vbus_status); - -} - -static void p9221_detect_work(void) -{ - - CPRINTS("%s online:%d check_vbus:%d check_det:%d vbus:%d", __func__, - wpc->online, wpc->p9221_check_vbus, wpc->p9221_check_det, - wpc->vbus_status); - - /* Step 1 */ - if (wpc->p9221_check_det) - p9221_notifier_check_det(); - - /* Step 2 */ - if (wpc->p9221_check_vbus) - p9221_notifier_check_vbus(); - -} -DECLARE_DEFERRED(p9221_detect_work); - -void p9221_notify_vbus_change(int vbus) -{ - wpc->p9221_check_vbus = true; - wpc->vbus_status = vbus; - hook_call_deferred(&p9221_detect_work_data, P9221_NOTIFIER_DELAY_MS); -} - -void wireless_power_charger_task(void *u) -{ - while (1) { - int ret, irq_src; - task_wait_event(-1); - - ret = p9221_read16(P9221_INT_REG, &irq_src); - if (ret) { - CPRINTS("Failed to read INT REG"); - continue; - } - - CPRINTS("INT SRC 0x%04x", irq_src); - - if (p9221r7_clear_interrupts(irq_src)) - continue; - - if (irq_src & P9221_STAT_VRECT) { - CPRINTS("VRECTON, online=%d", wpc->online); - if (!wpc->online) { - wpc->p9221_check_det = true; - hook_call_deferred(&p9221_detect_work_data, - P9221_NOTIFIER_DELAY_MS); - } - } - - p9221r7_irq_handler(irq_src); - } -} diff --git a/driver/wpc/p9221.h b/driver/wpc/p9221.h deleted file mode 100644 index 0bb0571b38..0000000000 --- a/driver/wpc/p9221.h +++ /dev/null @@ -1,323 +0,0 @@ -/* Copyright 2018 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. - */ - - -/* - * IDT P9221-R7 Wireless Power Receiver driver definitions. - */ - -#ifndef __P9221_R7_H -#define __P9221_R7_H - -#include "common.h" -#include "gpio.h" -#include "charge_manager.h" -#include "task.h" - - -/* ========== Variant-specific configuration ============ */ - -#define P9221_R7_ADDR_FLAGS 0x61 - -/* - * P9221 common registers - */ -#define P9221_CHIP_ID_REG 0x00 -#define P9221_CHIP_ID 0x9220 -#define P9221_CHIP_REVISION_REG 0x02 -#define P9221_CUSTOMER_ID_REG 0x03 -#define P9221R7_CUSTOMER_ID_VAL 0x05 -#define P9221_OTP_FW_MAJOR_REV_REG 0x04 -#define P9221_OTP_FW_MINOR_REV_REG 0x06 -#define P9221_OTP_FW_DATE_REG 0x08 -#define P9221_OTP_FW_DATE_SIZE 12 -#define P9221_OTP_FW_TIME_REG 0x14 -#define P9221_OTP_FW_TIME_SIZE 8 -#define P9221_SRAM_FW_MAJOR_REV_REG 0x1C -#define P9221_SRAM_FW_MINOR_REV_REG 0x1E -#define P9221_SRAM_FW_DATE_REG 0x20 -#define P9221_SRAM_FW_DATE_SIZE 12 -#define P9221_SRAM_FW_TIME_REG 0x2C -#define P9221_SRAM_FW_TIME_SIZE 8 -#define P9221_STATUS_REG 0x34 -#define P9221_INT_REG 0x36 -#define P9221_INT_MASK 0xF7 -#define P9221_INT_ENABLE_REG 0x38 -#define P9221_GPP_TX_MF_ID 0x0072 - -/* - * P9221 Rx registers (x != 5) - */ -#define P9221_CHARGE_STAT_REG 0x3A -#define P9221_EPT_REG 0x3B -#define P9221_VOUT_ADC_REG 0x3C -#define P9221_VOUT_ADC_MASK 0x0FFF -#define P9221_VOUT_SET_REG 0x3E -#define P9221_MAX_VOUT_SET_MV_DEFAULT 9000 -#define P9221_VRECT_ADC_REG 0x40 -#define P9221_VRECT_ADC_MASK 0x0FFF -#define P9221_OVSET_REG 0x42 -#define P9221_OVSET_MASK 0x70 -#define P9221_OVSET_SHIFT 4 -#define P9221_RX_IOUT_REG 0x44 -#define P9221_DIE_TEMP_ADC_REG 0x46 -#define P9221_DIE_TEMP_ADC_MASK 0x0FFF -#define P9221_OP_FREQ_REG 0x48 -#define P9221_ILIM_SET_REG 0x4A -#define P9221_ALIGN_X_ADC_REG 0x4B -#define P9221_ALIGN_Y_ADC_REG 0x4C -#define P9221_OP_MODE_REG 0x4D -#define P9221_COM_REG 0x4E -#define P9221_FW_SWITCH_KEY_REG 0x4F -#define P9221_INT_CLEAR_REG 0x56 -#define P9221_RXID_REG 0x5C -#define P9221_RXID_LEN 6 -#define P9221_MPREQ_REG 0x5C -#define P9221_MPREQ_LEN 6 -#define P9221_FOD_REG 0x68 -#define P9221_NUM_FOD 16 -#define P9221_RX_RAWIOUT_REG 0x7A -#define P9221_RX_RAWIOUT_MASK 0xFFF -#define P9221_PMA_AD_REG 0x7C -#define P9221_RX_PINGFREQ_REG 0xFC -#define P9221_RX_PINGFREQ_MASK 0xFFF -#define P9221_LAST_REG 0xFF - -/* - * P9221R7 unique registers - */ -#define P9221R7_INT_CLEAR_REG 0x3A -#define P9221R7_VOUT_SET_REG 0x3C -#define P9221R7_ILIM_SET_REG 0x3D -#define P9221R7_ILIM_SET_MAX 0x0E /* 0x0E = 1.6A */ -#define P9221R7_CHARGE_STAT_REG 0x3E -#define P9221R7_EPT_REG 0x3F -#define P9221R7_VRECT_REG 0x40 -#define P9221R7_VOUT_REG 0x42 -#define P9221R7_IOUT_REG 0x44 -#define P9221R7_OP_FREQ_REG 0x48 -#define P9221R7_SYSTEM_MODE_REG 0x4C -#define P9221R7_COM_CHAN_RESET_REG 0x50 -#define P9221R7_COM_CHAN_SEND_SIZE_REG 0x58 -#define P9221R7_COM_CHAN_SEND_IDX_REG 0x59 -#define P9221R7_COM_CHAN_RECV_SIZE_REG 0x5A -#define P9221R7_COM_CHAN_RECV_IDX_REG 0x5B -#define P9221R7_VRECT_ADC_REG 0x60 -#define P9221R7_VOUT_ADC_REG 0x62 -#define P9221R7_VOUT_ADC_MASK 0xFFF -#define P9221R7_IOUT_ADC_REG 0x64 -#define P9221R7_IOUT_ADC_MASK 0xFFF -#define P9221R7_DIE_TEMP_ADC_REG 0x66 -#define P9221R7_DIE_TEMP_ADC_MASK 0xFFF -#define P9221R7_AC_PERIOD_REG 0x68 -#define P9221R7_TX_PINGFREQ_REG 0x6A -#define P9221R7_EXT_TEMP_REG 0x6C -#define P9221R7_EXT_TEMP_MASK 0xFFF -#define P9221R7_FOD_REG 0x70 -#define P9221R7_NUM_FOD 16 -#define P9221R7_DEBUG_REG 0x80 -#define P9221R7_EPP_Q_FACTOR_REG 0x83 -#define P9221R7_EPP_TX_GUARANTEED_POWER_REG 0x84 -#define P9221R7_EPP_TX_POTENTIAL_POWER_REG 0x85 -#define P9221R7_EPP_TX_CAPABILITY_FLAGS_REG 0x86 -#define P9221R7_EPP_RENEGOTIATION_REG 0x87 -#define P9221R7_EPP_CUR_RPP_HEADER_REG 0x88 -#define P9221R7_EPP_CUR_NEGOTIATED_POWER_REG 0x89 -#define P9221R7_EPP_CUR_MAXIMUM_POWER_REG 0x8A -#define P9221R7_EPP_CUR_FSK_MODULATION_REG 0x8B -#define P9221R7_EPP_REQ_RPP_HEADER_REG 0x8C -#define P9221R7_EPP_REQ_NEGOTIATED_POWER_REG 0x8D -#define P9221R7_EPP_REQ_MAXIMUM_POWER_REG 0x8E -#define P9221R7_EPP_REQ_FSK_MODULATION_REG 0x8F -#define P9221R7_VRECT_TARGET_REG 0x90 -#define P9221R7_VRECT_KNEE_REG 0x92 -#define P9221R7_VRECT_CORRECTION_FACTOR_REG 0x93 -#define P9221R7_VRECT_MAX_CORRECTION_FACTOR_REG 0x94 -#define P9221R7_VRECT_MIN_CORRECTION_FACTOR_REG 0x96 -#define P9221R7_FOD_SECTION_REG 0x99 -#define P9221R7_VRECT_ADJ_REG 0x9E -#define P9221R7_ALIGN_X_ADC_REG 0xA0 -#define P9221R7_ALIGN_Y_ADC_REG 0xA1 -#define P9221R7_ASK_MODULATION_DEPTH_REG 0xA2 -#define P9221R7_OVSET_REG 0xA3 -#define P9221R7_OVSET_MASK 0x7 -#define P9221R7_EPP_TX_SPEC_REV_REG 0xA9 -#define P9221R7_EPP_TX_MFG_CODE_REG 0xAA -#define P9221R7_GP0_RESET_VOLT_REG 0xAC -#define P9221R7_GP1_RESET_VOLT_REG 0xAE -#define P9221R7_GP2_RESET_VOLT_REG 0xB0 -#define P9221R7_GP3_RESET_VOLT_REG 0xB2 -#define P9221R7_PROP_TX_ID_REG 0xB4 -#define P9221R7_PROP_TX_ID_SIZE 4 -#define P9221R7_DATA_SEND_BUF_START 0x100 -#define P9221R7_DATA_SEND_BUF_SIZE 0x80 -#define P9221R7_DATA_RECV_BUF_START 0x180 -#define P9221R7_DATA_RECV_BUF_SIZE 0x80 -#define P9221R7_MAX_PP_BUF_SIZE 16 -#define P9221R7_LAST_REG 0x1FF - -/* - * System Mode Mask (r7+/0x4C) - */ -#define P9221R7_SYSTEM_MODE_EXTENDED_MASK (1 << 3) - -/* - * TX ID GPP Mask (r7+/0xB4->0xB7) - */ -#define P9221R7_PROP_TX_ID_GPP_MASK (1 << 29) - -/* - * Com Channel Commands - */ -#define P9221R7_COM_CHAN_CCRESET BIT(7) -#define P9221_COM_CHAN_RETRIES 5 - -/* - * End of Power packet types - */ -#define P9221_EOP_UNKNOWN 0x00 -#define P9221_EOP_EOC 0x01 -#define P9221_EOP_INTERNAL_FAULT 0x02 -#define P9221_EOP_OVER_TEMP 0x03 -#define P9221_EOP_OVER_VOLT 0x04 -#define P9221_EOP_OVER_CURRENT 0x05 -#define P9221_EOP_BATT_FAIL 0x06 -#define P9221_EOP_RECONFIG 0x07 -#define P9221_EOP_NO_RESPONSE 0x08 -#define P9221_EOP_NEGOTIATION_FAIL 0x0A -#define P9221_EOP_RESTART_POWER 0x0B - -/* - * Command flags - */ -#define P9221R7_COM_RENEGOTIATE P9221_COM_RENEGOTIATE -#define P9221R7_COM_SWITCH2RAM P9221_COM_SWITCH_TO_RAM_MASK -#define P9221R7_COM_CLRINT P9221_COM_CLEAR_INT_MASK -#define P9221R7_COM_SENDCSP P9221_COM_SEND_CHG_STAT_MASK -#define P9221R7_COM_SENDEPT P9221_COM_SEND_EOP_MASK -#define P9221R7_COM_LDOTGL P9221_COM_LDO_TOGGLE -#define P9221R7_COM_CCACTIVATE BIT(0) - -#define P9221_COM_RENEGOTIATE BIT(7) -#define P9221_COM_SWITCH_TO_RAM_MASK BIT(6) -#define P9221_COM_CLEAR_INT_MASK BIT(5) -#define P9221_COM_SEND_CHG_STAT_MASK BIT(4) -#define P9221_COM_SEND_EOP_MASK BIT(3) -#define P9221_COM_LDO_TOGGLE BIT(1) - -/* - * Interrupt/Status flags for P9221 - */ -#define P9221_STAT_VOUT BIT(7) -#define P9221_STAT_VRECT BIT(6) -#define P9221_STAT_ACMISSING BIT(5) -#define P9221_STAT_OV_TEMP BIT(2) -#define P9221_STAT_OV_VOLT BIT(1) -#define P9221_STAT_OV_CURRENT BIT(0) -#define P9221_STAT_LIMIT_MASK (P9221_STAT_OV_TEMP | \ - P9221_STAT_OV_VOLT | \ - P9221_STAT_OV_CURRENT) -/* - * Interrupt/Status flags for P9221R7 - */ -#define P9221R7_STAT_CCRESET BIT(12) -#define P9221R7_STAT_CCERROR BIT(11) -#define P9221R7_STAT_PPRCVD BIT(10) -#define P9221R7_STAT_CCDATARCVD BIT(9) -#define P9221R7_STAT_CCSENDBUSY BIT(8) -#define P9221R7_STAT_VOUTCHANGED BIT(7) -#define P9221R7_STAT_VRECTON BIT(6) -#define P9221R7_STAT_MODECHANGED BIT(5) -#define P9221R7_STAT_UV BIT(3) -#define P9221R7_STAT_OVT BIT(2) -#define P9221R7_STAT_OVV BIT(1) -#define P9221R7_STAT_OVC BIT(0) -#define P9221R7_STAT_MASK 0x1FFF -#define P9221R7_STAT_CC_MASK (P9221R7_STAT_CCRESET | \ - P9221R7_STAT_PPRCVD | \ - P9221R7_STAT_CCERROR | \ - P9221R7_STAT_CCDATARCVD | \ - P9221R7_STAT_CCSENDBUSY) -#define P9221R7_STAT_LIMIT_MASK (P9221R7_STAT_UV | \ - P9221R7_STAT_OVV | \ - P9221R7_STAT_OVT | \ - P9221R7_STAT_OVC) - -#define P9221_DC_ICL_BPP_MA 1000 -#define P9221_DC_ICL_EPP_MA 1100 -#define P9221_DC_IVL_BPP_MV 5000 -#define P9221_DC_IVL_EPP_MV 9000 -#define P9221_EPP_THRESHOLD_UV 7000000 - -#define true 1 -#define false 0 - -struct wpc_charger_info { - uint8_t online; /* wpc is online */ - uint8_t cust_id; /* customer id */ - uint8_t i2c_port; /* i2c port */ - /* Proprietary Packets receive buffer, to get Proprietary data from TX*/ - uint8_t pp_buf[P9221R7_MAX_PP_BUF_SIZE]; - uint8_t pp_buf_valid; - /* Common message Packets receive buffer, for get data from TX */ - uint8_t rx_buf[P9221R7_DATA_RECV_BUF_SIZE]; - uint8_t rx_len; - uint8_t rx_done; - /* Message packets send buffer, used when send messages from RX to TX*/ - uint8_t tx_buf[P9221R7_DATA_SEND_BUF_SIZE]; - uint8_t tx_id; /* TX device id */ - uint8_t tx_len; /* The data size need send to TX */ - uint8_t tx_done; /* TX data send has done */ - uint8_t tx_busy; /* when tx_busy=1, can't transfer data from RX to TX */ - /* p9221_check_vbus=1 when VBUS has changed, need update charge state */ - uint8_t p9221_check_vbus; - /* p9221_check_det=1 when TX device has detected */ - uint8_t p9221_check_det; - /* vbus_status is 1 when VBUS attached and is 0 when VBUS detached*/ - uint8_t vbus_status; - /* supplier type of wireless charger */ - uint8_t charge_supplier; - /* lock of send command to p9221 */ - struct mutex cmd_lock; -}; - -/* Interrupt handler for p9221 */ -void p9221_interrupt(enum gpio_signal signal); - -/** - * notify p9221 detect update charger status when VBUS changed - * - * @param vbus: new status of VBUS, 1 if VBUS on, 0 if VBUS off. - */ -void p9221_notify_vbus_change(int vbus); - -/** - * get the fod (foreign-object detection) parameters for bpp charger type - * - * @param fod: return the real value of fod paramerters, - * return NULL if fod paramerters not set. - * - * @return the count bytes of fod paramerters. - */ -int board_get_fod(uint8_t **fod); - -/** - * get the fod (foreign-object detection) parameters for epp chager type - * - * @param fod: return the real value of fod paramerters, - * return NULL if fod paramerters not set. - * - * @return the count bytes of fod paramerters. - */ -int board_get_epp_fod(uint8_t **fod); - -/** - * return the wireless charge online status - * - * @return true if online, false if offline. - */ -int wpc_chip_is_online(void); - -#endif |