Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

regmap: spmi: support base and extended register spaces

SPMI states that a slave may contain two register spaces, the Base
register space is a 5-bit byte-addressable space accessed via the
Register Read/Write and Register Zero Write command sequences, and the
Extended register space: a 16-bit byte-addressable space accessed via
the Extended Read/Write and Extended Read/Write Long command sequences.

Provide support for accessing both of these spaces, taking advantage of
the more bandwidth-efficient commands ('Register 0 Write' vs 'Register
Write', and 'Extended Register Read/Write' vs 'Extended Register
Read/Write Long') when possible.

Signed-off-by: Josh Cartwright <joshc@codeaurora.org>
Acked-by: Mark Brown <broonie@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Josh Cartwright and committed by
Greg Kroah-Hartman
c9afbb05 2c9e577d

+208 -38
+200 -34
drivers/base/regmap/regmap-spmi.c
··· 22 22 #include <linux/module.h> 23 23 #include <linux/init.h> 24 24 25 - static int regmap_spmi_read(void *context, 26 - const void *reg, size_t reg_size, 27 - void *val, size_t val_size) 25 + static int regmap_spmi_base_read(void *context, 26 + const void *reg, size_t reg_size, 27 + void *val, size_t val_size) 28 28 { 29 - BUG_ON(reg_size != 2); 30 - return spmi_ext_register_readl(context, *(u16 *)reg, 31 - val, val_size); 29 + u8 addr = *(u8 *)reg; 30 + int err = 0; 31 + 32 + BUG_ON(reg_size != 1); 33 + 34 + while (val_size-- && !err) 35 + err = spmi_register_read(context, addr++, val++); 36 + 37 + return err; 32 38 } 33 39 34 - static int regmap_spmi_gather_write(void *context, 35 - const void *reg, size_t reg_size, 36 - const void *val, size_t val_size) 40 + static int regmap_spmi_base_gather_write(void *context, 41 + const void *reg, size_t reg_size, 42 + const void *val, size_t val_size) 37 43 { 38 - BUG_ON(reg_size != 2); 39 - return spmi_ext_register_writel(context, *(u16 *)reg, val, val_size); 44 + const u8 *data = val; 45 + u8 addr = *(u8 *)reg; 46 + int err = 0; 47 + 48 + BUG_ON(reg_size != 1); 49 + 50 + /* 51 + * SPMI defines a more bandwidth-efficient 'Register 0 Write' sequence, 52 + * use it when possible. 53 + */ 54 + if (addr == 0 && val_size) { 55 + err = spmi_register_zero_write(context, *data); 56 + if (err) 57 + goto err_out; 58 + 59 + data++; 60 + addr++; 61 + val_size--; 62 + } 63 + 64 + while (val_size) { 65 + err = spmi_register_write(context, addr, *data); 66 + if (err) 67 + goto err_out; 68 + 69 + data++; 70 + addr++; 71 + val_size--; 72 + } 73 + 74 + err_out: 75 + return err; 40 76 } 41 77 42 - static int regmap_spmi_write(void *context, const void *data, 43 - size_t count) 78 + static int regmap_spmi_base_write(void *context, const void *data, 79 + size_t count) 44 80 { 45 - BUG_ON(count < 2); 46 - return regmap_spmi_gather_write(context, data, 2, data + 2, count - 2); 81 + BUG_ON(count < 1); 82 + return regmap_spmi_base_gather_write(context, data, 1, data + 1, 83 + count - 1); 47 84 } 48 85 49 - static struct regmap_bus regmap_spmi = { 50 - .read = regmap_spmi_read, 51 - .write = regmap_spmi_write, 52 - .gather_write = regmap_spmi_gather_write, 86 + static struct regmap_bus regmap_spmi_base = { 87 + .read = regmap_spmi_base_read, 88 + .write = regmap_spmi_base_write, 89 + .gather_write = regmap_spmi_base_gather_write, 53 90 .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, 54 91 .val_format_endian_default = REGMAP_ENDIAN_NATIVE, 55 92 }; 56 93 57 94 /** 58 - * regmap_init_spmi(): Initialize register map 59 - * 60 - * @sdev: Device that will be interacted with 61 - * @config: Configuration for register map 95 + * regmap_init_spmi_base(): Create regmap for the Base register space 96 + * @sdev: SPMI device that will be interacted with 97 + * @config: Configuration for register map 62 98 * 63 99 * The return value will be an ERR_PTR() on error or a valid pointer to 64 100 * a struct regmap. 65 101 */ 66 - struct regmap *regmap_init_spmi(struct spmi_device *sdev, 67 - const struct regmap_config *config) 102 + struct regmap *regmap_init_spmi_base(struct spmi_device *sdev, 103 + const struct regmap_config *config) 68 104 { 69 - return regmap_init(&sdev->dev, &regmap_spmi, sdev, config); 105 + return regmap_init(&sdev->dev, &regmap_spmi_base, sdev, config); 70 106 } 71 - EXPORT_SYMBOL_GPL(regmap_init_spmi); 107 + EXPORT_SYMBOL_GPL(regmap_init_spmi_base); 72 108 73 109 /** 74 - * devm_regmap_init_spmi(): Initialise managed register map 75 - * 76 - * @sdev: Device that will be interacted with 77 - * @config: Configuration for register map 110 + * devm_regmap_init_spmi_base(): Create managed regmap for Base register space 111 + * @sdev: SPMI device that will be interacted with 112 + * @config: Configuration for register map 78 113 * 79 114 * The return value will be an ERR_PTR() on error or a valid pointer 80 115 * to a struct regmap. The regmap will be automatically freed by the 81 116 * device management code. 82 117 */ 83 - struct regmap *devm_regmap_init_spmi(struct spmi_device *sdev, 118 + struct regmap *devm_regmap_init_spmi_base(struct spmi_device *sdev, 119 + const struct regmap_config *config) 120 + { 121 + return devm_regmap_init(&sdev->dev, &regmap_spmi_base, sdev, config); 122 + } 123 + EXPORT_SYMBOL_GPL(devm_regmap_init_spmi_base); 124 + 125 + static int regmap_spmi_ext_read(void *context, 126 + const void *reg, size_t reg_size, 127 + void *val, size_t val_size) 128 + { 129 + int err = 0; 130 + size_t len; 131 + u16 addr; 132 + 133 + BUG_ON(reg_size != 2); 134 + 135 + addr = *(u16 *)reg; 136 + 137 + /* 138 + * Split accesses into two to take advantage of the more 139 + * bandwidth-efficient 'Extended Register Read' command when possible 140 + */ 141 + while (addr <= 0xFF && val_size) { 142 + len = min_t(size_t, val_size, 16); 143 + 144 + err = spmi_ext_register_read(context, addr, val, len); 145 + if (err) 146 + goto err_out; 147 + 148 + addr += len; 149 + val += len; 150 + val_size -= len; 151 + } 152 + 153 + while (val_size) { 154 + len = min_t(size_t, val_size, 8); 155 + 156 + err = spmi_ext_register_readl(context, addr, val, val_size); 157 + if (err) 158 + goto err_out; 159 + 160 + addr += len; 161 + val += len; 162 + val_size -= len; 163 + } 164 + 165 + err_out: 166 + return err; 167 + } 168 + 169 + static int regmap_spmi_ext_gather_write(void *context, 170 + const void *reg, size_t reg_size, 171 + const void *val, size_t val_size) 172 + { 173 + int err = 0; 174 + size_t len; 175 + u16 addr; 176 + 177 + BUG_ON(reg_size != 2); 178 + 179 + addr = *(u16 *)reg; 180 + 181 + while (addr <= 0xFF && val_size) { 182 + len = min_t(size_t, val_size, 16); 183 + 184 + err = spmi_ext_register_write(context, addr, val, len); 185 + if (err) 186 + goto err_out; 187 + 188 + addr += len; 189 + val += len; 190 + val_size -= len; 191 + } 192 + 193 + while (val_size) { 194 + len = min_t(size_t, val_size, 8); 195 + 196 + err = spmi_ext_register_writel(context, addr, val, len); 197 + if (err) 198 + goto err_out; 199 + 200 + addr += len; 201 + val += len; 202 + val_size -= len; 203 + } 204 + 205 + err_out: 206 + return err; 207 + } 208 + 209 + static int regmap_spmi_ext_write(void *context, const void *data, 210 + size_t count) 211 + { 212 + BUG_ON(count < 2); 213 + return regmap_spmi_ext_gather_write(context, data, 2, data + 2, 214 + count - 2); 215 + } 216 + 217 + static struct regmap_bus regmap_spmi_ext = { 218 + .read = regmap_spmi_ext_read, 219 + .write = regmap_spmi_ext_write, 220 + .gather_write = regmap_spmi_ext_gather_write, 221 + .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, 222 + .val_format_endian_default = REGMAP_ENDIAN_NATIVE, 223 + }; 224 + 225 + /** 226 + * regmap_init_spmi_ext(): Create regmap for Ext register space 227 + * @sdev: Device that will be interacted with 228 + * @config: Configuration for register map 229 + * 230 + * The return value will be an ERR_PTR() on error or a valid pointer to 231 + * a struct regmap. 232 + */ 233 + struct regmap *regmap_init_spmi_ext(struct spmi_device *sdev, 234 + const struct regmap_config *config) 235 + { 236 + return regmap_init(&sdev->dev, &regmap_spmi_ext, sdev, config); 237 + } 238 + EXPORT_SYMBOL_GPL(regmap_init_spmi_ext); 239 + 240 + /** 241 + * devm_regmap_init_spmi_ext(): Create managed regmap for Ext register space 242 + * @sdev: SPMI device that will be interacted with 243 + * @config: Configuration for register map 244 + * 245 + * The return value will be an ERR_PTR() on error or a valid pointer 246 + * to a struct regmap. The regmap will be automatically freed by the 247 + * device management code. 248 + */ 249 + struct regmap *devm_regmap_init_spmi_ext(struct spmi_device *sdev, 84 250 const struct regmap_config *config) 85 251 { 86 - return devm_regmap_init(&sdev->dev, &regmap_spmi, sdev, config); 252 + return devm_regmap_init(&sdev->dev, &regmap_spmi_ext, sdev, config); 87 253 } 88 - EXPORT_SYMBOL_GPL(devm_regmap_init_spmi); 254 + EXPORT_SYMBOL_GPL(devm_regmap_init_spmi_ext); 89 255 90 256 MODULE_LICENSE("GPL");
+8 -4
include/linux/regmap.h
··· 321 321 const struct regmap_config *config); 322 322 struct regmap *regmap_init_spi(struct spi_device *dev, 323 323 const struct regmap_config *config); 324 - struct regmap *regmap_init_spmi(struct spmi_device *dev, 325 - const struct regmap_config *config); 324 + struct regmap *regmap_init_spmi_base(struct spmi_device *dev, 325 + const struct regmap_config *config); 326 + struct regmap *regmap_init_spmi_ext(struct spmi_device *dev, 327 + const struct regmap_config *config); 326 328 struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id, 327 329 void __iomem *regs, 328 330 const struct regmap_config *config); ··· 337 335 const struct regmap_config *config); 338 336 struct regmap *devm_regmap_init_spi(struct spi_device *dev, 339 337 const struct regmap_config *config); 340 - struct regmap *devm_regmap_init_spmi(struct spmi_device *dev, 341 - const struct regmap_config *config); 338 + struct regmap *devm_regmap_init_spmi_base(struct spmi_device *dev, 339 + const struct regmap_config *config); 340 + struct regmap *devm_regmap_init_spmi_ext(struct spmi_device *dev, 341 + const struct regmap_config *config); 342 342 struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id, 343 343 void __iomem *regs, 344 344 const struct regmap_config *config);