diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index fa60ef1b706..800d39c3cd7 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -383,6 +383,15 @@ config SC8551 ---help--- The SC8551 are battery charger for lithium-ion batteries. +config STWLC38 + bool "STWLC38 Battery charger support" + default n + select I2C + select I2C_STWLC38 + depends on BATTERY_CHARGER + ---help--- + The STWLC38 are wireless rx for power supply. + config MCP73871 bool "Microchip MCP73871 Battery charger support" default n @@ -420,6 +429,16 @@ config DEBUG_SC8551 endif # SC8551 +if STWLC38 + +config DEBUG_STWLC38 + bool "STWLC38 Debug Features" + default n + ---help--- + Enable STWLC38 wireless rx debug features. + +endif # STWLC38 + config BATTERY_GAUGE bool "Battery Fuel Gauge support" default n @@ -482,6 +501,10 @@ config I2C_SC8551 bool default y if SC8551 +config I2C_STWLC38 + bool + default y if STWLC38 + config I2C_MAX1704X bool default y if MAX1704X diff --git a/drivers/power/Make.defs b/drivers/power/Make.defs index 57b3383bcb1..c5807f6f060 100644 --- a/drivers/power/Make.defs +++ b/drivers/power/Make.defs @@ -103,6 +103,10 @@ ifeq ($(CONFIG_I2C_SC8551),y) CSRCS += sc8551.c endif +ifeq ($(CONFIG_I2C_STWLC38),y) +CSRCS += polaris.c +endif + # Add the BQ256XX I2C-based battery charger driver ifeq ($(CONFIG_I2C_BQ25618),y) diff --git a/drivers/power/polaris.c b/drivers/power/polaris.c new file mode 100644 index 00000000000..b283f8a3412 --- /dev/null +++ b/drivers/power/polaris.c @@ -0,0 +1,778 @@ +/**************************************************************************** + * drivers/power/polaris.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +#ifndef __POLARIS_C +#define __POLARIS_C + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "polaris.h" +#include "polaris_nvm.c" + +#define PAGE_SIZE 256 + +#define NO_DEBUG + +/* Debug ********************************************************************/ +#ifdef CONFIG_DEBUG_STWLC38 +# define baterr _err +# define batdbg _err +# define batinfo _err +#else +# define baterr _none +# define batdbg _none +# define batinfo _none +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int stwlc38_state(FAR struct battery_charger_dev_s *dev, + FAR int *status); +static int stwlc38_health(FAR struct battery_charger_dev_s *dev, + FAR int *health); +static int stwlc38_online(FAR struct battery_charger_dev_s *dev, + FAR bool *status); +static int stwlc38_voltage(FAR struct battery_charger_dev_s *dev, + int value); +static int stwlc38_current(FAR struct battery_charger_dev_s *dev, + int value); +static int stwlc38_input_current(FAR struct battery_charger_dev_s *dev, + int value); +static int stwlc38_operate(FAR struct battery_charger_dev_s *dev, + uintptr_t param); + +static const struct battery_charger_operations_s g_stwlc38ops = +{ + stwlc38_state, + stwlc38_health, + stwlc38_online, + stwlc38_voltage, + stwlc38_current, + stwlc38_input_current, + stwlc38_operate, +}; + +static int stwlc38_state(FAR struct battery_charger_dev_s *dev, + FAR int *status) +{ + return ERROR; +} + +static int stwlc38_health(FAR struct battery_charger_dev_s *dev, + FAR int *health) +{ + return ERROR; +} + +static int stwlc38_online(FAR struct battery_charger_dev_s *dev, + FAR bool *status) +{ + return ERROR; +} + +static int stwlc38_voltage(FAR struct battery_charger_dev_s *dev, + FAR int value) +{ + return ERROR; +} + +static int stwlc38_current(FAR struct battery_charger_dev_s *dev, + FAR int value) +{ + return ERROR; +} + +static int stwlc38_input_current(FAR struct battery_charger_dev_s *dev, + FAR int value) +{ + return ERROR; +} + +static int stwlc38_operate(FAR struct battery_charger_dev_s *dev, + uintptr_t param) +{ + return ERROR; +} + +struct stwlc38_dev_s +{ + /* The common part of the battery driver visible to the upper-half driver */ + + FAR const struct battery_charger_operations_s *ops; /* Battery operations */ + sem_t batsem; /* Enforce mutually exclusive access */ + + /* Data fields specific to the lower half STWLC38 driver follow */ + + FAR struct i2c_master_s *i2c; /* I2C interface */ + uint8_t addr; /* I2C address */ + uint32_t frequency; /* I2C frequency */ +}; + +static uint8_t type_of_command[CMD_STR_LEN] = +{ + 0 +}; + +static int number_parameters; + +static int wlc_i2c_read(FAR struct stwlc38_dev_s *priv, uint8_t *cmd, + int cmd_length, uint8_t *read_data, int read_count) +{ + struct i2c_msg_s msg[2]; + int err; + FAR struct i2c_master_s *dev = priv->i2c; + +#ifdef DEBUG + int i = 0; +#endif + + msg[0].addr = priv->addr; + msg[0].buffer = cmd; + msg[0].length = cmd_length; + msg[0].flags = 0; + + msg[1].addr = priv->addr; + msg[1].buffer = read_data; + msg[1].length = read_count; + msg[1].flags = I2C_M_READ; + + if ((err = I2C_TRANSFER(dev, msg, 2)) < OK) + { + baterr("[WLC] i2c transfer failed! err: %d\n", err); + return err; + } + +#ifdef DEBUG + batinfo("[WLC] WR-W: "); + for (i = 0; i < cmd_length; i++) + printk(KERN_CONT "%02X ", cmd[i]); + + baterr("[WLC] WR-R: "); + for (i = 0; i < read_count; i++) + printk(KERN_CONT "%02X ", read_data[i]); +#endif + + return OK; +} + +static int wlc_i2c_write(FAR struct stwlc38_dev_s *priv, + uint8_t *cmd, int cmd_length) +{ + struct i2c_msg_s msg[1]; + int err; + FAR struct i2c_master_s *dev = priv->i2c; + +#ifdef DEBUG + int i = 0; +#endif + + msg[0].addr = priv->addr; + msg[0].buffer = cmd; + msg[0].length = cmd_length; + msg[0].flags = 0; + +#ifdef DEBUG + batinfo("[WLC] W: "); + for (i = 0; i < cmd_length; i++) + printk(KERN_CONT "%02X ", cmd[i]); +#endif + + if ((err = I2C_TRANSFER(dev, msg, 1)) < OK) + { + baterr("[WLC] i2c transfer failed! err: %d\n", err); + return err; + } + + return OK; +} + +static int hw_i2c_write(FAR struct stwlc38_dev_s *priv, uint32_t addr, + uint8_t *data, uint32_t data_length) +{ + uint8_t *cmd; + memset(cmd, 0, (5 + data_length) * sizeof(uint8_t)); + + cmd[0] = OPCODE_WRITE; + cmd[1] = (uint8_t)((addr >> 24) & 0xff); + cmd[2] = (uint8_t)((addr >> 16) & 0xff); + cmd[3] = (uint8_t)((addr >> 8) & 0xff); + cmd[4] = (uint8_t)((addr >> 0) & 0xff); + memcpy(&cmd[5], data, data_length); + + if ((wlc_i2c_write(priv, cmd, (5 + data_length))) < OK) + { + baterr("[WLC] Error in writing Hardware I2c!\n"); + kmm_free(cmd); + return E_BUS_W; + } + + kmm_free(cmd); + return OK; +} + +static int fw_i2c_write(FAR struct stwlc38_dev_s *priv, uint16_t addr, + uint8_t *data, uint32_t data_length) +{ + uint8_t *cmd; + memset(cmd, 0, (2 + data_length) * sizeof(uint8_t)); + cmd[0] = (uint8_t)((addr >> 8) & 0xff); + cmd[1] = (uint8_t)((addr >> 0) & 0xff); + memcpy(&cmd[2], data, data_length); + if ((wlc_i2c_write(priv, cmd, (2 + data_length))) < OK) + { + baterr("[WLC] ERROR: in writing Hardware I2c!\n"); + kmm_free(cmd); + return E_BUS_W; + } + + kmm_free(cmd); + return OK; +} + +static int hw_i2c_read(FAR struct stwlc38_dev_s *priv, uint32_t addr, + uint8_t *read_buff, int read_count) +{ + uint8_t cmd[5]; + cmd[0] = OPCODE_WRITE; + cmd[1] = (uint8_t)((addr >> 24) & 0xff); + cmd[2] = (uint8_t)((addr >> 16) & 0xff); + cmd[3] = (uint8_t)((addr >> 8) & 0xff); + cmd[4] = (uint8_t)((addr >> 0) & 0xff); + if ((wlc_i2c_read(priv, cmd, 5 , read_buff, read_count)) < OK) + { + baterr("[WLC] Error in writing Hardware I2c!\n"); + return E_BUS_WR; + } + + return OK; +} + +static int fw_i2c_read(FAR struct stwlc38_dev_s *priv, uint16_t addr, + uint8_t *read_buff, int read_count) +{ + uint8_t cmd[2]; + cmd[0] = (uint8_t)((addr >> 8) & 0xff); + cmd[1] = (uint8_t)((addr >> 0) & 0xff); + if ((wlc_i2c_read(priv, cmd, 2, read_buff, read_count)) < OK) + { + baterr("[WLC] Error in writing Hardware I2c!\n"); + return E_BUS_WR; + } + + return OK; +} + +char *print_hex(char *label, uint8_t *buff, int count, uint8_t *result) +{ + int i; + int offset; + offset = strlen(label) + 1; + strlcpy(result, label, offset); /* +1 for terminator char */ + for (i = 0; i < count; i++) + { + snprintf(&result[offset], 4, "%02X ", buff[i]); + + /* this append automatically a null terminator char */ + + offset += 3; + } + + return result; +} + +static int get_polaris_chip_info(FAR struct stwlc38_dev_s *priv, + struct polaris_chip_info *info) +{ + uint8_t read_buff[14]; + + memset(read_buff, 0, 14); + if (fw_i2c_read(priv, WLC_CHIPID_LOW_REG, read_buff, 14) < OK) + { + baterr("[WLC] Error while getting polaris_chip_info\n"); + return E_BUS_R; + } + + info->chip_id = (uint16_t)(read_buff[0] + (read_buff[1] << 8)); + info->chip_revision = read_buff[2]; + info->customer_id = read_buff[3]; + info->project_id = (uint16_t)(read_buff[4] + (read_buff[5] << 8)); + info->nvm_patch_id = (uint16_t)(read_buff[6] + (read_buff[7] << 8)); + info->ram_patch_id = (uint16_t)(read_buff[8] + (read_buff[9] << 8)); + info->config_id = (uint16_t)(read_buff[10] + (read_buff[11] << 8)); + info->pe_id = (uint16_t)(read_buff[12] + (read_buff[13] << 8)); + + if (hw_i2c_read(priv, HWREG_HW_VER_ADDR, read_buff, 1) < OK) + { + baterr("[WLC] Error while getting polaris_chip_info\n"); + return E_BUS_R; + } + + info->cut_id = read_buff[0]; + batinfo("[WLC] ChipID: %04X Chip Revision: %02X CustomerID: %02X \ + RomID: %04X NVMPatchID: %04X RAMPatchID: %04X CFG: %04X \ + PE: %04X\n", info->chip_id, info->chip_revision, \ + info->customer_id, info->project_id, info->nvm_patch_id, \ + info->ram_patch_id, info->config_id, info->pe_id); + return OK; +} + +static int polaris_nvm_write_sector(FAR struct stwlc38_dev_s *priv, + const uint8_t *data, + int data_length, + int sector_index) +{ + int err = 0; + int i = 0; + int timeout = 1; + uint8_t reg_value = (uint8_t)sector_index; + uint8_t write_buff[NVM_SECTOR_SIZE_BYTES]; + + batinfo("[WLC] writing sector %02X\n", sector_index); + if (data_length > NVM_SECTOR_SIZE_BYTES) + { + baterr("[WLC] sector data bigger than 256 bytes\n"); + return E_INVALID_INPUT; + } + + memset(write_buff, 0, NVM_SECTOR_SIZE_BYTES); + memcpy(write_buff, data, data_length); + + err = fw_i2c_write(priv, FWREG_NVM_SECTOR_INDEX_ADDR, ®_value, 1); + if (err != OK) return err; + + reg_value = 0x10; + err = fw_i2c_write(priv, FWREG_SYS_CMD_ADDR, ®_value, 1); + if (err != OK) return err; + + err = fw_i2c_write(priv, FWREG_AUX_DATA_00, write_buff, data_length); + if (err != OK) return err; + + reg_value = 0x04; + err = fw_i2c_write(priv, FWREG_SYS_CMD_ADDR, ®_value, 1); + if (err != OK) return err; + + for (i = 0; i < 20; i++) + { + sleep(1); + err = fw_i2c_read(priv, FWREG_SYS_CMD_ADDR, ®_value, 1); + if (err != OK) return err; + if ((reg_value & 0x04) == 0) + { + timeout = 0; + break; + } + } + + reg_value = 0x20; + if (fw_i2c_write(priv, FWREG_SYS_CMD_ADDR, ®_value, 1) != OK) + baterr("[WLC] Error power down the NVM\n"); + + return timeout == 0 ? OK : E_TIMEOUT; +} + +static int polaris_nvm_write_bulk(FAR struct stwlc38_dev_s *priv, + const uint8_t *data, + int data_length, + uint8_t sector_index) +{ + int err = 0; + int remaining = data_length; + int to_write_now = 0; + int written_already = 0; + while (remaining > 0) + { + if (remaining > NVM_SECTOR_SIZE_BYTES) + to_write_now = NVM_SECTOR_SIZE_BYTES; + else + to_write_now = remaining; + + err = polaris_nvm_write_sector(priv, data + written_already, + to_write_now, sector_index); + if (err != OK) return err; + remaining -= to_write_now; + written_already += to_write_now; + sector_index++; + } + + return OK; +} + +static int polaris_nvm_write(FAR struct stwlc38_dev_s *priv) +{ + int err = 0; + uint8_t reg_value = 0; + + /* check if OP MODE = DC POWER */ + + err = fw_i2c_read(priv, FWREG_OP_MODE_ADDR, ®_value, 1); + if (err != OK) return err; + baterr("[WLC] OP MODE %02X\n", reg_value); + + if (reg_value != FW_OP_MODE_SA) + { + baterr("[WLC] no DC power detected, nvm programming aborted\n"); + return E_UNEXPECTED_OP_MODE; + } + + /* FW system reset */ + + reg_value = 0x40; + if ((err = fw_i2c_write(priv, FWREG_SYS_CMD_ADDR, ®_value, 1)) != OK) + return err; + sleep(AFTER_SYS_RESET_SLEEP_MS); + reg_value = 0xc5; + if ((err = fw_i2c_write(priv, FWREG_NVM_PWD_ADDR, ®_value, 1)) != OK) + return err; + batinfo("[WLC] RRAM Programming.. \n"); + + err = polaris_nvm_write_bulk(priv, patch_data, NVM_PATCH_SIZE, + NVM_PATCH_START_SECTOR_INDEX); + if (err != OK) return err; + err = polaris_nvm_write_bulk(priv, cfg_data, NVM_CFG_SIZE, + NVM_CFG_START_SECTOR_INDEX); + if (err != OK) return err; + + /* system reset */ + + reg_value = 0x01; + if ((err = hw_i2c_write(priv, HWREG_HW_SYS_RST_ADDR, ®_value, 1)) != OK) + return err; + sleep(AFTER_SYS_RESET_SLEEP_MS); + return OK; +} + +static ssize_t chip_info_show(FAR struct stwlc38_dev_s *priv, char *buf) +{ + int error; + char temp[100]; + uint8_t read_buff[4]; + uint8_t cmd[2]; + FAR struct i2c_master_s *dev = priv->i2c; + + memset(read_buff, 0, 4); + memset(cmd, 0, 2); + + cmd[0] = (WLC_CHIPID_LOW_REG & 0xff00) >> 8; + cmd[1] = (WLC_CHIPID_LOW_REG & 0xff); + batinfo("[WLC] Chip Id Command: %02X %02X\n", cmd[0], cmd[1]); + + if (wlc_i2c_read(dev, cmd, 2, read_buff, 4) < OK) + { + baterr("[WLC] could not read the register\n"); + error = snprintf(buf, PAGE_SIZE, + "CHIP INFO READ ERROR {%02X}\n", E_BUS_WR); + return error; + } + + batinfo("[WLC] Chip Id : 0x%04X\n", (read_buff[0] | (read_buff[1] << 8))); + batinfo("[WLC] Chip Revision : 0x%02X\n", read_buff[2]); + error = snprintf(buf, PAGE_SIZE, "%s\n", print_hex("Chip Info: ", + read_buff, 3, temp)); + + return error; +} + +static ssize_t nvm_program_show(FAR struct stwlc38_dev_s *priv, char *buf) +{ + int err = 0; + FAR struct i2c_master_s *dev = priv->i2c; + int count = 0; + int config_id_mismatch = 0; + int patch_id_mismatch = 0; + struct polaris_chip_info chip_info; + batinfo("[WLC] NVM Programming started\n"); + if (get_polaris_chip_info(priv, &chip_info) < OK) + { + baterr("[WLC] Error in reading polaris_chip_info\n"); + err = E_BUS_R; + goto exit_0; + } + + /* determine what has to be programmed depending on version ids */ + + batinfo("[WLC] Cut Id: %02X\n", chip_info.cut_id); + if (chip_info.cut_id != NVM_TARGET_CUT_ID) + { + batinfo("[WLC] HW cut id mismatch with Target cut id, \ + NVM programming aborted\n"); + err = E_UNEXPECTED_HW_REV; + goto exit_0; + } + + if (chip_info.config_id != NVM_CFG_VERSION_ID) + { + batinfo("[WLC] Config ID mismatch - running|header: [%04X|%04X]\n", \ + chip_info.config_id, NVM_CFG_VERSION_ID); + config_id_mismatch = 1; + } + + if (chip_info.nvm_patch_id != NVM_PATCH_VERSION_ID) + { + batinfo("[WLC] Patch ID mismatch - running|header: [%04X|%04X]\n", \ + chip_info.nvm_patch_id, NVM_PATCH_VERSION_ID); + patch_id_mismatch = 1; + } + + if (config_id_mismatch == 0 && patch_id_mismatch == 0) + { + batinfo("[WLC] NVM programming is not required, \ + both cfg and patch are up to date\n"); + err = OK; + goto exit_0; + } + + /************************************************************************** + * program both cfg and patch + * in case one of the two needs to be programmed + **************************************************************************/ + + if ((err = polaris_nvm_write(priv)) != OK) + { + err = E_NVM_WRITE; + baterr("[WLC] NVM programming failed\n"); + goto exit_0; + } + + batinfo("[WLC] NVM programming completed, \ + now checking patch and cfg id\n"); + + if (get_polaris_chip_info(priv, &chip_info) < OK) + { + baterr("[WLC] Error in reading lyra_chip_info\n"); + err = E_BUS_R; + goto exit_0; + } + + if ((chip_info.config_id == NVM_CFG_VERSION_ID) + && (chip_info.nvm_patch_id == NVM_PATCH_VERSION_ID)) + { + batinfo("[WLC] NVM patch and cfg id is OK\n"); + batinfo("[WLC] NVM Programming is successful\n"); + } + else + { + err = E_NVM_DATA_MISMATCH; + if (chip_info.config_id != NVM_CFG_VERSION_ID) + baterr("[WLC] Config Id mismatch after NVM programming\n"); + if (chip_info.nvm_patch_id != NVM_PATCH_VERSION_ID) + baterr("[WLC] Patch Id mismatch after NVM programming\n"); + batinfo("[WLC] NVM Programming failed\n"); + } + +exit_0: + batinfo("[WLC] NVM programming exited\n"); + count = snprintf(buf, PAGE_SIZE, "{ %08X }\n", err); + + return count; +} + +static ssize_t st_polaris_i2c_bridge_show(FAR struct stwlc38_dev_s *priv, + char *buf) +{ + int err = 0; + FAR struct i2c_master_s *dev = priv->i2c; + uint8_t *read_buff = NULL; + uint8_t *all_strbuff = NULL; + int read_count = 0; + int i = 0; + int index = 0; + int size = (6 * 2) + 1; + if (number_parameters != 0) + { + switch (type_of_command[0]) + { + case WRITE_READ_OPERATION: + { + if (number_parameters >= MIN_WR_BYTE_LENGTH) + { + read_count = ((type_of_command[number_parameters - 2] << 8) + | (type_of_command[number_parameters - 1])); + batinfo("[WLC] read Count is %d\n", read_count); + memset(read_buff, 0, read_count * sizeof(uint8_t)); + if (read_buff == NULL) + { + err = E_MEMORY_ALLOC; + goto cleanup; + } + + if (wlc_i2c_read(priv, type_of_command + 1, + (number_parameters - 3), + read_buff, read_count) < OK) + { + err = E_BUS_WR; + } + else + { + size += (read_count * sizeof(uint8_t)) * 2; + memset(all_strbuff, 0, size); + if (all_strbuff == NULL) + { + err = E_MEMORY_ALLOC; + goto cleanup; + } + + err = OK; + snprintf(&all_strbuff[index], 11, "{ %08X", err); + index += 10; + for (i = 0; i < read_count; i++) + { + snprintf(&all_strbuff[index], 3, "%02X", + read_buff[i]); + index += 2; + } + snprintf(&all_strbuff[index], 3, " }"); + index += 2; + err = snprintf(buf, PAGE_SIZE, "%s\n", all_strbuff); + number_parameters = 0; + kmm_free(read_buff); + kmm_free(all_strbuff); + return err; + } + } + else + { + baterr("[WLC] Invalid input for Write read operation\n"); + err = E_INVALID_INPUT; + } + + goto cleanup; + } + + case WRITE_OPERATION: + { + if (number_parameters >= MIN_W_BYTE_LENGTH) + { + if (wlc_i2c_write(priv, type_of_command + 1, + (number_parameters - 1)) < OK) + { + err = E_BUS_W; + } + else + { + err = OK; + } + } + else + { + baterr("[WLC] Invalid input for Write operation\n"); + err = E_INVALID_INPUT; + } + + goto cleanup; + } + + default: + { + baterr("[WLC] Invalid input for i2c bridge\n"); + err = E_INVALID_INPUT; + goto cleanup; + } + } + } + else + { + err = E_INVALID_INPUT; + baterr("[WLC] Invalid input for write/write_read operation\n"); + goto cleanup; + } + +cleanup: + number_parameters = 0; + if (read_buff != NULL) kmm_free(read_buff); + err = snprintf(buf, PAGE_SIZE, "{ %08X }\n", err); + return err; +} + +static ssize_t st_polaris_i2c_bridge_store(FAR struct stwlc38_dev_s *priv, + const char *buf, size_t count) +{ + int n; + int temp; + char *p = (char *)buf; + number_parameters = 0; + + for (n = 0; n < (count + 1) / 3; n++) + { + if (sscanf(p, "%02X ", &temp) == 1) + { + p += 3; + type_of_command[n] = (uint8_t)temp; + batinfo("[WLC] type_of_command[%d] = %02X\n", + n, type_of_command[n]); + number_parameters++; + } + } + + batinfo("[WLC] Number of Parameters = %d\n", number_parameters); + return count; +} + +FAR struct battery_charger_dev_s * + stwlc38_initialize(FAR struct i2c_master_s *i2c, uint8_t addr, + uint32_t frequency, int current) +{ + FAR struct stwlc38_dev_s *priv; + char *buf; + int count; + + /* Initialize the SC8551 device structure */ + + priv = kmm_zalloc(sizeof(struct stwlc38_dev_s)); + if (priv) + { + /* Initialize the SC8551 device structure */ + + nxsem_init(&priv->batsem, 0, 1); + priv->ops = &g_stwlc38ops; + priv->i2c = i2c; + priv->addr = addr; + priv->frequency = frequency; + } + + count = nvm_program_show(priv, buf); + + return (FAR struct battery_charger_dev_s *)priv; +} + +#endif /* __POLARIS_C */ \ No newline at end of file diff --git a/drivers/power/polaris.h b/drivers/power/polaris.h new file mode 100644 index 00000000000..8e806f145ff --- /dev/null +++ b/drivers/power/polaris.h @@ -0,0 +1,89 @@ +/**************************************************************************** + * drivers/power/polaris.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __POLARIS_H +#define __POLARIS_H + +#define NVM_SECTOR_SIZE_BYTES 256 //128 +#define NVM_PATCH_START_SECTOR_INDEX 0 +#define NVM_CFG_START_SECTOR_INDEX 126 //93 +#define I2C_CHUNK_SIZE 256 //128 + +#define AFTER_SYS_RESET_SLEEP_MS 50 + +/* FW register address */ +#define FWREG_OP_MODE_ADDR 0x000E +#define FWREG_SYS_CMD_ADDR 0x0020 +#define FWREG_NVM_SECTOR_INDEX_ADDR 0x0024 +#define FWREG_AUX_DATA_00 0x0180 +#define FWREG_NVM_PWD_ADDR 0x0022 + +/* SYSREG registers */ +#define HWREG_HW_VER_ADDR 0x2001C002 +#define HWREG_HW_SYS_RST_ADDR 0x2001F200 + +typedef enum +{ + FW_OP_MODE_SA = 1, + FW_OP_MODE_RX = 2, + FW_OP_MODE_TX = 3 +}fw_op_mode_t; + +#define WRITE_READ_OPERATION 0x01 +#define WRITE_OPERATION 0x02 + +#define OPCODE_WRITE 0xFA + +#define MIN_WR_BYTE_LENGTH 5 +#define MIN_W_BYTE_LENGTH 4 + +#define CMD_STR_LEN 1024 + +#define OK ((int)0x00000000) +#define E_BUS_R ((int)0x80000001) +#define E_BUS_W ((int)0x80000002) +#define E_BUS_WR ((int)0x80000003) +#define E_UNEXPECTED_OP_MODE ((int)0x80000004) +#define E_NVM_WRITE ((int)0x80000005) +#define E_INVALID_INPUT ((int)0x80000006) +#define E_MEMORY_ALLOC ((int)0x80000007) +#define E_UNEXPECTED_HW_REV ((int)0x80000008) +#define E_TIMEOUT ((int)0x80000009) +#define E_NVM_DATA_MISMATCH ((int)0x8000000A) + +#define WLC_CHIPID_LOW_REG 0x0000 + +#define WLC_DRV_VERSION "1.0.0" /* driver version string format */ + +struct polaris_chip_info +{ + uint16_t chip_id; + uint8_t chip_revision; + uint8_t customer_id; + uint16_t project_id; + uint16_t nvm_patch_id; + uint16_t ram_patch_id; + uint16_t config_id; + uint16_t pe_id; + uint8_t cut_id; +}; + +#endif /* __POLARIS_H */ + diff --git a/drivers/power/polaris_nvm.c b/drivers/power/polaris_nvm.c new file mode 100644 index 00000000000..744e7d1e4e8 --- /dev/null +++ b/drivers/power/polaris_nvm.c @@ -0,0 +1,108 @@ +/**************************************************************************** + * drivers/power/polaris_nvm.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * The STWLC38 are Li-Ion Battery management + * + * This driver requires: + * + * CONFIG_BATTERY_CHARGER - Upper half battery driver support + * CONFIG_I2C - I2C support + * CONFIG_I2C_STWLC38 - And the driver must be explicitly selected. + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef NVM_DATA_H +#define NVM_DATA_H +#define NVM_TARGET_CUT_ID 1 +#define NVM_CFG_SIZE 384 +#define NVM_CFG_VERSION_ID 0x1001 +#define NVM_PATCH_SIZE 8 +#define NVM_PATCH_VERSION_ID 0x1000 + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +const uint8_t cfg_data[] = +{ + 0x01, 0x10, 0x00, 0x01, 0x77, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x14, 0x44, + 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x63, 0x00, 0x03, 0x0d, 0x09, 0x06, 0x00, 0xff, + 0x02, 0x19, 0x0f, 0x3d, 0x14, 0x0a, 0x32, 0x28, + 0x7d, 0x64, 0x0a, 0x00, 0x82, 0x82, 0x82, 0x82, + 0x41, 0x02, 0x02, 0x02, 0x02, 0xa5, 0x07, 0x06, + 0x12, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x23, 0x37, 0x2c, 0x42, 0x58, 0x6e, 0x84, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x7d, 0x7d, 0x7d, + 0x7d, 0x7d, 0x7d, 0xc8, 0x13, 0x0f, 0x0a, 0x05, + 0x26, 0x3c, 0x4b, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x56, 0x5f, 0x85, 0x64, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x07, 0x19, + 0x11, 0x00, 0x02, 0x00, 0x16, 0x11, 0x22, 0x33, + 0x44, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x05, 0x1e, 0x00, 0x12, 0x04, 0x1e, 0x5d, + 0x5d, 0x54, 0x80, 0x37, 0x9c, 0x14, 0x8e, 0x20, + 0x08, 0x04, 0x43, 0x11, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf0, 0x28, 0x0e, 0x05, + 0xd4, 0x00, 0xa8, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, 0x00, + 0x11, 0xc3, 0x05, 0x06, 0x09, 0x0d, 0x03, 0x1e, + 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x9a, 0x85, 0x29, 0x37, +}; + +const uint8_t patch_data[] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +#endif diff --git a/include/nuttx/power/battery_charger.h b/include/nuttx/power/battery_charger.h index 42deeac7070..d94060e45cb 100644 --- a/include/nuttx/power/battery_charger.h +++ b/include/nuttx/power/battery_charger.h @@ -338,6 +338,44 @@ FAR struct battery_charger_dev_s * uint32_t frequency, int current); #endif +/**************************************************************************** + * Name: stwlc38_initialize + * + * Description: + * Initialize the stwlc38 (wireless rx) charger driver and return + * an instance of the lower-half interface that may be used with + * battery_charger_register(). + * + * This is for: + * STWLC38 + * + * This driver requires: + * + * CONFIG_BATTERY_CHARGER - Upper half battery charger driver support + * CONFIG_I2C - I2C support + * CONFIG_I2C_STWLC38 - And the driver must be explicitly selected. + * + * Input Parameters: + * i2c - An instance of the I2C interface to use to communicate with + * the SC8551 + * addr - The I2C address of the STWLC38 (Better be 0x61). + * frequency - The I2C frequency + * current - The input current our power-supply can offer to charger + * + * Returned Value: + * A pointer to the initialized battery driver instance. A NULL pointer + * is returned on a failure to initialize the STWLC38 lower half. + * + ****************************************************************************/ + +#if defined(CONFIG_I2C) && defined(CONFIG_I2C_STWLC38) + +struct i2c_master_s; +FAR struct battery_charger_dev_s * + stwlc38_initialize(FAR struct i2c_master_s *i2c, uint8_t addr, + uint32_t frequency, int current); +#endif + #undef EXTERN #ifdef __cplusplus }