mirror of
https://github.com/apache/nuttx.git
synced 2026-09-01 14:43:02 +00:00
feat: charge: initialize rx charger stwlc38 driver
CHAMPION-25 Signed-off-by: zhangguoliang <zhangguoliang3@xiaomi.com> Change-Id: Ifa5732ae2160d4bc083f9aaf4e3beb34096b7770
This commit is contained in:
parent
7df6d25fc3
commit
e6d84fccc9
6 changed files with 1040 additions and 0 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
778
drivers/power/polaris.c
Normal file
778
drivers/power/polaris.c
Normal file
|
|
@ -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 <nuttx/config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <assert.h>
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/signal.h>
|
||||
#include <nuttx/i2c/i2c_master.h>
|
||||
#include <nuttx/power/battery_charger.h>
|
||||
#include <nuttx/power/battery_ioctl.h>
|
||||
|
||||
#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 */
|
||||
89
drivers/power/polaris.h
Normal file
89
drivers/power/polaris.h
Normal file
|
|
@ -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 */
|
||||
|
||||
108
drivers/power/polaris_nvm.c
Normal file
108
drivers/power/polaris_nvm.c
Normal file
|
|
@ -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
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue