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-i2c.c (9438B)


      1// SPDX-License-Identifier: GPL-2.0
      2//
      3// Register map access API - I2C support
      4//
      5// Copyright 2011 Wolfson Microelectronics plc
      6//
      7// Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
      8
      9#include <linux/regmap.h>
     10#include <linux/i2c.h>
     11#include <linux/module.h>
     12
     13#include "internal.h"
     14
     15static int regmap_smbus_byte_reg_read(void *context, unsigned int reg,
     16				      unsigned int *val)
     17{
     18	struct device *dev = context;
     19	struct i2c_client *i2c = to_i2c_client(dev);
     20	int ret;
     21
     22	if (reg > 0xff)
     23		return -EINVAL;
     24
     25	ret = i2c_smbus_read_byte_data(i2c, reg);
     26	if (ret < 0)
     27		return ret;
     28
     29	*val = ret;
     30
     31	return 0;
     32}
     33
     34static int regmap_smbus_byte_reg_write(void *context, unsigned int reg,
     35				       unsigned int val)
     36{
     37	struct device *dev = context;
     38	struct i2c_client *i2c = to_i2c_client(dev);
     39
     40	if (val > 0xff || reg > 0xff)
     41		return -EINVAL;
     42
     43	return i2c_smbus_write_byte_data(i2c, reg, val);
     44}
     45
     46static const struct regmap_bus regmap_smbus_byte = {
     47	.reg_write = regmap_smbus_byte_reg_write,
     48	.reg_read = regmap_smbus_byte_reg_read,
     49};
     50
     51static int regmap_smbus_word_reg_read(void *context, unsigned int reg,
     52				      unsigned int *val)
     53{
     54	struct device *dev = context;
     55	struct i2c_client *i2c = to_i2c_client(dev);
     56	int ret;
     57
     58	if (reg > 0xff)
     59		return -EINVAL;
     60
     61	ret = i2c_smbus_read_word_data(i2c, reg);
     62	if (ret < 0)
     63		return ret;
     64
     65	*val = ret;
     66
     67	return 0;
     68}
     69
     70static int regmap_smbus_word_reg_write(void *context, unsigned int reg,
     71				       unsigned int val)
     72{
     73	struct device *dev = context;
     74	struct i2c_client *i2c = to_i2c_client(dev);
     75
     76	if (val > 0xffff || reg > 0xff)
     77		return -EINVAL;
     78
     79	return i2c_smbus_write_word_data(i2c, reg, val);
     80}
     81
     82static const struct regmap_bus regmap_smbus_word = {
     83	.reg_write = regmap_smbus_word_reg_write,
     84	.reg_read = regmap_smbus_word_reg_read,
     85};
     86
     87static int regmap_smbus_word_read_swapped(void *context, unsigned int reg,
     88					  unsigned int *val)
     89{
     90	struct device *dev = context;
     91	struct i2c_client *i2c = to_i2c_client(dev);
     92	int ret;
     93
     94	if (reg > 0xff)
     95		return -EINVAL;
     96
     97	ret = i2c_smbus_read_word_swapped(i2c, reg);
     98	if (ret < 0)
     99		return ret;
    100
    101	*val = ret;
    102
    103	return 0;
    104}
    105
    106static int regmap_smbus_word_write_swapped(void *context, unsigned int reg,
    107					   unsigned int val)
    108{
    109	struct device *dev = context;
    110	struct i2c_client *i2c = to_i2c_client(dev);
    111
    112	if (val > 0xffff || reg > 0xff)
    113		return -EINVAL;
    114
    115	return i2c_smbus_write_word_swapped(i2c, reg, val);
    116}
    117
    118static const struct regmap_bus regmap_smbus_word_swapped = {
    119	.reg_write = regmap_smbus_word_write_swapped,
    120	.reg_read = regmap_smbus_word_read_swapped,
    121};
    122
    123static int regmap_i2c_write(void *context, const void *data, size_t count)
    124{
    125	struct device *dev = context;
    126	struct i2c_client *i2c = to_i2c_client(dev);
    127	int ret;
    128
    129	ret = i2c_master_send(i2c, data, count);
    130	if (ret == count)
    131		return 0;
    132	else if (ret < 0)
    133		return ret;
    134	else
    135		return -EIO;
    136}
    137
    138static int regmap_i2c_gather_write(void *context,
    139				   const void *reg, size_t reg_size,
    140				   const void *val, size_t val_size)
    141{
    142	struct device *dev = context;
    143	struct i2c_client *i2c = to_i2c_client(dev);
    144	struct i2c_msg xfer[2];
    145	int ret;
    146
    147	/* If the I2C controller can't do a gather tell the core, it
    148	 * will substitute in a linear write for us.
    149	 */
    150	if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_NOSTART))
    151		return -ENOTSUPP;
    152
    153	xfer[0].addr = i2c->addr;
    154	xfer[0].flags = 0;
    155	xfer[0].len = reg_size;
    156	xfer[0].buf = (void *)reg;
    157
    158	xfer[1].addr = i2c->addr;
    159	xfer[1].flags = I2C_M_NOSTART;
    160	xfer[1].len = val_size;
    161	xfer[1].buf = (void *)val;
    162
    163	ret = i2c_transfer(i2c->adapter, xfer, 2);
    164	if (ret == 2)
    165		return 0;
    166	if (ret < 0)
    167		return ret;
    168	else
    169		return -EIO;
    170}
    171
    172static int regmap_i2c_read(void *context,
    173			   const void *reg, size_t reg_size,
    174			   void *val, size_t val_size)
    175{
    176	struct device *dev = context;
    177	struct i2c_client *i2c = to_i2c_client(dev);
    178	struct i2c_msg xfer[2];
    179	int ret;
    180
    181	xfer[0].addr = i2c->addr;
    182	xfer[0].flags = 0;
    183	xfer[0].len = reg_size;
    184	xfer[0].buf = (void *)reg;
    185
    186	xfer[1].addr = i2c->addr;
    187	xfer[1].flags = I2C_M_RD;
    188	xfer[1].len = val_size;
    189	xfer[1].buf = val;
    190
    191	ret = i2c_transfer(i2c->adapter, xfer, 2);
    192	if (ret == 2)
    193		return 0;
    194	else if (ret < 0)
    195		return ret;
    196	else
    197		return -EIO;
    198}
    199
    200static const struct regmap_bus regmap_i2c = {
    201	.write = regmap_i2c_write,
    202	.gather_write = regmap_i2c_gather_write,
    203	.read = regmap_i2c_read,
    204	.reg_format_endian_default = REGMAP_ENDIAN_BIG,
    205	.val_format_endian_default = REGMAP_ENDIAN_BIG,
    206};
    207
    208static int regmap_i2c_smbus_i2c_write(void *context, const void *data,
    209				      size_t count)
    210{
    211	struct device *dev = context;
    212	struct i2c_client *i2c = to_i2c_client(dev);
    213
    214	if (count < 1)
    215		return -EINVAL;
    216
    217	--count;
    218	return i2c_smbus_write_i2c_block_data(i2c, ((u8 *)data)[0], count,
    219					      ((u8 *)data + 1));
    220}
    221
    222static int regmap_i2c_smbus_i2c_read(void *context, const void *reg,
    223				     size_t reg_size, void *val,
    224				     size_t val_size)
    225{
    226	struct device *dev = context;
    227	struct i2c_client *i2c = to_i2c_client(dev);
    228	int ret;
    229
    230	if (reg_size != 1 || val_size < 1)
    231		return -EINVAL;
    232
    233	ret = i2c_smbus_read_i2c_block_data(i2c, ((u8 *)reg)[0], val_size, val);
    234	if (ret == val_size)
    235		return 0;
    236	else if (ret < 0)
    237		return ret;
    238	else
    239		return -EIO;
    240}
    241
    242static const struct regmap_bus regmap_i2c_smbus_i2c_block = {
    243	.write = regmap_i2c_smbus_i2c_write,
    244	.read = regmap_i2c_smbus_i2c_read,
    245	.max_raw_read = I2C_SMBUS_BLOCK_MAX,
    246	.max_raw_write = I2C_SMBUS_BLOCK_MAX,
    247};
    248
    249static int regmap_i2c_smbus_i2c_write_reg16(void *context, const void *data,
    250				      size_t count)
    251{
    252	struct device *dev = context;
    253	struct i2c_client *i2c = to_i2c_client(dev);
    254
    255	if (count < 2)
    256		return -EINVAL;
    257
    258	count--;
    259	return i2c_smbus_write_i2c_block_data(i2c, ((u8 *)data)[0], count,
    260					      (u8 *)data + 1);
    261}
    262
    263static int regmap_i2c_smbus_i2c_read_reg16(void *context, const void *reg,
    264				     size_t reg_size, void *val,
    265				     size_t val_size)
    266{
    267	struct device *dev = context;
    268	struct i2c_client *i2c = to_i2c_client(dev);
    269	int ret, count, len = val_size;
    270
    271	if (reg_size != 2)
    272		return -EINVAL;
    273
    274	ret = i2c_smbus_write_byte_data(i2c, ((u16 *)reg)[0] & 0xff,
    275					((u16 *)reg)[0] >> 8);
    276	if (ret < 0)
    277		return ret;
    278
    279	count = 0;
    280	do {
    281		/* Current Address Read */
    282		ret = i2c_smbus_read_byte(i2c);
    283		if (ret < 0)
    284			break;
    285
    286		*((u8 *)val++) = ret;
    287		count++;
    288		len--;
    289	} while (len > 0);
    290
    291	if (count == val_size)
    292		return 0;
    293	else if (ret < 0)
    294		return ret;
    295	else
    296		return -EIO;
    297}
    298
    299static const struct regmap_bus regmap_i2c_smbus_i2c_block_reg16 = {
    300	.write = regmap_i2c_smbus_i2c_write_reg16,
    301	.read = regmap_i2c_smbus_i2c_read_reg16,
    302	.max_raw_read = I2C_SMBUS_BLOCK_MAX,
    303	.max_raw_write = I2C_SMBUS_BLOCK_MAX,
    304};
    305
    306static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c,
    307					const struct regmap_config *config)
    308{
    309	const struct i2c_adapter_quirks *quirks;
    310	const struct regmap_bus *bus = NULL;
    311	struct regmap_bus *ret_bus;
    312	u16 max_read = 0, max_write = 0;
    313
    314	if (i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C))
    315		bus = &regmap_i2c;
    316	else if (config->val_bits == 8 && config->reg_bits == 8 &&
    317		 i2c_check_functionality(i2c->adapter,
    318					 I2C_FUNC_SMBUS_I2C_BLOCK))
    319		bus = &regmap_i2c_smbus_i2c_block;
    320	else if (config->val_bits == 8 && config->reg_bits == 16 &&
    321		i2c_check_functionality(i2c->adapter,
    322					I2C_FUNC_SMBUS_I2C_BLOCK))
    323		bus = &regmap_i2c_smbus_i2c_block_reg16;
    324	else if (config->val_bits == 16 && config->reg_bits == 8 &&
    325		 i2c_check_functionality(i2c->adapter,
    326					 I2C_FUNC_SMBUS_WORD_DATA))
    327		switch (regmap_get_val_endian(&i2c->dev, NULL, config)) {
    328		case REGMAP_ENDIAN_LITTLE:
    329			bus = &regmap_smbus_word;
    330			break;
    331		case REGMAP_ENDIAN_BIG:
    332			bus = &regmap_smbus_word_swapped;
    333			break;
    334		default:		/* everything else is not supported */
    335			break;
    336		}
    337	else if (config->val_bits == 8 && config->reg_bits == 8 &&
    338		 i2c_check_functionality(i2c->adapter,
    339					 I2C_FUNC_SMBUS_BYTE_DATA))
    340		bus = &regmap_smbus_byte;
    341
    342	if (!bus)
    343		return ERR_PTR(-ENOTSUPP);
    344
    345	quirks = i2c->adapter->quirks;
    346	if (quirks) {
    347		if (quirks->max_read_len &&
    348		    (bus->max_raw_read == 0 || bus->max_raw_read > quirks->max_read_len))
    349			max_read = quirks->max_read_len;
    350
    351		if (quirks->max_write_len &&
    352		    (bus->max_raw_write == 0 || bus->max_raw_write > quirks->max_write_len))
    353			max_write = quirks->max_write_len;
    354
    355		if (max_read || max_write) {
    356			ret_bus = kmemdup(bus, sizeof(*bus), GFP_KERNEL);
    357			if (!ret_bus)
    358				return ERR_PTR(-ENOMEM);
    359			ret_bus->free_on_exit = true;
    360			ret_bus->max_raw_read = max_read;
    361			ret_bus->max_raw_write = max_write;
    362			bus = ret_bus;
    363		}
    364	}
    365
    366	return bus;
    367}
    368
    369struct regmap *__regmap_init_i2c(struct i2c_client *i2c,
    370				 const struct regmap_config *config,
    371				 struct lock_class_key *lock_key,
    372				 const char *lock_name)
    373{
    374	const struct regmap_bus *bus = regmap_get_i2c_bus(i2c, config);
    375
    376	if (IS_ERR(bus))
    377		return ERR_CAST(bus);
    378
    379	return __regmap_init(&i2c->dev, bus, &i2c->dev, config,
    380			     lock_key, lock_name);
    381}
    382EXPORT_SYMBOL_GPL(__regmap_init_i2c);
    383
    384struct regmap *__devm_regmap_init_i2c(struct i2c_client *i2c,
    385				      const struct regmap_config *config,
    386				      struct lock_class_key *lock_key,
    387				      const char *lock_name)
    388{
    389	const struct regmap_bus *bus = regmap_get_i2c_bus(i2c, config);
    390
    391	if (IS_ERR(bus))
    392		return ERR_CAST(bus);
    393
    394	return __devm_regmap_init(&i2c->dev, bus, &i2c->dev, config,
    395				  lock_key, lock_name);
    396}
    397EXPORT_SYMBOL_GPL(__devm_regmap_init_i2c);
    398
    399MODULE_LICENSE("GPL");