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, ®map_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