Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // Register map access API - SPMI support
0004 //
0005 // Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
0006 //
0007 // Based on regmap-i2c.c:
0008 // Copyright 2011 Wolfson Microelectronics plc
0009 // Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
0010 
0011 #include <linux/regmap.h>
0012 #include <linux/spmi.h>
0013 #include <linux/module.h>
0014 #include <linux/init.h>
0015 
0016 static int regmap_spmi_base_read(void *context,
0017                  const void *reg, size_t reg_size,
0018                  void *val, size_t val_size)
0019 {
0020     u8 addr = *(u8 *)reg;
0021     int err = 0;
0022 
0023     BUG_ON(reg_size != 1);
0024 
0025     while (val_size-- && !err)
0026         err = spmi_register_read(context, addr++, val++);
0027 
0028     return err;
0029 }
0030 
0031 static int regmap_spmi_base_gather_write(void *context,
0032                      const void *reg, size_t reg_size,
0033                      const void *val, size_t val_size)
0034 {
0035     const u8 *data = val;
0036     u8 addr = *(u8 *)reg;
0037     int err = 0;
0038 
0039     BUG_ON(reg_size != 1);
0040 
0041     /*
0042      * SPMI defines a more bandwidth-efficient 'Register 0 Write' sequence,
0043      * use it when possible.
0044      */
0045     if (addr == 0 && val_size) {
0046         err = spmi_register_zero_write(context, *data);
0047         if (err)
0048             goto err_out;
0049 
0050         data++;
0051         addr++;
0052         val_size--;
0053     }
0054 
0055     while (val_size) {
0056         err = spmi_register_write(context, addr, *data);
0057         if (err)
0058             goto err_out;
0059 
0060         data++;
0061         addr++;
0062         val_size--;
0063     }
0064 
0065 err_out:
0066     return err;
0067 }
0068 
0069 static int regmap_spmi_base_write(void *context, const void *data,
0070                   size_t count)
0071 {
0072     BUG_ON(count < 1);
0073     return regmap_spmi_base_gather_write(context, data, 1, data + 1,
0074                          count - 1);
0075 }
0076 
0077 static const struct regmap_bus regmap_spmi_base = {
0078     .read               = regmap_spmi_base_read,
0079     .write              = regmap_spmi_base_write,
0080     .gather_write           = regmap_spmi_base_gather_write,
0081     .reg_format_endian_default  = REGMAP_ENDIAN_NATIVE,
0082     .val_format_endian_default  = REGMAP_ENDIAN_NATIVE,
0083 };
0084 
0085 struct regmap *__regmap_init_spmi_base(struct spmi_device *sdev,
0086                        const struct regmap_config *config,
0087                        struct lock_class_key *lock_key,
0088                        const char *lock_name)
0089 {
0090     return __regmap_init(&sdev->dev, &regmap_spmi_base, sdev, config,
0091                  lock_key, lock_name);
0092 }
0093 EXPORT_SYMBOL_GPL(__regmap_init_spmi_base);
0094 
0095 struct regmap *__devm_regmap_init_spmi_base(struct spmi_device *sdev,
0096                         const struct regmap_config *config,
0097                         struct lock_class_key *lock_key,
0098                         const char *lock_name)
0099 {
0100     return __devm_regmap_init(&sdev->dev, &regmap_spmi_base, sdev, config,
0101                   lock_key, lock_name);
0102 }
0103 EXPORT_SYMBOL_GPL(__devm_regmap_init_spmi_base);
0104 
0105 static int regmap_spmi_ext_read(void *context,
0106                 const void *reg, size_t reg_size,
0107                 void *val, size_t val_size)
0108 {
0109     int err = 0;
0110     size_t len;
0111     u16 addr;
0112 
0113     BUG_ON(reg_size != 2);
0114 
0115     addr = *(u16 *)reg;
0116 
0117     /*
0118      * Split accesses into two to take advantage of the more
0119      * bandwidth-efficient 'Extended Register Read' command when possible
0120      */
0121     while (addr <= 0xFF && val_size) {
0122         len = min_t(size_t, val_size, 16);
0123 
0124         err = spmi_ext_register_read(context, addr, val, len);
0125         if (err)
0126             goto err_out;
0127 
0128         addr += len;
0129         val += len;
0130         val_size -= len;
0131     }
0132 
0133     while (val_size) {
0134         len = min_t(size_t, val_size, 8);
0135 
0136         err = spmi_ext_register_readl(context, addr, val, len);
0137         if (err)
0138             goto err_out;
0139 
0140         addr += len;
0141         val += len;
0142         val_size -= len;
0143     }
0144 
0145 err_out:
0146     return err;
0147 }
0148 
0149 static int regmap_spmi_ext_gather_write(void *context,
0150                     const void *reg, size_t reg_size,
0151                     const void *val, size_t val_size)
0152 {
0153     int err = 0;
0154     size_t len;
0155     u16 addr;
0156 
0157     BUG_ON(reg_size != 2);
0158 
0159     addr = *(u16 *)reg;
0160 
0161     while (addr <= 0xFF && val_size) {
0162         len = min_t(size_t, val_size, 16);
0163 
0164         err = spmi_ext_register_write(context, addr, val, len);
0165         if (err)
0166             goto err_out;
0167 
0168         addr += len;
0169         val += len;
0170         val_size -= len;
0171     }
0172 
0173     while (val_size) {
0174         len = min_t(size_t, val_size, 8);
0175 
0176         err = spmi_ext_register_writel(context, addr, val, len);
0177         if (err)
0178             goto err_out;
0179 
0180         addr += len;
0181         val += len;
0182         val_size -= len;
0183     }
0184 
0185 err_out:
0186     return err;
0187 }
0188 
0189 static int regmap_spmi_ext_write(void *context, const void *data,
0190                  size_t count)
0191 {
0192     BUG_ON(count < 2);
0193     return regmap_spmi_ext_gather_write(context, data, 2, data + 2,
0194                         count - 2);
0195 }
0196 
0197 static const struct regmap_bus regmap_spmi_ext = {
0198     .read               = regmap_spmi_ext_read,
0199     .write              = regmap_spmi_ext_write,
0200     .gather_write           = regmap_spmi_ext_gather_write,
0201     .reg_format_endian_default  = REGMAP_ENDIAN_NATIVE,
0202     .val_format_endian_default  = REGMAP_ENDIAN_NATIVE,
0203 };
0204 
0205 struct regmap *__regmap_init_spmi_ext(struct spmi_device *sdev,
0206                       const struct regmap_config *config,
0207                       struct lock_class_key *lock_key,
0208                       const char *lock_name)
0209 {
0210     return __regmap_init(&sdev->dev, &regmap_spmi_ext, sdev, config,
0211                  lock_key, lock_name);
0212 }
0213 EXPORT_SYMBOL_GPL(__regmap_init_spmi_ext);
0214 
0215 struct regmap *__devm_regmap_init_spmi_ext(struct spmi_device *sdev,
0216                        const struct regmap_config *config,
0217                        struct lock_class_key *lock_key,
0218                        const char *lock_name)
0219 {
0220     return __devm_regmap_init(&sdev->dev, &regmap_spmi_ext, sdev, config,
0221                   lock_key, lock_name);
0222 }
0223 EXPORT_SYMBOL_GPL(__devm_regmap_init_spmi_ext);
0224 
0225 MODULE_LICENSE("GPL");