1 /*
2 * Copyright (c) 2021 Google Inc
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT nuvoton_npcx_bbram
8
9 #include <zephyr/drivers/bbram.h>
10 #include <errno.h>
11 #include <zephyr/sys/util.h>
12
13 #include <zephyr/logging/log.h>
14 LOG_MODULE_REGISTER(npcx_bbram, CONFIG_BBRAM_LOG_LEVEL);
15
16 #include "npcx.h"
17
18 /*
19 * For emulator, define status bits for backup RAM status register.
20 * These are required for the emulator (native_sim) since the npcx SOC
21 * is not enabled, and missing definitions would cause a build error.
22 */
23 #ifdef CONFIG_BBRAM_NPCX_EMUL
24 #define NPCX_BKUPSTS_VSBY_STS BIT(1)
25 #define NPCX_BKUPSTS_VCC1_STS BIT(0)
26 #define NPCX_BKUPSTS_IBBR BIT(7)
27 #endif
28
29 #define DRV_STATUS(dev) \
30 (*((volatile uint8_t *)((const struct bbram_npcx_config *)(dev)->config)->status_reg_addr))
31
get_bit_and_reset(const struct device * dev,int mask)32 static int get_bit_and_reset(const struct device *dev, int mask)
33 {
34 int result = DRV_STATUS(dev) & mask;
35
36 /*
37 * Clear the bit(s):
38 * For emulator, write 0 to clear status bit(s).
39 * For real chip, write 1 to clear status bit(s).
40 */
41 #ifdef CONFIG_BBRAM_NPCX_EMUL
42 DRV_STATUS(dev) &= ~mask;
43 #else
44 DRV_STATUS(dev) = mask;
45
46 if (IS_ENABLED(CONFIG_BBRAM_NPCX_STATUS_REG_WRITE_WORKAROUND)) {
47 uint8_t __unused read_unused;
48
49 read_unused = DRV_STATUS(dev);
50 }
51 #endif
52
53 return result;
54 }
55
bbram_npcx_check_invalid(const struct device * dev)56 static int bbram_npcx_check_invalid(const struct device *dev)
57 {
58 return get_bit_and_reset(dev, NPCX_BKUPSTS_IBBR);
59 }
60
61 #ifndef CONFIG_BBRAM_NPCX_EX
bbram_npcx_check_standby_power(const struct device * dev)62 static int bbram_npcx_check_standby_power(const struct device *dev)
63 {
64 return get_bit_and_reset(dev, NPCX_BKUPSTS_VSBY_STS);
65 }
66 #endif /* CONFIG_BBRAM_NPCX_EX */
67
bbram_npcx_check_power(const struct device * dev)68 static int bbram_npcx_check_power(const struct device *dev)
69 {
70 return get_bit_and_reset(dev, NPCX_BKUPSTS_VCC1_STS);
71 }
72
bbram_npcx_get_size(const struct device * dev,size_t * size)73 static int bbram_npcx_get_size(const struct device *dev, size_t *size)
74 {
75 const struct bbram_npcx_config *config = dev->config;
76
77 *size = config->size;
78 return 0;
79 }
80
bbram_npcx_read(const struct device * dev,size_t offset,size_t size,uint8_t * data)81 static int bbram_npcx_read(const struct device *dev, size_t offset, size_t size,
82 uint8_t *data)
83 {
84 const struct bbram_npcx_config *config = dev->config;
85
86 if (size < 1 || offset + size > config->size || bbram_npcx_check_invalid(dev)) {
87 return -EINVAL;
88 }
89
90 bytecpy(data, ((uint8_t *)config->base_addr + offset), size);
91 return 0;
92 }
93
bbram_npcx_write(const struct device * dev,size_t offset,size_t size,const uint8_t * data)94 static int bbram_npcx_write(const struct device *dev, size_t offset, size_t size,
95 const uint8_t *data)
96 {
97 const struct bbram_npcx_config *config = dev->config;
98
99 if (size < 1 || offset + size > config->size || bbram_npcx_check_invalid(dev)) {
100 return -EINVAL;
101 }
102
103 bytecpy(((uint8_t *)config->base_addr + offset), data, size);
104 return 0;
105 }
106
107 static DEVICE_API(bbram, bbram_npcx_driver_api) = {
108 .check_invalid = bbram_npcx_check_invalid,
109 #ifndef CONFIG_BBRAM_NPCX_EX
110 .check_standby_power = bbram_npcx_check_standby_power,
111 #endif /* CONFIG_BBRAM_NPCX_EX */
112 .check_power = bbram_npcx_check_power,
113 .get_size = bbram_npcx_get_size,
114 .read = bbram_npcx_read,
115 .write = bbram_npcx_write,
116 };
117
118 #define BBRAM_INIT(inst) \
119 BBRAM_NPCX_DECL_CONFIG(inst); \
120 DEVICE_DT_INST_DEFINE(inst, NULL, NULL, NULL, &bbram_cfg_##inst, PRE_KERNEL_1, \
121 CONFIG_BBRAM_INIT_PRIORITY, &bbram_npcx_driver_api);
122
123 DT_INST_FOREACH_STATUS_OKAY(BBRAM_INIT);
124