226 lines · 5.0 KB · C
RawDownload
// 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, &regmap_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, &regmap_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, &regmap_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, &regmap_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");