// SPDX-License-Identifier: GPL-2.0//// Register map access API - SPMI support//// Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.//// Based on regmap-i2c.c:// Copyright 2011 Wolfson Microelectronics plc// Author: Mark Brown <broonie@opensource.wolfsonmicro.com> #include <linux/regmap.h>#include <linux/spmi.h>#include <linux/module.h>#include <linux/init.h> static int regmap_spmi_base_read(void *context, const void *reg, size_t reg_size, void *val, size_t val_size){ u8 addr = *(u8 *)reg; int err = 0; BUG_ON(reg_size != 1); while (val_size-- && !err) err = spmi_register_read(context, addr++, val++); return err;} static int regmap_spmi_base_gather_write(void *context, const void *reg, size_t reg_size, const void *val, size_t val_size){ const u8 *data = val; u8 addr = *(u8 *)reg; int err = 0; BUG_ON(reg_size != 1); /* * SPMI defines a more bandwidth-efficient 'Register 0 Write' sequence, * use it when possible. */ if (addr == 0 && val_size) { err = spmi_register_zero_write(context, *data); if (err) goto err_out; data++; addr++; val_size--; } while (val_size) { err = spmi_register_write(context, addr, *data); if (err) goto err_out; data++; addr++; val_size--; } err_out: return err;} static int regmap_spmi_base_write(void *context, const void *data, size_t count){ BUG_ON(count < 1); return regmap_spmi_base_gather_write(context, data, 1, data + 1, count - 1);} static const struct regmap_bus regmap_spmi_base = { .read = regmap_spmi_base_read, .write = regmap_spmi_base_write, .gather_write = regmap_spmi_base_gather_write, .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, .val_format_endian_default = REGMAP_ENDIAN_NATIVE,}; struct regmap *__regmap_init_spmi_base(struct spmi_device *sdev, const struct regmap_config *config, struct lock_class_key *lock_key, const char *lock_name){ return __regmap_init(&sdev->dev, ®map_spmi_base, sdev, config, lock_key, lock_name);}EXPORT_SYMBOL_GPL(__regmap_init_spmi_base); struct regmap *__devm_regmap_init_spmi_base(struct spmi_device *sdev, const struct regmap_config *config, struct lock_class_key *lock_key, const char *lock_name){ return __devm_regmap_init(&sdev->dev, ®map_spmi_base, sdev, config, lock_key, lock_name);}EXPORT_SYMBOL_GPL(__devm_regmap_init_spmi_base); static int regmap_spmi_ext_read(void *context, const void *reg, size_t reg_size, void *val, size_t val_size){ int err = 0; size_t len; u16 addr; BUG_ON(reg_size != 2); addr = *(u16 *)reg; /* * Split accesses into two to take advantage of the more * bandwidth-efficient 'Extended Register Read' command when possible */ while (addr <= 0xFF && val_size) { len = min_t(size_t, val_size, 16); err = spmi_ext_register_read(context, addr, val, len); if (err) goto err_out; addr += len; val += len; val_size -= len; } while (val_size) { len = min_t(size_t, val_size, 8); err = spmi_ext_register_readl(context, addr, val, len); if (err) goto err_out; addr += len; val += len; val_size -= len; } err_out: return err;} static int regmap_spmi_ext_gather_write(void *context, const void *reg, size_t reg_size, const void *val, size_t val_size){ int err = 0; size_t len; u16 addr; BUG_ON(reg_size != 2); addr = *(u16 *)reg; while (addr <= 0xFF && val_size) { len = min_t(size_t, val_size, 16); err = spmi_ext_register_write(context, addr, val, len); if (err) goto err_out; addr += len; val += len; val_size -= len; } while (val_size) { len = min_t(size_t, val_size, 8); err = spmi_ext_register_writel(context, addr, val, len); if (err) goto err_out; addr += len; val += len; val_size -= len; } err_out: return err;} static int regmap_spmi_ext_write(void *context, const void *data, size_t count){ BUG_ON(count < 2); return regmap_spmi_ext_gather_write(context, data, 2, data + 2, count - 2);} static const struct regmap_bus regmap_spmi_ext = { .read = regmap_spmi_ext_read, .write = regmap_spmi_ext_write, .gather_write = regmap_spmi_ext_gather_write, .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, .val_format_endian_default = REGMAP_ENDIAN_NATIVE,}; struct regmap *__regmap_init_spmi_ext(struct spmi_device *sdev, const struct regmap_config *config, struct lock_class_key *lock_key, const char *lock_name){ return __regmap_init(&sdev->dev, ®map_spmi_ext, sdev, config, lock_key, lock_name);}EXPORT_SYMBOL_GPL(__regmap_init_spmi_ext); struct regmap *__devm_regmap_init_spmi_ext(struct spmi_device *sdev, const struct regmap_config *config, struct lock_class_key *lock_key, const char *lock_name){ return __devm_regmap_init(&sdev->dev, ®map_spmi_ext, sdev, config, lock_key, lock_name);}EXPORT_SYMBOL_GPL(__devm_regmap_init_spmi_ext); MODULE_DESCRIPTION("Register map access API - SPMI support");MODULE_LICENSE("GPL");
// SPDX-License-Identifier: GPL-2.0
//
// Register map access API - SPMI support
//
// Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
//
// Based on regmap-i2c.c:
// Copyright 2011 Wolfson Microelectronics plc
// Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
#include <linux/regmap.h>
#include <linux/spmi.h>
#include <linux/module.h>
#include <linux/init.h>
static int regmap_spmi_base_read(void *context,
const void *reg, size_t reg_size,
void *val, size_t val_size)
{
u8 addr = *(u8 *)reg;
int err = 0;
BUG_ON(reg_size != 1);
while (val_size-- && !err)
err = spmi_register_read(context, addr++, val++);
return err;
}
static int regmap_spmi_base_gather_write(void *context,
const void *reg, size_t reg_size,
const void *val, size_t val_size)
{
const u8 *data = val;
u8 addr = *(u8 *)reg;
int err = 0;
BUG_ON(reg_size != 1);
/*
* SPMI defines a more bandwidth-efficient 'Register 0 Write' sequence,
* use it when possible.
*/
if (addr == 0 && val_size) {
err = spmi_register_zero_write(context, *data);
if (err)
goto err_out;
data++;
addr++;
val_size--;
}
while (val_size) {
err = spmi_register_write(context, addr, *data);
if (err)
goto err_out;
data++;
addr++;
val_size--;
}
err_out:
return err;
}
static int regmap_spmi_base_write(void *context, const void *data,
size_t count)
{
BUG_ON(count < 1);
return regmap_spmi_base_gather_write(context, data, 1, data + 1,
count - 1);
}
static const struct regmap_bus regmap_spmi_base = {
.read = regmap_spmi_base_read,
.write = regmap_spmi_base_write,
.gather_write = regmap_spmi_base_gather_write,
.reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
.val_format_endian_default = REGMAP_ENDIAN_NATIVE,
};
struct regmap *__regmap_init_spmi_base(struct spmi_device *sdev,
const struct regmap_config *config,
struct lock_class_key *lock_key,
const char *lock_name)
{
return __regmap_init(&sdev->dev, ®map_spmi_base, sdev, config,
lock_key, lock_name);
}
EXPORT_SYMBOL_GPL(__regmap_init_spmi_base);
struct regmap *__devm_regmap_init_spmi_base(struct spmi_device *sdev,
const struct regmap_config *config,
struct lock_class_key *lock_key,
const char *lock_name)
{
return __devm_regmap_init(&sdev->dev, ®map_spmi_base, sdev, config,
lock_key, lock_name);
}
EXPORT_SYMBOL_GPL(__devm_regmap_init_spmi_base);
static int regmap_spmi_ext_read(void *context,
const void *reg, size_t reg_size,
void *val, size_t val_size)
{
int err = 0;
size_t len;
u16 addr;
BUG_ON(reg_size != 2);
addr = *(u16 *)reg;
/*
* Split accesses into two to take advantage of the more
* bandwidth-efficient 'Extended Register Read' command when possible
*/
while (addr <= 0xFF && val_size) {
len = min_t(size_t, val_size, 16);
err = spmi_ext_register_read(context, addr, val, len);
if (err)
goto err_out;
addr += len;
val += len;
val_size -= len;
}
while (val_size) {
len = min_t(size_t, val_size, 8);
err = spmi_ext_register_readl(context, addr, val, len);
if (err)
goto err_out;
addr += len;
val += len;
val_size -= len;
}
err_out:
return err;
}
static int regmap_spmi_ext_gather_write(void *context,
const void *reg, size_t reg_size,
const void *val, size_t val_size)
{
int err = 0;
size_t len;
u16 addr;
BUG_ON(reg_size != 2);
addr = *(u16 *)reg;
while (addr <= 0xFF && val_size) {
len = min_t(size_t, val_size, 16);
err = spmi_ext_register_write(context, addr, val, len);
if (err)
goto err_out;
addr += len;
val += len;
val_size -= len;
}
while (val_size) {
len = min_t(size_t, val_size, 8);
err = spmi_ext_register_writel(context, addr, val, len);
if (err)
goto err_out;
addr += len;
val += len;
val_size -= len;
}
err_out:
return err;
}
static int regmap_spmi_ext_write(void *context, const void *data,
size_t count)
{
BUG_ON(count < 2);
return regmap_spmi_ext_gather_write(context, data, 2, data + 2,
count - 2);
}
static const struct regmap_bus regmap_spmi_ext = {
.read = regmap_spmi_ext_read,
.write = regmap_spmi_ext_write,
.gather_write = regmap_spmi_ext_gather_write,
.reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
.val_format_endian_default = REGMAP_ENDIAN_NATIVE,
};
struct regmap *__regmap_init_spmi_ext(struct spmi_device *sdev,
const struct regmap_config *config,
struct lock_class_key *lock_key,
const char *lock_name)
{
return __regmap_init(&sdev->dev, ®map_spmi_ext, sdev, config,
lock_key, lock_name);
}
EXPORT_SYMBOL_GPL(__regmap_init_spmi_ext);
struct regmap *__devm_regmap_init_spmi_ext(struct spmi_device *sdev,
const struct regmap_config *config,
struct lock_class_key *lock_key,
const char *lock_name)
{
return __devm_regmap_init(&sdev->dev, ®map_spmi_ext, sdev, config,
lock_key, lock_name);
}
EXPORT_SYMBOL_GPL(__devm_regmap_init_spmi_ext);
MODULE_DESCRIPTION("Register map access API - SPMI support");
MODULE_LICENSE("GPL");