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 15static 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 28static 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 35static const struct regmap_bus regmap_fsi32 = { 36 .reg_write = regmap_fsi32_reg_write, 37 .reg_read = regmap_fsi32_reg_read, 38}; 39 40static 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 53static 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 60static const struct regmap_bus regmap_fsi32le = { 61 .reg_write = regmap_fsi32le_reg_write, 62 .reg_read = regmap_fsi32le_reg_read, 63}; 64 65static 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 78static 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 89static const struct regmap_bus regmap_fsi16 = { 90 .reg_write = regmap_fsi16_reg_write, 91 .reg_read = regmap_fsi16_reg_read, 92}; 93 94static 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 107static 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 118static const struct regmap_bus regmap_fsi16le = { 119 .reg_write = regmap_fsi16le_reg_write, 120 .reg_read = regmap_fsi16le_reg_read, 121}; 122 123static 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 136static 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 147static const struct regmap_bus regmap_fsi8 = { 148 .reg_write = regmap_fsi8_reg_write, 149 .reg_read = regmap_fsi8_reg_read, 150}; 151 152static 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 206struct 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} 216EXPORT_SYMBOL_GPL(__regmap_init_fsi); 217 218struct 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} 229EXPORT_SYMBOL_GPL(__devm_regmap_init_fsi); 230 231MODULE_LICENSE("GPL"); 232