Skip to content

Commit

Permalink
Merge branch 'regmap-4.19' into regmap-next
Browse files Browse the repository at this point in the history
  • Loading branch information
broonie committed Aug 9, 2018
2 parents 1ffaddd + 1cbdded commit 1dce5d8
Show file tree
Hide file tree
Showing 9 changed files with 303 additions and 28 deletions.
4 changes: 4 additions & 0 deletions drivers/base/regmap/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,7 @@ config REGMAP_IRQ
config REGMAP_SOUNDWIRE
tristate
depends on SOUNDWIRE_BUS

config REGMAP_SCCB
tristate
depends on I2C
1 change: 1 addition & 0 deletions drivers/base/regmap/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ obj-$(CONFIG_REGMAP_MMIO) += regmap-mmio.o
obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o
obj-$(CONFIG_REGMAP_W1) += regmap-w1.o
obj-$(CONFIG_REGMAP_SOUNDWIRE) += regmap-sdw.o
obj-$(CONFIG_REGMAP_SCCB) += regmap-sccb.o
3 changes: 3 additions & 0 deletions drivers/base/regmap/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,12 @@ struct regmap {
bool (*readable_reg)(struct device *dev, unsigned int reg);
bool (*volatile_reg)(struct device *dev, unsigned int reg);
bool (*precious_reg)(struct device *dev, unsigned int reg);
bool (*readable_noinc_reg)(struct device *dev, unsigned int reg);
const struct regmap_access_table *wr_table;
const struct regmap_access_table *rd_table;
const struct regmap_access_table *volatile_table;
const struct regmap_access_table *precious_table;
const struct regmap_access_table *rd_noinc_table;

int (*reg_read)(void *context, unsigned int reg, unsigned int *val);
int (*reg_write)(void *context, unsigned int reg, unsigned int val);
Expand Down Expand Up @@ -181,6 +183,7 @@ bool regmap_writeable(struct regmap *map, unsigned int reg);
bool regmap_readable(struct regmap *map, unsigned int reg);
bool regmap_volatile(struct regmap *map, unsigned int reg);
bool regmap_precious(struct regmap *map, unsigned int reg);
bool regmap_readable_noinc(struct regmap *map, unsigned int reg);

int _regmap_write(struct regmap *map, unsigned int reg,
unsigned int val);
Expand Down
128 changes: 128 additions & 0 deletions drivers/base/regmap/regmap-sccb.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// SPDX-License-Identifier: GPL-2.0
// Register map access API - SCCB support

#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/regmap.h>

#include "internal.h"

/**
* sccb_is_available - Check if the adapter supports SCCB protocol
* @adap: I2C adapter
*
* Return true if the I2C adapter is capable of using SCCB helper functions,
* false otherwise.
*/
static bool sccb_is_available(struct i2c_adapter *adap)
{
u32 needed_funcs = I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA;

/*
* If we ever want support for hardware doing SCCB natively, we will
* introduce a sccb_xfer() callback to struct i2c_algorithm and check
* for it here.
*/

return (i2c_get_functionality(adap) & needed_funcs) == needed_funcs;
}

/**
* regmap_sccb_read - Read data from SCCB slave device
* @context: Device that will be interacted with
* @reg: Register to be read from
* @val: Pointer to store read value
*
* This executes the 2-phase write transmission cycle that is followed by a
* 2-phase read transmission cycle, returning negative errno else zero on
* success.
*/
static int regmap_sccb_read(void *context, unsigned int reg, unsigned int *val)
{
struct device *dev = context;
struct i2c_client *i2c = to_i2c_client(dev);
int ret;
union i2c_smbus_data data;

i2c_lock_bus(i2c->adapter, I2C_LOCK_SEGMENT);

ret = __i2c_smbus_xfer(i2c->adapter, i2c->addr, i2c->flags,
I2C_SMBUS_WRITE, reg, I2C_SMBUS_BYTE, NULL);
if (ret < 0)
goto out;

ret = __i2c_smbus_xfer(i2c->adapter, i2c->addr, i2c->flags,
I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &data);
if (ret < 0)
goto out;

*val = data.byte;
out:
i2c_unlock_bus(i2c->adapter, I2C_LOCK_SEGMENT);

return ret;
}

/**
* regmap_sccb_write - Write data to SCCB slave device
* @context: Device that will be interacted with
* @reg: Register to write to
* @val: Value to be written
*
* This executes the SCCB 3-phase write transmission cycle, returning negative
* errno else zero on success.
*/
static int regmap_sccb_write(void *context, unsigned int reg, unsigned int val)
{
struct device *dev = context;
struct i2c_client *i2c = to_i2c_client(dev);

return i2c_smbus_write_byte_data(i2c, reg, val);
}

static struct regmap_bus regmap_sccb_bus = {
.reg_write = regmap_sccb_write,
.reg_read = regmap_sccb_read,
};

static const struct regmap_bus *regmap_get_sccb_bus(struct i2c_client *i2c,
const struct regmap_config *config)
{
if (config->val_bits == 8 && config->reg_bits == 8 &&
sccb_is_available(i2c->adapter))
return &regmap_sccb_bus;

return ERR_PTR(-ENOTSUPP);
}

struct regmap *__regmap_init_sccb(struct i2c_client *i2c,
const struct regmap_config *config,
struct lock_class_key *lock_key,
const char *lock_name)
{
const struct regmap_bus *bus = regmap_get_sccb_bus(i2c, config);

if (IS_ERR(bus))
return ERR_CAST(bus);

return __regmap_init(&i2c->dev, bus, &i2c->dev, config,
lock_key, lock_name);
}
EXPORT_SYMBOL_GPL(__regmap_init_sccb);

struct regmap *__devm_regmap_init_sccb(struct i2c_client *i2c,
const struct regmap_config *config,
struct lock_class_key *lock_key,
const char *lock_name)
{
const struct regmap_bus *bus = regmap_get_sccb_bus(i2c, config);

if (IS_ERR(bus))
return ERR_CAST(bus);

return __devm_regmap_init(&i2c->dev, bus, &i2c->dev, config,
lock_key, lock_name);
}
EXPORT_SYMBOL_GPL(__devm_regmap_init_sccb);

MODULE_LICENSE("GPL v2");
23 changes: 7 additions & 16 deletions drivers/base/regmap/regmap-slimbus.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,24 @@

#include "internal.h"

static int regmap_slimbus_byte_reg_read(void *context, unsigned int reg,
unsigned int *val)
static int regmap_slimbus_write(void *context, const void *data, size_t count)
{
struct slim_device *sdev = context;
int v;

v = slim_readb(sdev, reg);

if (v < 0)
return v;

*val = v;

return 0;
return slim_write(sdev, *(u16 *)data, count - 2, (u8 *)data + 2);
}

static int regmap_slimbus_byte_reg_write(void *context, unsigned int reg,
unsigned int val)
static int regmap_slimbus_read(void *context, const void *reg, size_t reg_size,
void *val, size_t val_size)
{
struct slim_device *sdev = context;

return slim_writeb(sdev, reg, val);
return slim_read(sdev, *(u16 *)reg, val_size, val);
}

static struct regmap_bus regmap_slimbus_bus = {
.reg_write = regmap_slimbus_byte_reg_write,
.reg_read = regmap_slimbus_byte_reg_read,
.write = regmap_slimbus_write,
.read = regmap_slimbus_read,
.reg_format_endian_default = REGMAP_ENDIAN_LITTLE,
.val_format_endian_default = REGMAP_ENDIAN_LITTLE,
};
Expand Down
79 changes: 78 additions & 1 deletion drivers/base/regmap/regmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,17 @@ bool regmap_precious(struct regmap *map, unsigned int reg)
return false;
}

bool regmap_readable_noinc(struct regmap *map, unsigned int reg)
{
if (map->readable_noinc_reg)
return map->readable_noinc_reg(map->dev, reg);

if (map->rd_noinc_table)
return regmap_check_range_table(map, reg, map->rd_noinc_table);

return true;
}

static bool regmap_volatile_range(struct regmap *map, unsigned int reg,
size_t num)
{
Expand Down Expand Up @@ -766,10 +777,12 @@ struct regmap *__regmap_init(struct device *dev,
map->rd_table = config->rd_table;
map->volatile_table = config->volatile_table;
map->precious_table = config->precious_table;
map->rd_noinc_table = config->rd_noinc_table;
map->writeable_reg = config->writeable_reg;
map->readable_reg = config->readable_reg;
map->volatile_reg = config->volatile_reg;
map->precious_reg = config->precious_reg;
map->readable_noinc_reg = config->readable_noinc_reg;
map->cache_type = config->cache_type;

spin_lock_init(&map->async_lock);
Expand Down Expand Up @@ -1285,6 +1298,7 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
map->readable_reg = config->readable_reg;
map->volatile_reg = config->volatile_reg;
map->precious_reg = config->precious_reg;
map->readable_noinc_reg = config->readable_noinc_reg;
map->cache_type = config->cache_type;

regmap_debugfs_init(map, config->name);
Expand Down Expand Up @@ -2564,7 +2578,70 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
EXPORT_SYMBOL_GPL(regmap_raw_read);

/**
* regmap_field_read() - Read a value to a single register field
* regmap_noinc_read(): Read data from a register without incrementing the
* register number
*
* @map: Register map to read from
* @reg: Register to read from
* @val: Pointer to data buffer
* @val_len: Length of output buffer in bytes.
*
* The regmap API usually assumes that bulk bus read operations will read a
* range of registers. Some devices have certain registers for which a read
* operation read will read from an internal FIFO.
*
* The target register must be volatile but registers after it can be
* completely unrelated cacheable registers.
*
* This will attempt multiple reads as required to read val_len bytes.
*
* A value of zero will be returned on success, a negative errno will be
* returned in error cases.
*/
int regmap_noinc_read(struct regmap *map, unsigned int reg,
void *val, size_t val_len)
{
size_t read_len;
int ret;

if (!map->bus)
return -EINVAL;
if (!map->bus->read)
return -ENOTSUPP;
if (val_len % map->format.val_bytes)
return -EINVAL;
if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL;
if (val_len == 0)
return -EINVAL;

map->lock(map->lock_arg);

if (!regmap_volatile(map, reg) || !regmap_readable_noinc(map, reg)) {
ret = -EINVAL;
goto out_unlock;
}

while (val_len) {
if (map->max_raw_read && map->max_raw_read < val_len)
read_len = map->max_raw_read;
else
read_len = val_len;
ret = _regmap_raw_read(map, reg, val, read_len);
if (ret)
goto out_unlock;
val = ((u8 *)val) + read_len;
val_len -= read_len;
}

out_unlock:
map->unlock(map->lock_arg);
return ret;
}
EXPORT_SYMBOL_GPL(regmap_noinc_read);

/**
* regmap_field_read(): Read a value to a single register field
*
* @field: Register field to read from
* @val: Pointer to store read value
Expand Down
28 changes: 20 additions & 8 deletions drivers/i2c/i2c-core-smbus.c
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
msg[num-1].len++;
}

status = i2c_transfer(adapter, msg, num);
status = __i2c_transfer(adapter, msg, num);
if (status < 0)
goto cleanup;
if (status != num) {
Expand Down Expand Up @@ -524,9 +524,24 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
* This executes an SMBus protocol operation, and returns a negative
* errno code else zero on success.
*/
s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
char read_write, u8 command, int protocol,
union i2c_smbus_data *data)
s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
unsigned short flags, char read_write,
u8 command, int protocol, union i2c_smbus_data *data)
{
s32 res;

i2c_lock_bus(adapter, I2C_LOCK_SEGMENT);
res = __i2c_smbus_xfer(adapter, addr, flags, read_write,
command, protocol, data);
i2c_unlock_bus(adapter, I2C_LOCK_SEGMENT);

return res;
}
EXPORT_SYMBOL(i2c_smbus_xfer);

s32 __i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
unsigned short flags, char read_write,
u8 command, int protocol, union i2c_smbus_data *data)
{
unsigned long orig_jiffies;
int try;
Expand All @@ -543,8 +558,6 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
flags &= I2C_M_TEN | I2C_CLIENT_PEC | I2C_CLIENT_SCCB;

if (adapter->algo->smbus_xfer) {
i2c_lock_bus(adapter, I2C_LOCK_SEGMENT);

/* Retry automatically on arbitration loss */
orig_jiffies = jiffies;
for (res = 0, try = 0; try <= adapter->retries; try++) {
Expand All @@ -557,7 +570,6 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
orig_jiffies + adapter->timeout))
break;
}
i2c_unlock_bus(adapter, I2C_LOCK_SEGMENT);

if (res != -EOPNOTSUPP || !adapter->algo->master_xfer)
goto trace;
Expand All @@ -579,7 +591,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,

return res;
}
EXPORT_SYMBOL(i2c_smbus_xfer);
EXPORT_SYMBOL(__i2c_smbus_xfer);

/**
* i2c_smbus_read_i2c_block_data_or_emulated - read block or emulate
Expand Down
11 changes: 8 additions & 3 deletions include/linux/i2c.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,14 @@ extern int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
and probably just as fast.
Note that we use i2c_adapter here, because you do not need a specific
smbus adapter to call this function. */
extern s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
unsigned short flags, char read_write, u8 command,
int size, union i2c_smbus_data *data);
s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
unsigned short flags, char read_write, u8 command,
int protocol, union i2c_smbus_data *data);

/* Unlocked flavor */
s32 __i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
unsigned short flags, char read_write, u8 command,
int protocol, union i2c_smbus_data *data);

/* Now follow the 'nice' access routines. These also document the calling
conventions of i2c_smbus_xfer. */
Expand Down
Loading

0 comments on commit 1dce5d8

Please sign in to comment.