cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

regmap-spmi.c (5074B)


      1// SPDX-License-Identifier: GPL-2.0
      2//
      3// Register map access API - SPMI support
      4//
      5// Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
      6//
      7// Based on regmap-i2c.c:
      8// Copyright 2011 Wolfson Microelectronics plc
      9// Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
     10
     11#include <linux/regmap.h>
     12#include <linux/spmi.h>
     13#include <linux/module.h>
     14#include <linux/init.h>
     15
     16static int regmap_spmi_base_read(void *context,
     17				 const void *reg, size_t reg_size,
     18				 void *val, size_t val_size)
     19{
     20	u8 addr = *(u8 *)reg;
     21	int err = 0;
     22
     23	BUG_ON(reg_size != 1);
     24
     25	while (val_size-- && !err)
     26		err = spmi_register_read(context, addr++, val++);
     27
     28	return err;
     29}
     30
     31static int regmap_spmi_base_gather_write(void *context,
     32					 const void *reg, size_t reg_size,
     33					 const void *val, size_t val_size)
     34{
     35	const u8 *data = val;
     36	u8 addr = *(u8 *)reg;
     37	int err = 0;
     38
     39	BUG_ON(reg_size != 1);
     40
     41	/*
     42	 * SPMI defines a more bandwidth-efficient 'Register 0 Write' sequence,
     43	 * use it when possible.
     44	 */
     45	if (addr == 0 && val_size) {
     46		err = spmi_register_zero_write(context, *data);
     47		if (err)
     48			goto err_out;
     49
     50		data++;
     51		addr++;
     52		val_size--;
     53	}
     54
     55	while (val_size) {
     56		err = spmi_register_write(context, addr, *data);
     57		if (err)
     58			goto err_out;
     59
     60		data++;
     61		addr++;
     62		val_size--;
     63	}
     64
     65err_out:
     66	return err;
     67}
     68
     69static int regmap_spmi_base_write(void *context, const void *data,
     70				  size_t count)
     71{
     72	BUG_ON(count < 1);
     73	return regmap_spmi_base_gather_write(context, data, 1, data + 1,
     74					     count - 1);
     75}
     76
     77static const struct regmap_bus regmap_spmi_base = {
     78	.read				= regmap_spmi_base_read,
     79	.write				= regmap_spmi_base_write,
     80	.gather_write			= regmap_spmi_base_gather_write,
     81	.reg_format_endian_default	= REGMAP_ENDIAN_NATIVE,
     82	.val_format_endian_default	= REGMAP_ENDIAN_NATIVE,
     83};
     84
     85struct regmap *__regmap_init_spmi_base(struct spmi_device *sdev,
     86				       const struct regmap_config *config,
     87				       struct lock_class_key *lock_key,
     88				       const char *lock_name)
     89{
     90	return __regmap_init(&sdev->dev, &regmap_spmi_base, sdev, config,
     91			     lock_key, lock_name);
     92}
     93EXPORT_SYMBOL_GPL(__regmap_init_spmi_base);
     94
     95struct regmap *__devm_regmap_init_spmi_base(struct spmi_device *sdev,
     96					    const struct regmap_config *config,
     97					    struct lock_class_key *lock_key,
     98					    const char *lock_name)
     99{
    100	return __devm_regmap_init(&sdev->dev, &regmap_spmi_base, sdev, config,
    101				  lock_key, lock_name);
    102}
    103EXPORT_SYMBOL_GPL(__devm_regmap_init_spmi_base);
    104
    105static int regmap_spmi_ext_read(void *context,
    106				const void *reg, size_t reg_size,
    107				void *val, size_t val_size)
    108{
    109	int err = 0;
    110	size_t len;
    111	u16 addr;
    112
    113	BUG_ON(reg_size != 2);
    114
    115	addr = *(u16 *)reg;
    116
    117	/*
    118	 * Split accesses into two to take advantage of the more
    119	 * bandwidth-efficient 'Extended Register Read' command when possible
    120	 */
    121	while (addr <= 0xFF && val_size) {
    122		len = min_t(size_t, val_size, 16);
    123
    124		err = spmi_ext_register_read(context, addr, val, len);
    125		if (err)
    126			goto err_out;
    127
    128		addr += len;
    129		val += len;
    130		val_size -= len;
    131	}
    132
    133	while (val_size) {
    134		len = min_t(size_t, val_size, 8);
    135
    136		err = spmi_ext_register_readl(context, addr, val, len);
    137		if (err)
    138			goto err_out;
    139
    140		addr += len;
    141		val += len;
    142		val_size -= len;
    143	}
    144
    145err_out:
    146	return err;
    147}
    148
    149static int regmap_spmi_ext_gather_write(void *context,
    150					const void *reg, size_t reg_size,
    151					const void *val, size_t val_size)
    152{
    153	int err = 0;
    154	size_t len;
    155	u16 addr;
    156
    157	BUG_ON(reg_size != 2);
    158
    159	addr = *(u16 *)reg;
    160
    161	while (addr <= 0xFF && val_size) {
    162		len = min_t(size_t, val_size, 16);
    163
    164		err = spmi_ext_register_write(context, addr, val, len);
    165		if (err)
    166			goto err_out;
    167
    168		addr += len;
    169		val += len;
    170		val_size -= len;
    171	}
    172
    173	while (val_size) {
    174		len = min_t(size_t, val_size, 8);
    175
    176		err = spmi_ext_register_writel(context, addr, val, len);
    177		if (err)
    178			goto err_out;
    179
    180		addr += len;
    181		val += len;
    182		val_size -= len;
    183	}
    184
    185err_out:
    186	return err;
    187}
    188
    189static int regmap_spmi_ext_write(void *context, const void *data,
    190				 size_t count)
    191{
    192	BUG_ON(count < 2);
    193	return regmap_spmi_ext_gather_write(context, data, 2, data + 2,
    194					    count - 2);
    195}
    196
    197static const struct regmap_bus regmap_spmi_ext = {
    198	.read				= regmap_spmi_ext_read,
    199	.write				= regmap_spmi_ext_write,
    200	.gather_write			= regmap_spmi_ext_gather_write,
    201	.reg_format_endian_default	= REGMAP_ENDIAN_NATIVE,
    202	.val_format_endian_default	= REGMAP_ENDIAN_NATIVE,
    203};
    204
    205struct regmap *__regmap_init_spmi_ext(struct spmi_device *sdev,
    206				      const struct regmap_config *config,
    207				      struct lock_class_key *lock_key,
    208				      const char *lock_name)
    209{
    210	return __regmap_init(&sdev->dev, &regmap_spmi_ext, sdev, config,
    211			     lock_key, lock_name);
    212}
    213EXPORT_SYMBOL_GPL(__regmap_init_spmi_ext);
    214
    215struct regmap *__devm_regmap_init_spmi_ext(struct spmi_device *sdev,
    216					   const struct regmap_config *config,
    217					   struct lock_class_key *lock_key,
    218					   const char *lock_name)
    219{
    220	return __devm_regmap_init(&sdev->dev, &regmap_spmi_ext, sdev, config,
    221				  lock_key, lock_name);
    222}
    223EXPORT_SYMBOL_GPL(__devm_regmap_init_spmi_ext);
    224
    225MODULE_LICENSE("GPL");