linux/drivers/base/regmap/regmap-spmi.c
<<
>>
Prefs
   1/*
   2 * Register map access API - SPMI support
   3 *
   4 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
   5 *
   6 * Based on regmap-i2c.c:
   7 * Copyright 2011 Wolfson Microelectronics plc
   8 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License version 2 and
  12 * only version 2 as published by the Free Software Foundation.
  13 *
  14 * This program is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 * GNU General Public License for more details.
  18 *
  19 */
  20#include <linux/regmap.h>
  21#include <linux/spmi.h>
  22#include <linux/module.h>
  23#include <linux/init.h>
  24
  25static int regmap_spmi_base_read(void *context,
  26                                 const void *reg, size_t reg_size,
  27                                 void *val, size_t val_size)
  28{
  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;
  38}
  39
  40static int regmap_spmi_base_gather_write(void *context,
  41                                         const void *reg, size_t reg_size,
  42                                         const void *val, size_t val_size)
  43{
  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
  74err_out:
  75        return err;
  76}
  77
  78static int regmap_spmi_base_write(void *context, const void *data,
  79                                  size_t count)
  80{
  81        BUG_ON(count < 1);
  82        return regmap_spmi_base_gather_write(context, data, 1, data + 1,
  83                                             count - 1);
  84}
  85
  86static 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,
  90        .reg_format_endian_default      = REGMAP_ENDIAN_NATIVE,
  91        .val_format_endian_default      = REGMAP_ENDIAN_NATIVE,
  92};
  93
  94struct regmap *__regmap_init_spmi_base(struct spmi_device *sdev,
  95                                       const struct regmap_config *config,
  96                                       struct lock_class_key *lock_key,
  97                                       const char *lock_name)
  98{
  99        return __regmap_init(&sdev->dev, &regmap_spmi_base, sdev, config,
 100                             lock_key, lock_name);
 101}
 102EXPORT_SYMBOL_GPL(__regmap_init_spmi_base);
 103
 104struct regmap *__devm_regmap_init_spmi_base(struct spmi_device *sdev,
 105                                            const struct regmap_config *config,
 106                                            struct lock_class_key *lock_key,
 107                                            const char *lock_name)
 108{
 109        return __devm_regmap_init(&sdev->dev, &regmap_spmi_base, sdev, config,
 110                                  lock_key, lock_name);
 111}
 112EXPORT_SYMBOL_GPL(__devm_regmap_init_spmi_base);
 113
 114static int regmap_spmi_ext_read(void *context,
 115                                const void *reg, size_t reg_size,
 116                                void *val, size_t val_size)
 117{
 118        int err = 0;
 119        size_t len;
 120        u16 addr;
 121
 122        BUG_ON(reg_size != 2);
 123
 124        addr = *(u16 *)reg;
 125
 126        /*
 127         * Split accesses into two to take advantage of the more
 128         * bandwidth-efficient 'Extended Register Read' command when possible
 129         */
 130        while (addr <= 0xFF && val_size) {
 131                len = min_t(size_t, val_size, 16);
 132
 133                err = spmi_ext_register_read(context, addr, val, len);
 134                if (err)
 135                        goto err_out;
 136
 137                addr += len;
 138                val += len;
 139                val_size -= len;
 140        }
 141
 142        while (val_size) {
 143                len = min_t(size_t, val_size, 8);
 144
 145                err = spmi_ext_register_readl(context, addr, val, len);
 146                if (err)
 147                        goto err_out;
 148
 149                addr += len;
 150                val += len;
 151                val_size -= len;
 152        }
 153
 154err_out:
 155        return err;
 156}
 157
 158static int regmap_spmi_ext_gather_write(void *context,
 159                                        const void *reg, size_t reg_size,
 160                                        const void *val, size_t val_size)
 161{
 162        int err = 0;
 163        size_t len;
 164        u16 addr;
 165
 166        BUG_ON(reg_size != 2);
 167
 168        addr = *(u16 *)reg;
 169
 170        while (addr <= 0xFF && val_size) {
 171                len = min_t(size_t, val_size, 16);
 172
 173                err = spmi_ext_register_write(context, addr, val, len);
 174                if (err)
 175                        goto err_out;
 176
 177                addr += len;
 178                val += len;
 179                val_size -= len;
 180        }
 181
 182        while (val_size) {
 183                len = min_t(size_t, val_size, 8);
 184
 185                err = spmi_ext_register_writel(context, addr, val, len);
 186                if (err)
 187                        goto err_out;
 188
 189                addr += len;
 190                val += len;
 191                val_size -= len;
 192        }
 193
 194err_out:
 195        return err;
 196}
 197
 198static int regmap_spmi_ext_write(void *context, const void *data,
 199                                 size_t count)
 200{
 201        BUG_ON(count < 2);
 202        return regmap_spmi_ext_gather_write(context, data, 2, data + 2,
 203                                            count - 2);
 204}
 205
 206static struct regmap_bus regmap_spmi_ext = {
 207        .read                           = regmap_spmi_ext_read,
 208        .write                          = regmap_spmi_ext_write,
 209        .gather_write                   = regmap_spmi_ext_gather_write,
 210        .reg_format_endian_default      = REGMAP_ENDIAN_NATIVE,
 211        .val_format_endian_default      = REGMAP_ENDIAN_NATIVE,
 212};
 213
 214struct regmap *__regmap_init_spmi_ext(struct spmi_device *sdev,
 215                                      const struct regmap_config *config,
 216                                      struct lock_class_key *lock_key,
 217                                      const char *lock_name)
 218{
 219        return __regmap_init(&sdev->dev, &regmap_spmi_ext, sdev, config,
 220                             lock_key, lock_name);
 221}
 222EXPORT_SYMBOL_GPL(__regmap_init_spmi_ext);
 223
 224struct regmap *__devm_regmap_init_spmi_ext(struct spmi_device *sdev,
 225                                           const struct regmap_config *config,
 226                                           struct lock_class_key *lock_key,
 227                                           const char *lock_name)
 228{
 229        return __devm_regmap_init(&sdev->dev, &regmap_spmi_ext, sdev, config,
 230                                  lock_key, lock_name);
 231}
 232EXPORT_SYMBOL_GPL(__devm_regmap_init_spmi_ext);
 233
 234MODULE_LICENSE("GPL");
 235