xref: /linux/drivers/base/regmap/regmap-raw-ram.c (revision 5b0764a53235d3c77e1ed674e836e1b3fe1a4b1f)
1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // Register map access API - Memory region with raw access
4 //
5 // This is intended for testing only
6 //
7 // Copyright (c) 2023, Arm Ltd
8 
9 #include <linux/clk.h>
10 #include <linux/err.h>
11 #include <linux/io.h>
12 #include <linux/module.h>
13 #include <linux/regmap.h>
14 #include <linux/slab.h>
15 #include <linux/swab.h>
16 
17 #include "internal.h"
18 
19 static unsigned int decode_reg(struct regmap_ram_data *data, const void *reg)
20 {
21 	const u16 *r = reg;
22 	unsigned int decode;
23 
24 	if (data->reg_endian == REGMAP_ENDIAN_BIG)
25 		decode = be16_to_cpu(*r);
26 	else
27 		decode = le16_to_cpu(*r);
28 
29 	return decode - data->base_reg;
30 }
31 
32 static int regmap_raw_ram_gather_write(void *context,
33 				       const void *reg, size_t reg_len,
34 				       const void *val, size_t val_len)
35 {
36 	struct regmap_ram_data *data = context;
37 	unsigned int r;
38 	u16 *our_buf = (u16 *)data->vals;
39 	int i;
40 
41 	if (reg_len != 2)
42 		return -EINVAL;
43 	if (val_len % 2)
44 		return -EINVAL;
45 
46 	r = decode_reg(data, reg);
47 	if (data->noinc_reg && data->noinc_reg(data, r)) {
48 		memcpy(&our_buf[r], val + val_len - 2, 2);
49 		data->written[r] = true;
50 	} else {
51 		memcpy(&our_buf[r], val, val_len);
52 
53 		for (i = 0; i < val_len / 2; i++)
54 			data->written[r + i] = true;
55 	}
56 
57 	return 0;
58 }
59 
60 static int regmap_raw_ram_write(void *context, const void *data, size_t count)
61 {
62 	return regmap_raw_ram_gather_write(context, data, 2,
63 					   data + 2, count - 2);
64 }
65 
66 static int regmap_raw_ram_read(void *context,
67 			       const void *reg, size_t reg_len,
68 			       void *val, size_t val_len)
69 {
70 	struct regmap_ram_data *data = context;
71 	unsigned int r;
72 	u16 *our_buf = (u16 *)data->vals;
73 	int i;
74 
75 	if (reg_len != 2)
76 		return -EINVAL;
77 	if (val_len % 2)
78 		return -EINVAL;
79 
80 	r = decode_reg(data, reg);
81 	if (data->noinc_reg && data->noinc_reg(data, r)) {
82 		for (i = 0; i < val_len; i += 2)
83 			memcpy(val + i, &our_buf[r], 2);
84 		data->read[r] = true;
85 	} else {
86 		memcpy(val, &our_buf[r], val_len);
87 
88 		for (i = 0; i < val_len / 2; i++)
89 			data->read[r + i] = true;
90 	}
91 
92 	return 0;
93 }
94 
95 static void regmap_raw_ram_free_context(void *context)
96 {
97 	struct regmap_ram_data *data = context;
98 
99 	kfree(data->vals);
100 	kfree(data->read);
101 	kfree(data->written);
102 	kfree(data);
103 }
104 
105 static const struct regmap_bus regmap_raw_ram = {
106 	.fast_io = true,
107 	.write = regmap_raw_ram_write,
108 	.gather_write = regmap_raw_ram_gather_write,
109 	.read = regmap_raw_ram_read,
110 	.free_context = regmap_raw_ram_free_context,
111 };
112 
113 struct regmap *__regmap_init_raw_ram(struct device *dev,
114 				     const struct regmap_config *config,
115 				     struct regmap_ram_data *data,
116 				     struct lock_class_key *lock_key,
117 				     const char *lock_name)
118 {
119 	struct regmap *map;
120 	unsigned int regs;
121 
122 	if (config->reg_bits != 16)
123 		return ERR_PTR(-EINVAL);
124 
125 	if (!config->max_register) {
126 		pr_crit("No max_register specified for RAM regmap\n");
127 		return ERR_PTR(-EINVAL);
128 	}
129 
130 	regs = config->max_register - data->base_reg + 1;
131 	data->read = kzalloc_objs(bool, regs);
132 	if (!data->read)
133 		return ERR_PTR(-ENOMEM);
134 
135 	data->written = kzalloc_objs(bool, regs);
136 	if (!data->written)
137 		return ERR_PTR(-ENOMEM);
138 
139 	data->reg_endian = config->reg_format_endian;
140 
141 	map = __regmap_init(dev, &regmap_raw_ram, data, config,
142 			    lock_key, lock_name);
143 
144 	return map;
145 }
146 EXPORT_SYMBOL_GPL(__regmap_init_raw_ram);
147 
148 MODULE_DESCRIPTION("Register map access API - Memory region with raw access");
149 MODULE_LICENSE("GPL v2");
150