drivers: bbram: Add Microchip MCP7940N driver

Adds Microchip MCP7940N battery-backed RAM support.

Signed-off-by: Jamie McCrae <jamie.mccrae@nordicsemi.no>
This commit is contained in:
Jamie McCrae 2023-02-24 12:12:43 +00:00 committed by Carles Cufí
commit f9fd899da0
5 changed files with 256 additions and 2 deletions

View file

@ -8,5 +8,6 @@ zephyr_library_sources_ifdef(CONFIG_BBRAM_SHELL bbram_shell.c)
zephyr_library_sources_ifdef(CONFIG_BBRAM_NPCX bbram_npcx.c) zephyr_library_sources_ifdef(CONFIG_BBRAM_NPCX bbram_npcx.c)
zephyr_library_sources_ifdef(CONFIG_BBRAM_IT8XXX2 bbram_it8xxx2.c) zephyr_library_sources_ifdef(CONFIG_BBRAM_IT8XXX2 bbram_it8xxx2.c)
zephyr_library_sources_ifdef(CONFIG_BBRAM_EMUL bbram_emul.c) zephyr_library_sources_ifdef(CONFIG_BBRAM_EMUL bbram_emul.c)
zephyr_library_sources_ifdef(CONFIG_BBRAM_MICROCHIP_MCP7940N bbram_microchip_mcp7940n.c)
zephyr_library_sources_ifdef(CONFIG_BBRAM_XEC bbram_xec.c) zephyr_library_sources_ifdef(CONFIG_BBRAM_XEC bbram_xec.c)
zephyr_library_sources_ifdef(CONFIG_BBRAM_STM32 bbram_stm32.c) zephyr_library_sources_ifdef(CONFIG_BBRAM_STM32 bbram_stm32.c)

View file

@ -23,6 +23,9 @@ config BBRAM_INIT_PRIORITY
# In STM32, BBRAM is a part of RTC. In this case init priority must be # In STM32, BBRAM is a part of RTC. In this case init priority must be
# lower than COUNTER_INIT_PRIORITY. # lower than COUNTER_INIT_PRIORITY.
default 65 if BBRAM_STM32 default 65 if BBRAM_STM32
# MCP7940N is an I2C device, therefore the init priority must be
# greater than I2C_INIT_PRIORITY.
default 55 if BBRAM_MICROCHIP_MCP7940N
default 10 default 10
help help
BBRAM driver initialization priority BBRAM driver initialization priority
@ -33,6 +36,8 @@ source "drivers/bbram/Kconfig.it8xxx2"
source "drivers/bbram/Kconfig.bbram_emul" source "drivers/bbram/Kconfig.bbram_emul"
source "drivers/bbram/Kconfig.microchip"
source "drivers/bbram/Kconfig.xec" source "drivers/bbram/Kconfig.xec"
source "drivers/bbram/Kconfig.stm32" source "drivers/bbram/Kconfig.stm32"

View file

@ -0,0 +1,10 @@
# Copyright (c) 2023 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0
config BBRAM_MICROCHIP_MCP7940N
bool "Microchip MCP7940N SRAM BBRAM driver"
default y
depends on DT_HAS_MICROCHIP_MCP7940N_ENABLED
select I2C
help
Enable driver for Microchip MCP7940N SRAM based battery-backed RAM.

View file

@ -0,0 +1,238 @@
/*
* Copyright (c) 2023, Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT microchip_mcp7940n
#include <string.h>
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/drivers/bbram.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/util.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(bbram_microchip_mcp7940n, CONFIG_BBRAM_LOG_LEVEL);
#define MICROCHIP_MCP7940N_SRAM_OFFSET 0x20
#define MICROCHIP_MCP7940N_SRAM_SIZE 64
#define MICROCHIP_MCP7940N_RTCWKDAY_REGISTER_ADDRESS 0x03
#define MICROCHIP_MCP7940N_RTCWKDAY_VBATEN_BIT BIT(3)
#define MICROCHIP_MCP7940N_RTCWKDAY_PWRFAIL_BIT BIT(4)
struct microchip_mcp7940n_bbram_data {
struct k_mutex lock;
};
struct microchip_mcp7940n_bbram_config {
struct i2c_dt_spec i2c;
};
static int microchip_mcp7940n_bbram_init(const struct device *dev)
{
const struct microchip_mcp7940n_bbram_config *config = dev->config;
struct microchip_mcp7940n_bbram_data *data = dev->data;
int32_t rc = 0;
uint8_t buffer;
if (!device_is_ready(config->i2c.bus)) {
LOG_ERR("I2C device %s is not ready", config->i2c.bus->name);
return -ENODEV;
}
k_mutex_init(&data->lock);
rc = i2c_reg_read_byte_dt(&config->i2c,
MICROCHIP_MCP7940N_RTCWKDAY_REGISTER_ADDRESS,
&buffer);
if (rc != 0) {
LOG_ERR("Failed to read RTCWKDAY register: %d", rc);
}
return rc;
}
static int microchip_mcp7940n_bbram_size(const struct device *dev, size_t *size)
{
*size = MICROCHIP_MCP7940N_SRAM_SIZE;
return 0;
}
static int microchip_mcp7940n_bbram_is_invalid(const struct device *dev)
{
const struct microchip_mcp7940n_bbram_config *config = dev->config;
struct microchip_mcp7940n_bbram_data *data = dev->data;
int32_t rc = 0;
uint8_t buffer;
bool data_valid = true;
k_mutex_lock(&data->lock, K_FOREVER);
rc = i2c_reg_read_byte_dt(&config->i2c,
MICROCHIP_MCP7940N_RTCWKDAY_REGISTER_ADDRESS,
&buffer);
if ((buffer & MICROCHIP_MCP7940N_RTCWKDAY_PWRFAIL_BIT)) {
data_valid = false;
buffer &= (buffer ^ MICROCHIP_MCP7940N_RTCWKDAY_PWRFAIL_BIT);
rc = i2c_reg_write_byte_dt(&config->i2c,
MICROCHIP_MCP7940N_RTCWKDAY_REGISTER_ADDRESS,
buffer);
if (rc != 0) {
LOG_ERR("Failed to write RTCWKDAY register: %d", rc);
goto finish;
}
}
finish:
k_mutex_unlock(&data->lock);
if (rc == 0 && data_valid == true) {
rc = 1;
}
return rc;
}
static int microchip_mcp7940n_bbram_check_standby_power(const struct device *dev)
{
const struct microchip_mcp7940n_bbram_config *config = dev->config;
struct microchip_mcp7940n_bbram_data *data = dev->data;
int32_t rc = 0;
uint8_t buffer;
bool power_enabled = true;
k_mutex_lock(&data->lock, K_FOREVER);
rc = i2c_reg_read_byte_dt(&config->i2c,
MICROCHIP_MCP7940N_RTCWKDAY_REGISTER_ADDRESS,
&buffer);
if (!(buffer & MICROCHIP_MCP7940N_RTCWKDAY_VBATEN_BIT)) {
power_enabled = false;
buffer |= MICROCHIP_MCP7940N_RTCWKDAY_VBATEN_BIT;
rc = i2c_reg_write_byte_dt(&config->i2c,
MICROCHIP_MCP7940N_RTCWKDAY_REGISTER_ADDRESS,
buffer);
if (rc != 0) {
LOG_ERR("Failed to write RTCWKDAY register: %d", rc);
goto finish;
}
}
finish:
k_mutex_unlock(&data->lock);
if (rc == 0 && power_enabled == true) {
rc = 1;
}
return rc;
}
static int microchip_mcp7940n_bbram_read(const struct device *dev, size_t offset, size_t size,
uint8_t *buffer)
{
const struct microchip_mcp7940n_bbram_config *config = dev->config;
struct microchip_mcp7940n_bbram_data *data = dev->data;
size_t i = 0;
int32_t rc = 0;
if ((offset + size) > MICROCHIP_MCP7940N_SRAM_SIZE) {
return -EINVAL;
}
k_mutex_lock(&data->lock, K_FOREVER);
while (i < size) {
LOG_DBG("Read from 0x%x", (MICROCHIP_MCP7940N_SRAM_OFFSET + offset + i));
rc = i2c_reg_read_byte_dt(&config->i2c,
(MICROCHIP_MCP7940N_SRAM_OFFSET + offset + i),
&buffer[i]);
if (rc != 0) {
goto finish;
}
++i;
}
finish:
k_mutex_unlock(&data->lock);
return rc;
}
static int microchip_mcp7940n_bbram_write(const struct device *dev, size_t offset, size_t size,
const uint8_t *buffer)
{
const struct microchip_mcp7940n_bbram_config *config = dev->config;
struct microchip_mcp7940n_bbram_data *data = dev->data;
size_t i = 0;
int32_t rc = 0;
if ((offset + size) > MICROCHIP_MCP7940N_SRAM_SIZE) {
return -EINVAL;
}
k_mutex_lock(&data->lock, K_FOREVER);
while (i < size) {
LOG_DBG("Write 0x%x to 0x%x", buffer[i],
(MICROCHIP_MCP7940N_SRAM_OFFSET + offset + i));
rc = i2c_reg_write_byte_dt(&config->i2c,
(MICROCHIP_MCP7940N_SRAM_OFFSET + offset + i),
buffer[i]);
if (rc != 0) {
goto finish;
}
++i;
}
finish:
k_mutex_unlock(&data->lock);
return rc;
}
static const struct bbram_driver_api microchip_mcp7940n_bbram_api = {
.get_size = microchip_mcp7940n_bbram_size,
.check_invalid = microchip_mcp7940n_bbram_is_invalid,
.check_standby_power = microchip_mcp7940n_bbram_check_standby_power,
.read = microchip_mcp7940n_bbram_read,
.write = microchip_mcp7940n_bbram_write,
};
#define MICROCHIP_MCP7940N_BBRAM_DEVICE(inst) \
static struct microchip_mcp7940n_bbram_data microchip_mcp7940n_bbram_data_##inst; \
static const struct microchip_mcp7940n_bbram_config \
microchip_mcp7940n_bbram_config_##inst = { \
.i2c = I2C_DT_SPEC_INST_GET(inst), \
}; \
DEVICE_DT_INST_DEFINE(inst, \
&microchip_mcp7940n_bbram_init, \
NULL, \
&microchip_mcp7940n_bbram_data_##inst, \
&microchip_mcp7940n_bbram_config_##inst, \
POST_KERNEL, \
CONFIG_BBRAM_INIT_PRIORITY, \
&microchip_mcp7940n_bbram_api);
DT_INST_FOREACH_STATUS_OKAY(MICROCHIP_MCP7940N_BBRAM_DEVICE)

View file

@ -1,10 +1,11 @@
# #
# Copyright (c) 2021 Laird Connectivity # Copyright (c) 2021 Laird Connectivity
# Copyright (c) 2023 Nordic Semiconductor ASA
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
description: Microchip MCP7940N I2C RTC description: Microchip MCP7940N I2C RTC with battery-backed SRAM
compatible: "microchip,mcp7940n" compatible: "microchip,mcp7940n"
@ -17,7 +18,6 @@ properties:
int-gpios: int-gpios:
type: phandle-array type: phandle-array
description: | description: |
Host input connected to the MCP7940N MFP open drain output pin Host input connected to the MCP7940N MFP open drain output pin
Notifies when an alarm has triggered by asserting this line. Notifies when an alarm has triggered by asserting this line.