1 // SPDX-License-Identifier: GPL-2.0 2 // 3 // Register map access API - FSI support 4 // 5 // Copyright 2022 IBM Corp 6 // 7 // Author: Eddie James <eajames@linux.ibm.com> 8 9 #include <linux/fsi.h> 10 #include <linux/module.h> 11 #include <linux/regmap.h> 12 13 #include "internal.h" 14 15 static int regmap_fsi32_reg_read(void *context, unsigned int reg, unsigned int *val) 16 { 17 u32 v; 18 int ret; 19 20 ret = fsi_slave_read(context, reg, &v, sizeof(v)); 21 if (ret) 22 return ret; 23 24 *val = v; 25 return 0; 26 } 27 28 static int regmap_fsi32_reg_write(void *context, unsigned int reg, unsigned int val) 29 { 30 u32 v = val; 31 32 return fsi_slave_write(context, reg, &v, sizeof(v)); 33 } 34 35 static const struct regmap_bus regmap_fsi32 = { 36 .reg_write = regmap_fsi32_reg_write, 37 .reg_read = regmap_fsi32_reg_read, 38 }; 39 40 static int regmap_fsi32le_reg_read(void *context, unsigned int reg, unsigned int *val) 41 { 42 __be32 v; 43 int ret; 44 45 ret = fsi_slave_read(context, reg, &v, sizeof(v)); 46 if (ret) 47 return ret; 48 49 *val = be32_to_cpu(v); 50 return 0; 51 } 52 53 static int regmap_fsi32le_reg_write(void *context, unsigned int reg, unsigned int val) 54 { 55 __be32 v = cpu_to_be32(val); 56 57 return fsi_slave_write(context, reg, &v, sizeof(v)); 58 } 59 60 static const struct regmap_bus regmap_fsi32le = { 61 .reg_write = regmap_fsi32le_reg_write, 62 .reg_read = regmap_fsi32le_reg_read, 63 }; 64 65 static int regmap_fsi16_reg_read(void *context, unsigned int reg, unsigned int *val) 66 { 67 u16 v; 68 int ret; 69 70 ret = fsi_slave_read(context, reg, &v, sizeof(v)); 71 if (ret) 72 return ret; 73 74 *val = v; 75 return 0; 76 } 77 78 static int regmap_fsi16_reg_write(void *context, unsigned int reg, unsigned int val) 79 { 80 u16 v; 81 82 if (val > 0xffff) 83 return -EINVAL; 84 85 v = val; 86 return fsi_slave_write(context, reg, &v, sizeof(v)); 87 } 88 89 static const struct regmap_bus regmap_fsi16 = { 90 .reg_write = regmap_fsi16_reg_write, 91 .reg_read = regmap_fsi16_reg_read, 92 }; 93 94 static int regmap_fsi16le_reg_read(void *context, unsigned int reg, unsigned int *val) 95 { 96 __be16 v; 97 int ret; 98 99 ret = fsi_slave_read(context, reg, &v, sizeof(v)); 100 if (ret) 101 return ret; 102 103 *val = be16_to_cpu(v); 104 return 0; 105 } 106 107 static int regmap_fsi16le_reg_write(void *context, unsigned int reg, unsigned int val) 108 { 109 __be16 v; 110 111 if (val > 0xffff) 112 return -EINVAL; 113 114 v = cpu_to_be16(val); 115 return fsi_slave_write(context, reg, &v, sizeof(v)); 116 } 117 118 static const struct regmap_bus regmap_fsi16le = { 119 .reg_write = regmap_fsi16le_reg_write, 120 .reg_read = regmap_fsi16le_reg_read, 121 }; 122 123 static int regmap_fsi8_reg_read(void *context, unsigned int reg, unsigned int *val) 124 { 125 u8 v; 126 int ret; 127 128 ret = fsi_slave_read(context, reg, &v, sizeof(v)); 129 if (ret) 130 return ret; 131 132 *val = v; 133 return 0; 134 } 135 136 static int regmap_fsi8_reg_write(void *context, unsigned int reg, unsigned int val) 137 { 138 u8 v; 139 140 if (val > 0xff) 141 return -EINVAL; 142 143 v = val; 144 return fsi_slave_write(context, reg, &v, sizeof(v)); 145 } 146 147 static const struct regmap_bus regmap_fsi8 = { 148 .reg_write = regmap_fsi8_reg_write, 149 .reg_read = regmap_fsi8_reg_read, 150 }; 151 152 static const struct regmap_bus *regmap_get_fsi_bus(struct fsi_device *fsi_dev, 153 const struct regmap_config *config) 154 { 155 const struct regmap_bus *bus = NULL; 156 157 if (config->reg_bits == 8 || config->reg_bits == 16 || config->reg_bits == 32) { 158 switch (config->val_bits) { 159 case 8: 160 bus = ®map_fsi8; 161 break; 162 case 16: 163 switch (regmap_get_val_endian(&fsi_dev->dev, NULL, config)) { 164 case REGMAP_ENDIAN_LITTLE: 165 #ifdef __LITTLE_ENDIAN 166 case REGMAP_ENDIAN_NATIVE: 167 #endif 168 bus = ®map_fsi16le; 169 break; 170 case REGMAP_ENDIAN_DEFAULT: 171 case REGMAP_ENDIAN_BIG: 172 #ifdef __BIG_ENDIAN 173 case REGMAP_ENDIAN_NATIVE: 174 #endif 175 bus = ®map_fsi16; 176 break; 177 default: 178 break; 179 } 180 break; 181 case 32: 182 switch (regmap_get_val_endian(&fsi_dev->dev, NULL, config)) { 183 case REGMAP_ENDIAN_LITTLE: 184 #ifdef __LITTLE_ENDIAN 185 case REGMAP_ENDIAN_NATIVE: 186 #endif 187 bus = ®map_fsi32le; 188 break; 189 case REGMAP_ENDIAN_DEFAULT: 190 case REGMAP_ENDIAN_BIG: 191 #ifdef __BIG_ENDIAN 192 case REGMAP_ENDIAN_NATIVE: 193 #endif 194 bus = ®map_fsi32; 195 break; 196 default: 197 break; 198 } 199 break; 200 } 201 } 202 203 return bus ?: ERR_PTR(-EOPNOTSUPP); 204 } 205 206 struct regmap *__regmap_init_fsi(struct fsi_device *fsi_dev, const struct regmap_config *config, 207 struct lock_class_key *lock_key, const char *lock_name) 208 { 209 const struct regmap_bus *bus = regmap_get_fsi_bus(fsi_dev, config); 210 211 if (IS_ERR(bus)) 212 return ERR_CAST(bus); 213 214 return __regmap_init(&fsi_dev->dev, bus, fsi_dev->slave, config, lock_key, lock_name); 215 } 216 EXPORT_SYMBOL_GPL(__regmap_init_fsi); 217 218 struct regmap *__devm_regmap_init_fsi(struct fsi_device *fsi_dev, 219 const struct regmap_config *config, 220 struct lock_class_key *lock_key, const char *lock_name) 221 { 222 const struct regmap_bus *bus = regmap_get_fsi_bus(fsi_dev, config); 223 224 if (IS_ERR(bus)) 225 return ERR_CAST(bus); 226 227 return __devm_regmap_init(&fsi_dev->dev, bus, fsi_dev->slave, config, lock_key, lock_name); 228 } 229 EXPORT_SYMBOL_GPL(__devm_regmap_init_fsi); 230 231 MODULE_LICENSE("GPL"); 232