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