Skip to content
This repository has been archived by the owner on Aug 27, 2022. It is now read-only.

Commit

Permalink
Merge tag 'regmap-v3.16' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/broonie/regmap into next

Pull regmap updates from Mark Brown:
 "Another fairly quiet release, a few bug fixes and a couple of new
  features:

   - support for I2C devices connected to SMBus rather than full I2C
     controllers contributed by Boris Brezillon.  If the controller is
     only capable of SMBus operation the framework will transparently
     fall back to that

   - suport for little endian values, contributed by Xiubo Li"

* tag 'regmap-v3.16' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap:
  regmap: mmio: Fix regmap_mmio_write for uneven counts
  regmap: irq: Fix possible ZERO_SIZE_PTR pointer dereferencing error.
  regmap: Add missing initialization of this_page
  regmap: Fix possible ZERO_SIZE_PTR pointer dereferencing error.
  regmap: i2c: fallback to SMBus if the adapter does not support standard I2C
  regmap: add reg_read/reg_write callbacks to regmap_bus struct
  regmap: rbtree: improve 64bits memory alignment
  regmap: mmio: Fix the bug of 'offset' value parsing.
  regmap: implement LE formatting/parsing for 16/32-bit values.
  • Loading branch information
torvalds committed Jun 3, 2014
2 parents bd698cf + ef98ae4 commit de6b25d
Show file tree
Hide file tree
Showing 6 changed files with 227 additions and 18 deletions.
8 changes: 4 additions & 4 deletions drivers/base/regmap/regcache-rbtree.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,16 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
static int regcache_rbtree_exit(struct regmap *map);

struct regcache_rbtree_node {
/* the actual rbtree node holding this block */
struct rb_node node;
/* base register handled by this block */
unsigned int base_reg;
/* block of adjacent registers */
void *block;
/* Which registers are present */
long *cache_present;
/* base register handled by this block */
unsigned int base_reg;
/* number of registers available in the block */
unsigned int blklen;
/* the actual rbtree node holding this block */
struct rb_node node;
} __attribute__ ((packed));

struct regcache_rbtree_ctx {
Expand Down
104 changes: 102 additions & 2 deletions drivers/base/regmap/regmap-i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,79 @@
#include <linux/i2c.h>
#include <linux/module.h>


static int regmap_smbus_byte_reg_read(void *context, unsigned int reg,
unsigned int *val)
{
struct device *dev = context;
struct i2c_client *i2c = to_i2c_client(dev);
int ret;

if (reg > 0xff)
return -EINVAL;

ret = i2c_smbus_read_byte_data(i2c, reg);
if (ret < 0)
return ret;

*val = ret;

return 0;
}

static int regmap_smbus_byte_reg_write(void *context, unsigned int reg,
unsigned int val)
{
struct device *dev = context;
struct i2c_client *i2c = to_i2c_client(dev);

if (val > 0xff || reg > 0xff)
return -EINVAL;

return i2c_smbus_write_byte_data(i2c, reg, val);
}

static struct regmap_bus regmap_smbus_byte = {
.reg_write = regmap_smbus_byte_reg_write,
.reg_read = regmap_smbus_byte_reg_read,
};

static int regmap_smbus_word_reg_read(void *context, unsigned int reg,
unsigned int *val)
{
struct device *dev = context;
struct i2c_client *i2c = to_i2c_client(dev);
int ret;

if (reg > 0xff)
return -EINVAL;

ret = i2c_smbus_read_word_data(i2c, reg);
if (ret < 0)
return ret;

*val = ret;

return 0;
}

static int regmap_smbus_word_reg_write(void *context, unsigned int reg,
unsigned int val)
{
struct device *dev = context;
struct i2c_client *i2c = to_i2c_client(dev);

if (val > 0xffff || reg > 0xff)
return -EINVAL;

return i2c_smbus_write_word_data(i2c, reg, val);
}

static struct regmap_bus regmap_smbus_word = {
.reg_write = regmap_smbus_word_reg_write,
.reg_read = regmap_smbus_word_reg_read,
};

static int regmap_i2c_write(void *context, const void *data, size_t count)
{
struct device *dev = context;
Expand Down Expand Up @@ -97,6 +170,23 @@ static struct regmap_bus regmap_i2c = {
.read = regmap_i2c_read,
};

static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c,
const struct regmap_config *config)
{
if (i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C))
return &regmap_i2c;
else if (config->val_bits == 16 && config->reg_bits == 8 &&
i2c_check_functionality(i2c->adapter,
I2C_FUNC_SMBUS_WORD_DATA))
return &regmap_smbus_word;
else if (config->val_bits == 8 && config->reg_bits == 8 &&
i2c_check_functionality(i2c->adapter,
I2C_FUNC_SMBUS_BYTE_DATA))
return &regmap_smbus_byte;

return ERR_PTR(-ENOTSUPP);
}

/**
* regmap_init_i2c(): Initialise register map
*
Expand All @@ -109,7 +199,12 @@ static struct regmap_bus regmap_i2c = {
struct regmap *regmap_init_i2c(struct i2c_client *i2c,
const struct regmap_config *config)
{
return regmap_init(&i2c->dev, &regmap_i2c, &i2c->dev, config);
const struct regmap_bus *bus = regmap_get_i2c_bus(i2c, config);

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

return regmap_init(&i2c->dev, bus, &i2c->dev, config);
}
EXPORT_SYMBOL_GPL(regmap_init_i2c);

Expand All @@ -126,7 +221,12 @@ EXPORT_SYMBOL_GPL(regmap_init_i2c);
struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c,
const struct regmap_config *config)
{
return devm_regmap_init(&i2c->dev, &regmap_i2c, &i2c->dev, config);
const struct regmap_bus *bus = regmap_get_i2c_bus(i2c, config);

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

return devm_regmap_init(&i2c->dev, bus, &i2c->dev, config);
}
EXPORT_SYMBOL_GPL(devm_regmap_init_i2c);

Expand Down
9 changes: 6 additions & 3 deletions drivers/base/regmap/regmap-irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
* published by the Free Software Foundation.
*/

#include <linux/export.h>
#include <linux/device.h>
#include <linux/regmap.h>
#include <linux/irq.h>
#include <linux/export.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/slab.h>

#include "internal.h"
Expand Down Expand Up @@ -347,6 +347,9 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
int ret = -ENOMEM;
u32 reg;

if (chip->num_regs <= 0)
return -EINVAL;

for (i = 0; i < chip->num_irqs; i++) {
if (chip->irqs[i].reg_offset % map->reg_stride)
return -EINVAL;
Expand Down
35 changes: 27 additions & 8 deletions drivers/base/regmap/regmap-mmio.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,17 +61,36 @@ static int regmap_mmio_regbits_check(size_t reg_bits)
}
}

static inline void regmap_mmio_count_check(size_t count)
static inline void regmap_mmio_count_check(size_t count, u32 offset)
{
BUG_ON(count % 2 != 0);
BUG_ON(count <= offset);
}

static inline unsigned int
regmap_mmio_get_offset(const void *reg, size_t reg_size)
{
switch (reg_size) {
case 1:
return *(u8 *)reg;
case 2:
return *(u16 *)reg;
case 4:
return *(u32 *)reg;
#ifdef CONFIG_64BIT
case 8:
return *(u64 *)reg;
#endif
default:
BUG();
}
}

static int regmap_mmio_gather_write(void *context,
const void *reg, size_t reg_size,
const void *val, size_t val_size)
{
struct regmap_mmio_context *ctx = context;
u32 offset;
unsigned int offset;
int ret;

regmap_mmio_regsize_check(reg_size);
Expand All @@ -82,7 +101,7 @@ static int regmap_mmio_gather_write(void *context,
return ret;
}

offset = *(u32 *)reg;
offset = regmap_mmio_get_offset(reg, reg_size);

while (val_size) {
switch (ctx->val_bytes) {
Expand Down Expand Up @@ -118,9 +137,9 @@ static int regmap_mmio_gather_write(void *context,
static int regmap_mmio_write(void *context, const void *data, size_t count)
{
struct regmap_mmio_context *ctx = context;
u32 offset = ctx->reg_bytes + ctx->pad_bytes;
unsigned int offset = ctx->reg_bytes + ctx->pad_bytes;

regmap_mmio_count_check(count);
regmap_mmio_count_check(count, offset);

return regmap_mmio_gather_write(context, data, ctx->reg_bytes,
data + offset, count - offset);
Expand All @@ -131,7 +150,7 @@ static int regmap_mmio_read(void *context,
void *val, size_t val_size)
{
struct regmap_mmio_context *ctx = context;
u32 offset;
unsigned int offset;
int ret;

regmap_mmio_regsize_check(reg_size);
Expand All @@ -142,7 +161,7 @@ static int regmap_mmio_read(void *context,
return ret;
}

offset = *(u32 *)reg;
offset = regmap_mmio_get_offset(reg, reg_size);

while (val_size) {
switch (ctx->val_bytes) {
Expand Down
Loading

0 comments on commit de6b25d

Please sign in to comment.