Commit e81b594c authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'regmap-v4.3' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap

Pull regmap updates from Mark Brown:
 "This has been a busy release for regmap.

  By far the biggest set of changes here are those from Markus Pargmann
  which implement support for block transfers in smbus devices.  This
  required quite a bit of refactoring but leaves us better able to
  handle odd restrictions that controllers may have and with better
  performance on smbus.

  Other new features include:

   - Fix interactions with lockdep for nested regmaps (eg, when a device
     using regmap is connected to a bus where the bus controller has a
     separate regmap).  Lockdep's default class identification is too
     crude to work without help.

   - Support for must write bitfield operations, useful for operations
     which require writing a bit to trigger them from Kuniori Morimoto.

   - Support for delaying during register patch application from Nariman
     Poushin.

   - Support for overriding cache state via the debugfs implementation
     from Richard Fitzgerald"

* tag 'regmap-v4.3' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap: (25 commits)
  regmap: fix a NULL pointer dereference in __regmap_init
  regmap: Support bulk reads for devices without raw formatting
  regmap-i2c: Add smbus i2c block support
  regmap: Add raw_write/read checks for max_raw_write/read sizes
  regmap: regmap max_raw_read/write getter functions
  regmap: Introduce max_raw_read/write for regmap_bulk_read/write
  regmap: Add missing comments about struct regmap_bus
  regmap: No multi_write support if bus->write does not exist
  regmap: Split use_single_rw internally into use_single_read/write
  regmap: Fix regmap_bulk_write for bus writes
  regmap: regmap_raw_read return error on !bus->read
  regulator: core: Print at debug level on debugfs creation failure
  regmap: Fix regmap_can_raw_write check
  regmap: fix typos in regmap.c
  regmap: Fix integertypes for register address and value
  regmap: Move documentation to regmap.h
  regmap: Use different lockdep class for each regmap init call
  thermal: sti: Add parentheses around bridge->ops->regmap_init call
  mfd: vexpress: Add parentheses around bridge->ops->regmap_init call
  regmap: debugfs: Fix misuse of IS_ENABLED
  ...
parents fa815580 072502a6
...@@ -139,11 +139,17 @@ struct regmap { ...@@ -139,11 +139,17 @@ struct regmap {
struct reg_sequence *patch; struct reg_sequence *patch;
int patch_regs; int patch_regs;
/* if set, converts bulk rw to single rw */ /* if set, converts bulk read to single read */
bool use_single_rw; bool use_single_read;
/* if set, converts bulk read to single read */
bool use_single_write;
/* if set, the device supports multi write mode */ /* if set, the device supports multi write mode */
bool can_multi_write; bool can_multi_write;
/* if set, raw reads/writes are limited to this size */
size_t max_raw_read;
size_t max_raw_write;
struct rb_root range_tree; struct rb_root range_tree;
void *selector_work_buf; /* Scratch buffer used for selector */ void *selector_work_buf; /* Scratch buffer used for selector */
}; };
......
...@@ -729,7 +729,7 @@ int regcache_sync_block(struct regmap *map, void *block, ...@@ -729,7 +729,7 @@ int regcache_sync_block(struct regmap *map, void *block,
unsigned int block_base, unsigned int start, unsigned int block_base, unsigned int start,
unsigned int end) unsigned int end)
{ {
if (regmap_can_raw_write(map) && !map->use_single_rw) if (regmap_can_raw_write(map) && !map->use_single_write)
return regcache_sync_block_raw(map, block, cache_present, return regcache_sync_block_raw(map, block, cache_present,
block_base, start, end); block_base, start, end);
else else
......
...@@ -78,37 +78,24 @@ static const struct regmap_bus ac97_regmap_bus = { ...@@ -78,37 +78,24 @@ static const struct regmap_bus ac97_regmap_bus = {
.reg_read = regmap_ac97_reg_read, .reg_read = regmap_ac97_reg_read,
}; };
/** struct regmap *__regmap_init_ac97(struct snd_ac97 *ac97,
* regmap_init_ac97(): Initialise AC'97 register map const struct regmap_config *config,
* struct lock_class_key *lock_key,
* @ac97: Device that will be interacted with const char *lock_name)
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer to
* a struct regmap.
*/
struct regmap *regmap_init_ac97(struct snd_ac97 *ac97,
const struct regmap_config *config)
{ {
return regmap_init(&ac97->dev, &ac97_regmap_bus, ac97, config); return __regmap_init(&ac97->dev, &ac97_regmap_bus, ac97, config,
lock_key, lock_name);
} }
EXPORT_SYMBOL_GPL(regmap_init_ac97); EXPORT_SYMBOL_GPL(__regmap_init_ac97);
/** struct regmap *__devm_regmap_init_ac97(struct snd_ac97 *ac97,
* devm_regmap_init_ac97(): Initialise AC'97 register map const struct regmap_config *config,
* struct lock_class_key *lock_key,
* @ac97: Device that will be interacted with const char *lock_name)
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer
* to a struct regmap. The regmap will be automatically freed by the
* device management code.
*/
struct regmap *devm_regmap_init_ac97(struct snd_ac97 *ac97,
const struct regmap_config *config)
{ {
return devm_regmap_init(&ac97->dev, &ac97_regmap_bus, ac97, config); return __devm_regmap_init(&ac97->dev, &ac97_regmap_bus, ac97, config,
lock_key, lock_name);
} }
EXPORT_SYMBOL_GPL(devm_regmap_init_ac97); EXPORT_SYMBOL_GPL(__devm_regmap_init_ac97);
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
...@@ -469,6 +469,87 @@ static const struct file_operations regmap_access_fops = { ...@@ -469,6 +469,87 @@ static const struct file_operations regmap_access_fops = {
.llseek = default_llseek, .llseek = default_llseek,
}; };
static ssize_t regmap_cache_only_write_file(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct regmap *map = container_of(file->private_data,
struct regmap, cache_only);
ssize_t result;
bool was_enabled, require_sync = false;
int err;
map->lock(map->lock_arg);
was_enabled = map->cache_only;
result = debugfs_write_file_bool(file, user_buf, count, ppos);
if (result < 0) {
map->unlock(map->lock_arg);
return result;
}
if (map->cache_only && !was_enabled) {
dev_warn(map->dev, "debugfs cache_only=Y forced\n");
add_taint(TAINT_USER, LOCKDEP_STILL_OK);
} else if (!map->cache_only && was_enabled) {
dev_warn(map->dev, "debugfs cache_only=N forced: syncing cache\n");
require_sync = true;
}
map->unlock(map->lock_arg);
if (require_sync) {
err = regcache_sync(map);
if (err)
dev_err(map->dev, "Failed to sync cache %d\n", err);
}
return result;
}
static const struct file_operations regmap_cache_only_fops = {
.open = simple_open,
.read = debugfs_read_file_bool,
.write = regmap_cache_only_write_file,
};
static ssize_t regmap_cache_bypass_write_file(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct regmap *map = container_of(file->private_data,
struct regmap, cache_bypass);
ssize_t result;
bool was_enabled;
map->lock(map->lock_arg);
was_enabled = map->cache_bypass;
result = debugfs_write_file_bool(file, user_buf, count, ppos);
if (result < 0)
goto out;
if (map->cache_bypass && !was_enabled) {
dev_warn(map->dev, "debugfs cache_bypass=Y forced\n");
add_taint(TAINT_USER, LOCKDEP_STILL_OK);
} else if (!map->cache_bypass && was_enabled) {
dev_warn(map->dev, "debugfs cache_bypass=N forced\n");
}
out:
map->unlock(map->lock_arg);
return result;
}
static const struct file_operations regmap_cache_bypass_fops = {
.open = simple_open,
.read = debugfs_read_file_bool,
.write = regmap_cache_bypass_write_file,
};
void regmap_debugfs_init(struct regmap *map, const char *name) void regmap_debugfs_init(struct regmap *map, const char *name)
{ {
struct rb_node *next; struct rb_node *next;
...@@ -518,10 +599,11 @@ void regmap_debugfs_init(struct regmap *map, const char *name) ...@@ -518,10 +599,11 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
if (map->max_register || regmap_readable(map, 0)) { if (map->max_register || regmap_readable(map, 0)) {
umode_t registers_mode; umode_t registers_mode;
if (IS_ENABLED(REGMAP_ALLOW_WRITE_DEBUGFS)) #if defined(REGMAP_ALLOW_WRITE_DEBUGFS)
registers_mode = 0600; registers_mode = 0600;
else #else
registers_mode = 0400; registers_mode = 0400;
#endif
debugfs_create_file("registers", registers_mode, map->debugfs, debugfs_create_file("registers", registers_mode, map->debugfs,
map, &regmap_map_fops); map, &regmap_map_fops);
...@@ -530,12 +612,13 @@ void regmap_debugfs_init(struct regmap *map, const char *name) ...@@ -530,12 +612,13 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
} }
if (map->cache_type) { if (map->cache_type) {
debugfs_create_bool("cache_only", 0400, map->debugfs, debugfs_create_file("cache_only", 0600, map->debugfs,
&map->cache_only); &map->cache_only, &regmap_cache_only_fops);
debugfs_create_bool("cache_dirty", 0400, map->debugfs, debugfs_create_bool("cache_dirty", 0400, map->debugfs,
&map->cache_dirty); &map->cache_dirty);
debugfs_create_bool("cache_bypass", 0400, map->debugfs, debugfs_create_file("cache_bypass", 0600, map->debugfs,
&map->cache_bypass); &map->cache_bypass,
&regmap_cache_bypass_fops);
} }
next = rb_first(&map->range_tree); next = rb_first(&map->range_tree);
......
...@@ -209,11 +209,60 @@ static struct regmap_bus regmap_i2c = { ...@@ -209,11 +209,60 @@ static struct regmap_bus regmap_i2c = {
.val_format_endian_default = REGMAP_ENDIAN_BIG, .val_format_endian_default = REGMAP_ENDIAN_BIG,
}; };
static int regmap_i2c_smbus_i2c_write(void *context, const void *data,
size_t count)
{
struct device *dev = context;
struct i2c_client *i2c = to_i2c_client(dev);
if (count < 1)
return -EINVAL;
if (count >= I2C_SMBUS_BLOCK_MAX)
return -E2BIG;
--count;
return i2c_smbus_write_i2c_block_data(i2c, ((u8 *)data)[0], count,
((u8 *)data + 1));
}
static int regmap_i2c_smbus_i2c_read(void *context, const void *reg,
size_t reg_size, void *val,
size_t val_size)
{
struct device *dev = context;
struct i2c_client *i2c = to_i2c_client(dev);
int ret;
if (reg_size != 1 || val_size < 1)
return -EINVAL;
if (val_size >= I2C_SMBUS_BLOCK_MAX)
return -E2BIG;
ret = i2c_smbus_read_i2c_block_data(i2c, ((u8 *)reg)[0], val_size, val);
if (ret == val_size)
return 0;
else if (ret < 0)
return ret;
else
return -EIO;
}
static struct regmap_bus regmap_i2c_smbus_i2c_block = {
.write = regmap_i2c_smbus_i2c_write,
.read = regmap_i2c_smbus_i2c_read,
.max_raw_read = I2C_SMBUS_BLOCK_MAX,
.max_raw_write = I2C_SMBUS_BLOCK_MAX,
};
static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c, static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c,
const struct regmap_config *config) const struct regmap_config *config)
{ {
if (i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) if (i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C))
return &regmap_i2c; return &regmap_i2c;
else if (config->reg_bits == 8 &&
i2c_check_functionality(i2c->adapter,
I2C_FUNC_SMBUS_I2C_BLOCK))
return &regmap_i2c_smbus_i2c_block;
else if (config->val_bits == 16 && config->reg_bits == 8 && else if (config->val_bits == 16 && config->reg_bits == 8 &&
i2c_check_functionality(i2c->adapter, i2c_check_functionality(i2c->adapter,
I2C_FUNC_SMBUS_WORD_DATA)) I2C_FUNC_SMBUS_WORD_DATA))
...@@ -233,47 +282,34 @@ static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c, ...@@ -233,47 +282,34 @@ static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c,
return ERR_PTR(-ENOTSUPP); return ERR_PTR(-ENOTSUPP);
} }
/** struct regmap *__regmap_init_i2c(struct i2c_client *i2c,
* regmap_init_i2c(): Initialise register map const struct regmap_config *config,
* struct lock_class_key *lock_key,
* @i2c: Device that will be interacted with const char *lock_name)
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer to
* a struct regmap.
*/
struct regmap *regmap_init_i2c(struct i2c_client *i2c,
const struct regmap_config *config)
{ {
const struct regmap_bus *bus = regmap_get_i2c_bus(i2c, config); const struct regmap_bus *bus = regmap_get_i2c_bus(i2c, config);
if (IS_ERR(bus)) if (IS_ERR(bus))
return ERR_CAST(bus); return ERR_CAST(bus);
return regmap_init(&i2c->dev, bus, &i2c->dev, config); return __regmap_init(&i2c->dev, bus, &i2c->dev, config,
lock_key, lock_name);
} }
EXPORT_SYMBOL_GPL(regmap_init_i2c); EXPORT_SYMBOL_GPL(__regmap_init_i2c);
/** struct regmap *__devm_regmap_init_i2c(struct i2c_client *i2c,
* devm_regmap_init_i2c(): Initialise managed register map const struct regmap_config *config,
* struct lock_class_key *lock_key,
* @i2c: Device that will be interacted with const char *lock_name)
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer
* to a struct regmap. The regmap will be automatically freed by the
* device management code.
*/
struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c,
const struct regmap_config *config)
{ {
const struct regmap_bus *bus = regmap_get_i2c_bus(i2c, config); const struct regmap_bus *bus = regmap_get_i2c_bus(i2c, config);
if (IS_ERR(bus)) if (IS_ERR(bus))
return ERR_CAST(bus); return ERR_CAST(bus);
return devm_regmap_init(&i2c->dev, bus, &i2c->dev, config); return __devm_regmap_init(&i2c->dev, bus, &i2c->dev, config,
lock_key, lock_name);
} }
EXPORT_SYMBOL_GPL(devm_regmap_init_i2c); EXPORT_SYMBOL_GPL(__devm_regmap_init_i2c);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -209,7 +209,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) ...@@ -209,7 +209,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
* Read in the statuses, using a single bulk read if possible * Read in the statuses, using a single bulk read if possible
* in order to reduce the I/O overheads. * in order to reduce the I/O overheads.
*/ */
if (!map->use_single_rw && map->reg_stride == 1 && if (!map->use_single_read && map->reg_stride == 1 &&
data->irq_reg_stride == 1) { data->irq_reg_stride == 1) {
u8 *buf8 = data->status_reg_buf; u8 *buf8 = data->status_reg_buf;
u16 *buf16 = data->status_reg_buf; u16 *buf16 = data->status_reg_buf;
...@@ -398,7 +398,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, ...@@ -398,7 +398,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
else else
d->irq_reg_stride = 1; d->irq_reg_stride = 1;
if (!map->use_single_rw && map->reg_stride == 1 && if (!map->use_single_read && map->reg_stride == 1 &&
d->irq_reg_stride == 1) { d->irq_reg_stride == 1) {
d->status_reg_buf = kmalloc(map->format.val_bytes * d->status_reg_buf = kmalloc(map->format.val_bytes *
chip->num_regs, GFP_KERNEL); chip->num_regs, GFP_KERNEL);
......
...@@ -296,20 +296,11 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, ...@@ -296,20 +296,11 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
return ERR_PTR(ret); return ERR_PTR(ret);
} }
/** struct regmap *__regmap_init_mmio_clk(struct device *dev, const char *clk_id,
* regmap_init_mmio_clk(): Initialise register map with register clock
*
* @dev: Device that will be interacted with
* @clk_id: register clock consumer ID
* @regs: Pointer to memory-mapped IO region
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer to
* a struct regmap.
*/
struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id,
void __iomem *regs, void __iomem *regs,
const struct regmap_config *config) const struct regmap_config *config,
struct lock_class_key *lock_key,
const char *lock_name)
{ {
struct regmap_mmio_context *ctx; struct regmap_mmio_context *ctx;
...@@ -317,25 +308,17 @@ struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id, ...@@ -317,25 +308,17 @@ struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id,
if (IS_ERR(ctx)) if (IS_ERR(ctx))
return ERR_CAST(ctx); return ERR_CAST(ctx);
return regmap_init(dev, &regmap_mmio, ctx, config); return __regmap_init(dev, &regmap_mmio, ctx, config,
lock_key, lock_name);
} }
EXPORT_SYMBOL_GPL(regmap_init_mmio_clk); EXPORT_SYMBOL_GPL(__regmap_init_mmio_clk);
/** struct regmap *__devm_regmap_init_mmio_clk(struct device *dev,
* devm_regmap_init_mmio_clk(): Initialise managed register map with clock const char *clk_id,
*
* @dev: Device that will be interacted with
* @clk_id: register clock consumer ID
* @regs: Pointer to memory-mapped IO region
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer
* to a struct regmap. The regmap will be automatically freed by the
* device management code.
*/
struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id,
void __iomem *regs, void __iomem *regs,
const struct regmap_config *config) const struct regmap_config *config,
struct lock_class_key *lock_key,
const char *lock_name)
{ {
struct regmap_mmio_context *ctx; struct regmap_mmio_context *ctx;
...@@ -343,8 +326,9 @@ struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id, ...@@ -343,8 +326,9 @@ struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id,
if (IS_ERR(ctx)) if (IS_ERR(ctx))
return ERR_CAST(ctx); return ERR_CAST(ctx);
return devm_regmap_init(dev, &regmap_mmio, ctx, config); return __devm_regmap_init(dev, &regmap_mmio, ctx, config,
lock_key, lock_name);
} }
EXPORT_SYMBOL_GPL(devm_regmap_init_mmio_clk); EXPORT_SYMBOL_GPL(__devm_regmap_init_mmio_clk);
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
...@@ -113,37 +113,24 @@ static struct regmap_bus regmap_spi = { ...@@ -113,37 +113,24 @@ static struct regmap_bus regmap_spi = {
.val_format_endian_default = REGMAP_ENDIAN_BIG, .val_format_endian_default = REGMAP_ENDIAN_BIG,
}; };
/** struct regmap *__regmap_init_spi(struct spi_device *spi,
* regmap_init_spi(): Initialise register map const struct regmap_config *config,
* struct lock_class_key *lock_key,
* @spi: Device that will be interacted with const char *lock_name)
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer to
* a struct regmap.
*/
struct regmap *regmap_init_spi(struct spi_device *spi,
const struct regmap_config *config)
{ {
return regmap_init(&spi->dev, &regmap_spi, &spi->dev, config); return __regmap_init(&spi->dev, &regmap_spi, &spi->dev, config,
lock_key, lock_name);
} }
EXPORT_SYMBOL_GPL(regmap_init_spi); EXPORT_SYMBOL_GPL(__regmap_init_spi);
/** struct regmap *__devm_regmap_init_spi(struct spi_device *spi,
* devm_regmap_init_spi(): Initialise register map const struct regmap_config *config,
* struct lock_class_key *lock_key,
* @spi: Device that will be interacted with const char *lock_name)
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer
* to a struct regmap. The map will be automatically freed by the
* device management code.
*/
struct regmap *devm_regmap_init_spi(struct spi_device *spi,
const struct regmap_config *config)
{ {
return devm_regmap_init(&spi->dev, &regmap_spi, &spi->dev, config); return __devm_regmap_init(&spi->dev, &regmap_spi, &spi->dev, config,
lock_key, lock_name);
} }
EXPORT_SYMBOL_GPL(devm_regmap_init_spi); EXPORT_SYMBOL_GPL(__devm_regmap_init_spi);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -91,36 +91,25 @@ static struct regmap_bus regmap_spmi_base = { ...@@ -91,36 +91,25 @@ static struct regmap_bus regmap_spmi_base = {
.val_format_endian_default = REGMAP_ENDIAN_NATIVE, .val_format_endian_default = REGMAP_ENDIAN_NATIVE,
}; };
/** struct regmap *__regmap_init_spmi_base(struct spmi_device *sdev,
* regmap_init_spmi_base(): Create regmap for the Base register space const struct regmap_config *config,
* @sdev: SPMI device that will be interacted with struct lock_class_key *lock_key,
* @config: Configuration for register map const char *lock_name)
*
* The return value will be an ERR_PTR() on error or a valid pointer to
* a struct regmap.
*/
struct regmap *regmap_init_spmi_base(struct spmi_device *sdev,
const struct regmap_config *config)
{ {
return regmap_init(&sdev->dev, &regmap_spmi_base, sdev, config); return __regmap_init(&sdev->dev, &regmap_spmi_base, sdev, config,
lock_key, lock_name);
} }
EXPORT_SYMBOL_GPL(regmap_init_spmi_base); EXPORT_SYMBOL_GPL(__regmap_init_spmi_base);
/** struct regmap *__devm_regmap_init_spmi_base(struct spmi_device *sdev,
* devm_regmap_init_spmi_base(): Create managed regmap for Base register space const struct regmap_config *config,
* @sdev: SPMI device that will be interacted with struct lock_class_key *lock_key,
* @config: Configuration for register map const char *lock_name)
*
* The return value will be an ERR_PTR() on error or a valid pointer
* to a struct regmap. The regmap will be automatically freed by the
* device management code.
*/
struct regmap *devm_regmap_init_spmi_base(struct spmi_device *sdev,
const struct regmap_config *config)
{ {
return devm_regmap_init(&sdev->dev, &regmap_spmi_base, sdev, config); return __devm_regmap_init(&sdev->dev, &regmap_spmi_base, sdev, config,
lock_key, lock_name);
} }
EXPORT_SYMBOL_GPL(devm_regmap_init_spmi_base); EXPORT_SYMBOL_GPL(__devm_regmap_init_spmi_base);
static int regmap_spmi_ext_read(void *context, static int regmap_spmi_ext_read(void *context,
const void *reg, size_t reg_size, const void *reg, size_t reg_size,
...@@ -222,35 +211,24 @@ static struct regmap_bus regmap_spmi_ext = { ...@@ -222,35 +211,24 @@ static struct regmap_bus regmap_spmi_ext = {
.val_format_endian_default = REGMAP_ENDIAN_NATIVE, .val_format_endian_default = REGMAP_ENDIAN_NATIVE,
}; };
/** struct regmap *__regmap_init_spmi_ext(struct spmi_device *sdev,
* regmap_init_spmi_ext(): Create regmap for Ext register space const struct regmap_config *config,
* @sdev: Device that will be interacted with struct lock_class_key *lock_key,
* @config: Configuration for register map const char *lock_name)
*
* The return value will be an ERR_PTR() on error or a valid pointer to
* a struct regmap.
*/
struct regmap *regmap_init_spmi_ext(struct spmi_device *sdev,
const struct regmap_config *config)
{ {
return regmap_init(&sdev->dev, &regmap_spmi_ext, sdev, config); return __regmap_init(&sdev->dev, &regmap_spmi_ext, sdev, config,
lock_key, lock_name);
} }
EXPORT_SYMBOL_GPL(regmap_init_spmi_ext); EXPORT_SYMBOL_GPL(__regmap_init_spmi_ext);
/** struct regmap *__devm_regmap_init_spmi_ext(struct spmi_device *sdev,
* devm_regmap_init_spmi_ext(): Create managed regmap for Ext register space const struct regmap_config *config,
* @sdev: SPMI device that will be interacted with struct lock_class_key *lock_key,
* @config: Configuration for register map const char *lock_name)
*
* The return value will be an ERR_PTR() on error or a valid pointer
* to a struct regmap. The regmap will be automatically freed by the
* device management code.
*/
struct regmap *devm_regmap_init_spmi_ext(struct spmi_device *sdev,
const struct regmap_config *config)
{ {
return devm_regmap_init(&sdev->dev, &regmap_spmi_ext, sdev, config); return __devm_regmap_init(&sdev->dev, &regmap_spmi_ext, sdev, config,
lock_key, lock_name);
} }
EXPORT_SYMBOL_GPL(devm_regmap_init_spmi_ext); EXPORT_SYMBOL_GPL(__devm_regmap_init_spmi_ext);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/rbtree.h> #include <linux/rbtree.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/delay.h>
#define CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS
#include "trace.h" #include "trace.h"
...@@ -93,6 +94,9 @@ bool regmap_writeable(struct regmap *map, unsigned int reg) ...@@ -93,6 +94,9 @@ bool regmap_writeable(struct regmap *map, unsigned int reg)
bool regmap_readable(struct regmap *map, unsigned int reg) bool regmap_readable(struct regmap *map, unsigned int reg)
{ {
if (!map->reg_read)
return false;
if (map->max_register && reg > map->max_register) if (map->max_register && reg > map->max_register)
return false; return false;
...@@ -515,22 +519,12 @@ enum regmap_endian regmap_get_val_endian(struct device *dev, ...@@ -515,22 +519,12 @@ enum regmap_endian regmap_get_val_endian(struct device *dev,
} }
EXPORT_SYMBOL_GPL(regmap_get_val_endian); EXPORT_SYMBOL_GPL(regmap_get_val_endian);
/** struct regmap *__regmap_init(struct device *dev,
* regmap_init(): Initialise register map
*
* @dev: Device that will be interacted with
* @bus: Bus-specific callbacks to use with device
* @bus_context: Data passed to bus-specific callbacks
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer to
* a struct regmap. This function should generally not be called
* directly, it should be called by bus-specific init functions.
*/
struct regmap *regmap_init(struct device *dev,
const struct regmap_bus *bus, const struct regmap_bus *bus,
void *bus_context, void *bus_context,
const struct regmap_config *config) const struct regmap_config *config,
struct lock_class_key *lock_key,
const char *lock_name)
{ {
struct regmap *map; struct regmap *map;
int ret = -EINVAL; int ret = -EINVAL;
...@@ -556,10 +550,14 @@ struct regmap *regmap_init(struct device *dev, ...@@ -556,10 +550,14 @@ struct regmap *regmap_init(struct device *dev,
spin_lock_init(&map->spinlock); spin_lock_init(&map->spinlock);
map->lock = regmap_lock_spinlock; map->lock = regmap_lock_spinlock;
map->unlock = regmap_unlock_spinlock; map->unlock = regmap_unlock_spinlock;
lockdep_set_class_and_name(&map->spinlock,
lock_key, lock_name);
} else { } else {
mutex_init(&map->mutex); mutex_init(&map->mutex);
map->lock = regmap_lock_mutex; map->lock = regmap_lock_mutex;
map->unlock = regmap_unlock_mutex; map->unlock = regmap_unlock_mutex;
lockdep_set_class_and_name(&map->mutex,
lock_key, lock_name);
} }
map->lock_arg = map; map->lock_arg = map;
} }
...@@ -573,8 +571,13 @@ struct regmap *regmap_init(struct device *dev, ...@@ -573,8 +571,13 @@ struct regmap *regmap_init(struct device *dev,
map->reg_stride = config->reg_stride; map->reg_stride = config->reg_stride;
else else
map->reg_stride = 1; map->reg_stride = 1;
map->use_single_rw = config->use_single_rw; map->use_single_read = config->use_single_rw || !bus || !bus->read;
map->can_multi_write = config->can_multi_write; map->use_single_write = config->use_single_rw || !bus || !bus->write;
map->can_multi_write = config->can_multi_write && bus && bus->write;
if (bus) {
map->max_raw_read = bus->max_raw_read;
map->max_raw_write = bus->max_raw_write;
}
map->dev = dev; map->dev = dev;
map->bus = bus; map->bus = bus;
map->bus_context = bus_context; map->bus_context = bus_context;
...@@ -763,7 +766,7 @@ struct regmap *regmap_init(struct device *dev, ...@@ -763,7 +766,7 @@ struct regmap *regmap_init(struct device *dev,
if ((reg_endian != REGMAP_ENDIAN_BIG) || if ((reg_endian != REGMAP_ENDIAN_BIG) ||
(val_endian != REGMAP_ENDIAN_BIG)) (val_endian != REGMAP_ENDIAN_BIG))
goto err_map; goto err_map;
map->use_single_rw = true; map->use_single_write = true;
} }
if (!map->format.format_write && if (!map->format.format_write &&
...@@ -899,30 +902,19 @@ struct regmap *regmap_init(struct device *dev, ...@@ -899,30 +902,19 @@ struct regmap *regmap_init(struct device *dev,
err: err:
return ERR_PTR(ret); return ERR_PTR(ret);
} }
EXPORT_SYMBOL_GPL(regmap_init); EXPORT_SYMBOL_GPL(__regmap_init);
static void devm_regmap_release(struct device *dev, void *res) static void devm_regmap_release(struct device *dev, void *res)
{ {
regmap_exit(*(struct regmap **)res); regmap_exit(*(struct regmap **)res);
} }
/** struct regmap *__devm_regmap_init(struct device *dev,
* devm_regmap_init(): Initialise managed register map
*
* @dev: Device that will be interacted with
* @bus: Bus-specific callbacks to use with device
* @bus_context: Data passed to bus-specific callbacks
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer
* to a struct regmap. This function should generally not be called
* directly, it should be called by bus-specific init functions. The
* map will be automatically freed by the device management code.
*/
struct regmap *devm_regmap_init(struct device *dev,
const struct regmap_bus *bus, const struct regmap_bus *bus,
void *bus_context, void *bus_context,
const struct regmap_config *config) const struct regmap_config *config,
struct lock_class_key *lock_key,
const char *lock_name)
{ {
struct regmap **ptr, *regmap; struct regmap **ptr, *regmap;
...@@ -930,7 +922,8 @@ struct regmap *devm_regmap_init(struct device *dev, ...@@ -930,7 +922,8 @@ struct regmap *devm_regmap_init(struct device *dev,
if (!ptr) if (!ptr)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
regmap = regmap_init(dev, bus, bus_context, config); regmap = __regmap_init(dev, bus, bus_context, config,
lock_key, lock_name);
if (!IS_ERR(regmap)) { if (!IS_ERR(regmap)) {
*ptr = regmap; *ptr = regmap;
devres_add(dev, ptr); devres_add(dev, ptr);
...@@ -940,7 +933,7 @@ struct regmap *devm_regmap_init(struct device *dev, ...@@ -940,7 +933,7 @@ struct regmap *devm_regmap_init(struct device *dev,
return regmap; return regmap;
} }
EXPORT_SYMBOL_GPL(devm_regmap_init); EXPORT_SYMBOL_GPL(__devm_regmap_init);
static void regmap_field_init(struct regmap_field *rm_field, static void regmap_field_init(struct regmap_field *rm_field,
struct regmap *regmap, struct reg_field reg_field) struct regmap *regmap, struct reg_field reg_field)
...@@ -1382,10 +1375,33 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg, ...@@ -1382,10 +1375,33 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
*/ */
bool regmap_can_raw_write(struct regmap *map) bool regmap_can_raw_write(struct regmap *map)
{ {
return map->bus && map->format.format_val && map->format.format_reg; return map->bus && map->bus->write && map->format.format_val &&
map->format.format_reg;
} }
EXPORT_SYMBOL_GPL(regmap_can_raw_write); EXPORT_SYMBOL_GPL(regmap_can_raw_write);
/**
* regmap_get_raw_read_max - Get the maximum size we can read
*
* @map: Map to check.
*/
size_t regmap_get_raw_read_max(struct regmap *map)
{
return map->max_raw_read;
}
EXPORT_SYMBOL_GPL(regmap_get_raw_read_max);
/**
* regmap_get_raw_write_max - Get the maximum size we can read
*
* @map: Map to check.
*/
size_t regmap_get_raw_write_max(struct regmap *map)
{
return map->max_raw_write;
}
EXPORT_SYMBOL_GPL(regmap_get_raw_write_max);
static int _regmap_bus_formatted_write(void *context, unsigned int reg, static int _regmap_bus_formatted_write(void *context, unsigned int reg,
unsigned int val) unsigned int val)
{ {
...@@ -1555,6 +1571,8 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, ...@@ -1555,6 +1571,8 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
return -EINVAL; return -EINVAL;
if (val_len % map->format.val_bytes) if (val_len % map->format.val_bytes)
return -EINVAL; return -EINVAL;
if (map->max_raw_write && map->max_raw_write > val_len)
return -E2BIG;
map->lock(map->lock_arg); map->lock(map->lock_arg);
...@@ -1681,6 +1699,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, ...@@ -1681,6 +1699,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
{ {
int ret = 0, i; int ret = 0, i;
size_t val_bytes = map->format.val_bytes; size_t val_bytes = map->format.val_bytes;
size_t total_size = val_bytes * val_count;
if (map->bus && !map->format.parse_inplace) if (map->bus && !map->format.parse_inplace)
return -EINVAL; return -EINVAL;
...@@ -1689,9 +1708,15 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, ...@@ -1689,9 +1708,15 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
/* /*
* Some devices don't support bulk write, for * Some devices don't support bulk write, for
* them we have a series of single write operations. * them we have a series of single write operations in the first two if
* blocks.
*
* The first if block is used for memory mapped io. It does not allow
* val_bytes of 3 for example.
* The second one is used for busses which do not have this limitation
* and can write arbitrary value lengths.
*/ */
if (!map->bus || map->use_single_rw) { if (!map->bus) {
map->lock(map->lock_arg); map->lock(map->lock_arg);
for (i = 0; i < val_count; i++) { for (i = 0; i < val_count; i++) {
unsigned int ival; unsigned int ival;
...@@ -1723,6 +1748,38 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, ...@@ -1723,6 +1748,38 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
} }
out: out:
map->unlock(map->lock_arg); map->unlock(map->lock_arg);
} else if (map->use_single_write ||
(map->max_raw_write && map->max_raw_write < total_size)) {
int chunk_stride = map->reg_stride;
size_t chunk_size = val_bytes;
size_t chunk_count = val_count;
if (!map->use_single_write) {
chunk_size = map->max_raw_write;
if (chunk_size % val_bytes)
chunk_size -= chunk_size % val_bytes;
chunk_count = total_size / chunk_size;
chunk_stride *= chunk_size / val_bytes;
}
map->lock(map->lock_arg);
/* Write as many bytes as possible with chunk_size */
for (i = 0; i < chunk_count; i++) {
ret = _regmap_raw_write(map,
reg + (i * chunk_stride),
val + (i * chunk_size),
chunk_size);
if (ret)
break;
}
/* Write remaining bytes */
if (!ret && chunk_size * i < total_size) {
ret = _regmap_raw_write(map, reg + (i * chunk_stride),
val + (i * chunk_size),
total_size - i * chunk_size);
}
map->unlock(map->lock_arg);
} else { } else {
void *wval; void *wval;
...@@ -1752,7 +1809,7 @@ EXPORT_SYMBOL_GPL(regmap_bulk_write); ...@@ -1752,7 +1809,7 @@ EXPORT_SYMBOL_GPL(regmap_bulk_write);
* *
* the (register,newvalue) pairs in regs have not been formatted, but * the (register,newvalue) pairs in regs have not been formatted, but
* they are all in the same page and have been changed to being page * they are all in the same page and have been changed to being page
* relative. The page register has been written if that was neccessary. * relative. The page register has been written if that was necessary.
*/ */
static int _regmap_raw_multi_reg_write(struct regmap *map, static int _regmap_raw_multi_reg_write(struct regmap *map,
const struct reg_sequence *regs, const struct reg_sequence *regs,
...@@ -1780,8 +1837,8 @@ static int _regmap_raw_multi_reg_write(struct regmap *map, ...@@ -1780,8 +1837,8 @@ static int _regmap_raw_multi_reg_write(struct regmap *map,
u8 = buf; u8 = buf;
for (i = 0; i < num_regs; i++) { for (i = 0; i < num_regs; i++) {
int reg = regs[i].reg; unsigned int reg = regs[i].reg;
int val = regs[i].def; unsigned int val = regs[i].def;
trace_regmap_hw_write_start(map, reg, 1); trace_regmap_hw_write_start(map, reg, 1);
map->format.format_reg(u8, reg, map->reg_shift); map->format.format_reg(u8, reg, map->reg_shift);
u8 += reg_bytes + pad_bytes; u8 += reg_bytes + pad_bytes;
...@@ -1819,10 +1876,12 @@ static int _regmap_range_multi_paged_reg_write(struct regmap *map, ...@@ -1819,10 +1876,12 @@ static int _regmap_range_multi_paged_reg_write(struct regmap *map,
int i, n; int i, n;
struct reg_sequence *base; struct reg_sequence *base;
unsigned int this_page = 0; unsigned int this_page = 0;
unsigned int page_change = 0;
/* /*
* the set of registers are not neccessarily in order, but * the set of registers are not neccessarily in order, but
* since the order of write must be preserved this algorithm * since the order of write must be preserved this algorithm
* chops the set each time the page changes * chops the set each time the page changes. This also applies
* if there is a delay required at any point in the sequence.
*/ */
base = regs; base = regs;
for (i = 0, n = 0; i < num_regs; i++, n++) { for (i = 0, n = 0; i < num_regs; i++, n++) {
...@@ -1838,16 +1897,48 @@ static int _regmap_range_multi_paged_reg_write(struct regmap *map, ...@@ -1838,16 +1897,48 @@ static int _regmap_range_multi_paged_reg_write(struct regmap *map,
this_page = win_page; this_page = win_page;
if (win_page != this_page) { if (win_page != this_page) {
this_page = win_page; this_page = win_page;
page_change = 1;
}
}
/* If we have both a page change and a delay make sure to
* write the regs and apply the delay before we change the
* page.
*/
if (page_change || regs[i].delay_us) {
/* For situations where the first write requires
* a delay we need to make sure we don't call
* raw_multi_reg_write with n=0
* This can't occur with page breaks as we
* never write on the first iteration
*/
if (regs[i].delay_us && i == 0)
n = 1;
ret = _regmap_raw_multi_reg_write(map, base, n); ret = _regmap_raw_multi_reg_write(map, base, n);
if (ret != 0) if (ret != 0)
return ret; return ret;
if (regs[i].delay_us)
udelay(regs[i].delay_us);
base += n; base += n;
n = 0; n = 0;
}
ret = _regmap_select_page(map, &base[n].reg, range, 1); if (page_change) {
ret = _regmap_select_page(map,
&base[n].reg,
range, 1);
if (ret != 0) if (ret != 0)
return ret; return ret;
page_change = 0;
} }
}
} }
if (n > 0) if (n > 0)
return _regmap_raw_multi_reg_write(map, base, n); return _regmap_raw_multi_reg_write(map, base, n);
...@@ -1866,6 +1957,9 @@ static int _regmap_multi_reg_write(struct regmap *map, ...@@ -1866,6 +1957,9 @@ static int _regmap_multi_reg_write(struct regmap *map,
ret = _regmap_write(map, regs[i].reg, regs[i].def); ret = _regmap_write(map, regs[i].reg, regs[i].def);
if (ret != 0) if (ret != 0)
return ret; return ret;
if (regs[i].delay_us)
udelay(regs[i].delay_us);
} }
return 0; return 0;
} }
...@@ -1905,8 +1999,12 @@ static int _regmap_multi_reg_write(struct regmap *map, ...@@ -1905,8 +1999,12 @@ static int _regmap_multi_reg_write(struct regmap *map,
for (i = 0; i < num_regs; i++) { for (i = 0; i < num_regs; i++) {
unsigned int reg = regs[i].reg; unsigned int reg = regs[i].reg;
struct regmap_range_node *range; struct regmap_range_node *range;
/* Coalesce all the writes between a page break or a delay
* in a sequence
*/
range = _regmap_range_lookup(map, reg); range = _regmap_range_lookup(map, reg);
if (range) { if (range || regs[i].delay_us) {
size_t len = sizeof(struct reg_sequence)*num_regs; size_t len = sizeof(struct reg_sequence)*num_regs;
struct reg_sequence *base = kmemdup(regs, len, struct reg_sequence *base = kmemdup(regs, len,
GFP_KERNEL); GFP_KERNEL);
...@@ -2062,7 +2160,7 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, ...@@ -2062,7 +2160,7 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
/* /*
* Some buses or devices flag reads by setting the high bits in the * Some buses or devices flag reads by setting the high bits in the
* register addresss; since it's always the high bits for all * register address; since it's always the high bits for all
* current formats we can do this here rather than in * current formats we can do this here rather than in
* formatting. This may break if we get interesting formats. * formatting. This may break if we get interesting formats.
*/ */
...@@ -2109,8 +2207,6 @@ static int _regmap_read(struct regmap *map, unsigned int reg, ...@@ -2109,8 +2207,6 @@ static int _regmap_read(struct regmap *map, unsigned int reg,
int ret; int ret;
void *context = _regmap_map_get_context(map); void *context = _regmap_map_get_context(map);
WARN_ON(!map->reg_read);
if (!map->cache_bypass) { if (!map->cache_bypass) {
ret = regcache_read(map, reg, val); ret = regcache_read(map, reg, val);
if (ret == 0) if (ret == 0)
...@@ -2191,11 +2287,22 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val, ...@@ -2191,11 +2287,22 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
return -EINVAL; return -EINVAL;
if (reg % map->reg_stride) if (reg % map->reg_stride)
return -EINVAL; return -EINVAL;
if (val_count == 0)
return -EINVAL;
map->lock(map->lock_arg); map->lock(map->lock_arg);
if (regmap_volatile_range(map, reg, val_count) || map->cache_bypass || if (regmap_volatile_range(map, reg, val_count) || map->cache_bypass ||
map->cache_type == REGCACHE_NONE) { map->cache_type == REGCACHE_NONE) {
if (!map->bus->read) {
ret = -ENOTSUPP;
goto out;
}
if (map->max_raw_read && map->max_raw_read < val_len) {
ret = -E2BIG;
goto out;
}
/* Physical block read if there's no cache involved */ /* Physical block read if there's no cache involved */
ret = _regmap_raw_read(map, reg, val, val_len); ret = _regmap_raw_read(map, reg, val, val_len);
...@@ -2304,21 +2411,52 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, ...@@ -2304,21 +2411,52 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
* Some devices does not support bulk read, for * Some devices does not support bulk read, for
* them we have a series of single read operations. * them we have a series of single read operations.
*/ */
if (map->use_single_rw) { size_t total_size = val_bytes * val_count;
for (i = 0; i < val_count; i++) {
if (!map->use_single_read &&
(!map->max_raw_read || map->max_raw_read > total_size)) {
ret = regmap_raw_read(map, reg, val,
val_bytes * val_count);
if (ret != 0)
return ret;
} else {
/*
* Some devices do not support bulk read or do not
* support large bulk reads, for them we have a series
* of read operations.
*/
int chunk_stride = map->reg_stride;
size_t chunk_size = val_bytes;
size_t chunk_count = val_count;
if (!map->use_single_read) {
chunk_size = map->max_raw_read;
if (chunk_size % val_bytes)
chunk_size -= chunk_size % val_bytes;
chunk_count = total_size / chunk_size;
chunk_stride *= chunk_size / val_bytes;
}
/* Read bytes that fit into a multiple of chunk_size */
for (i = 0; i < chunk_count; i++) {
ret = regmap_raw_read(map, ret = regmap_raw_read(map,
reg + (i * map->reg_stride), reg + (i * chunk_stride),
val + (i * val_bytes), val + (i * chunk_size),
val_bytes); chunk_size);
if (ret != 0) if (ret != 0)
return ret; return ret;
} }
} else {
ret = regmap_raw_read(map, reg, val, /* Read remaining bytes */
val_bytes * val_count); if (chunk_size * i < total_size) {
ret = regmap_raw_read(map,
reg + (i * chunk_stride),
val + (i * chunk_size),
total_size - i * chunk_size);
if (ret != 0) if (ret != 0)
return ret; return ret;
} }
}
for (i = 0; i < val_count * val_bytes; i += val_bytes) for (i = 0; i < val_count * val_bytes; i += val_bytes)
map->format.parse_inplace(val + i); map->format.parse_inplace(val + i);
...@@ -2329,7 +2467,34 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, ...@@ -2329,7 +2467,34 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
&ival); &ival);
if (ret != 0) if (ret != 0)
return ret; return ret;
if (map->format.format_val) {
map->format.format_val(val + (i * val_bytes), ival, 0); map->format.format_val(val + (i * val_bytes), ival, 0);
} else {
/* Devices providing read and write
* operations can use the bulk I/O
* functions if they define a val_bytes,
* we assume that the values are native
* endian.
*/
u32 *u32 = val;
u16 *u16 = val;
u8 *u8 = val;
switch (map->format.val_bytes) {
case 4:
u32[i] = ival;
break;
case 2:
u16[i] = ival;
break;
case 1:
u8[i] = ival;
break;
default:
return -EINVAL;
}
}
} }
} }
......
...@@ -107,7 +107,7 @@ struct regmap *devm_regmap_init_vexpress_config(struct device *dev) ...@@ -107,7 +107,7 @@ struct regmap *devm_regmap_init_vexpress_config(struct device *dev)
if (!res) if (!res)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
regmap = bridge->ops->regmap_init(dev, bridge->context); regmap = (bridge->ops->regmap_init)(dev, bridge->context);
if (IS_ERR(regmap)) { if (IS_ERR(regmap)) {
devres_free(res); devres_free(res);
return regmap; return regmap;
......
...@@ -1262,7 +1262,7 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, ...@@ -1262,7 +1262,7 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
regulator->debugfs = debugfs_create_dir(regulator->supply_name, regulator->debugfs = debugfs_create_dir(regulator->supply_name,
rdev->debugfs); rdev->debugfs);
if (!regulator->debugfs) { if (!regulator->debugfs) {
rdev_warn(rdev, "Failed to create debugfs directory\n"); rdev_dbg(rdev, "Failed to create debugfs directory\n");
} else { } else {
debugfs_create_u32("uA_load", 0444, regulator->debugfs, debugfs_create_u32("uA_load", 0444, regulator->debugfs,
&regulator->uA_load); &regulator->uA_load);
......
...@@ -214,7 +214,7 @@ int st_thermal_register(struct platform_device *pdev, ...@@ -214,7 +214,7 @@ int st_thermal_register(struct platform_device *pdev,
sensor->ops = sensor->cdata->ops; sensor->ops = sensor->cdata->ops;
ret = sensor->ops->regmap_init(sensor); ret = (sensor->ops->regmap_init)(sensor);
if (ret) if (ret)
return ret; return ret;
......
...@@ -435,7 +435,7 @@ struct dentry *debugfs_create_atomic_t(const char *name, umode_t mode, ...@@ -435,7 +435,7 @@ struct dentry *debugfs_create_atomic_t(const char *name, umode_t mode,
} }
EXPORT_SYMBOL_GPL(debugfs_create_atomic_t); EXPORT_SYMBOL_GPL(debugfs_create_atomic_t);
static ssize_t read_file_bool(struct file *file, char __user *user_buf, ssize_t debugfs_read_file_bool(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
char buf[3]; char buf[3];
...@@ -449,8 +449,9 @@ static ssize_t read_file_bool(struct file *file, char __user *user_buf, ...@@ -449,8 +449,9 @@ static ssize_t read_file_bool(struct file *file, char __user *user_buf,
buf[2] = 0x00; buf[2] = 0x00;
return simple_read_from_buffer(user_buf, count, ppos, buf, 2); return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
} }
EXPORT_SYMBOL_GPL(debugfs_read_file_bool);
static ssize_t write_file_bool(struct file *file, const char __user *user_buf, ssize_t debugfs_write_file_bool(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
char buf[32]; char buf[32];
...@@ -468,10 +469,11 @@ static ssize_t write_file_bool(struct file *file, const char __user *user_buf, ...@@ -468,10 +469,11 @@ static ssize_t write_file_bool(struct file *file, const char __user *user_buf,
return count; return count;
} }
EXPORT_SYMBOL_GPL(debugfs_write_file_bool);
static const struct file_operations fops_bool = { static const struct file_operations fops_bool = {
.read = read_file_bool, .read = debugfs_read_file_bool,
.write = write_file_bool, .write = debugfs_write_file_bool,
.open = simple_open, .open = simple_open,
.llseek = default_llseek, .llseek = default_llseek,
}; };
......
...@@ -116,6 +116,12 @@ struct dentry *debugfs_create_devm_seqfile(struct device *dev, const char *name, ...@@ -116,6 +116,12 @@ struct dentry *debugfs_create_devm_seqfile(struct device *dev, const char *name,
bool debugfs_initialized(void); bool debugfs_initialized(void);
ssize_t debugfs_read_file_bool(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos);
ssize_t debugfs_write_file_bool(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos);
#else #else
#include <linux/err.h> #include <linux/err.h>
...@@ -282,6 +288,20 @@ static inline struct dentry *debugfs_create_devm_seqfile(struct device *dev, ...@@ -282,6 +288,20 @@ static inline struct dentry *debugfs_create_devm_seqfile(struct device *dev,
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
} }
static inline ssize_t debugfs_read_file_bool(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
return -ENODEV;
}
static inline ssize_t debugfs_write_file_bool(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
return -ENODEV;
}
#endif #endif
#endif #endif
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/rbtree.h> #include <linux/rbtree.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/bug.h> #include <linux/bug.h>
#include <linux/lockdep.h>
struct module; struct module;
struct device; struct device;
...@@ -51,14 +52,17 @@ struct reg_default { ...@@ -51,14 +52,17 @@ struct reg_default {
}; };
/** /**
* Register/value pairs for sequences of writes * Register/value pairs for sequences of writes with an optional delay in
* microseconds to be applied after each write.
* *
* @reg: Register address. * @reg: Register address.
* @def: Register value. * @def: Register value.
* @delay_us: Delay to be applied after the register write in microseconds
*/ */
struct reg_sequence { struct reg_sequence {
unsigned int reg; unsigned int reg;
unsigned int def; unsigned int def;
unsigned int delay_us;
}; };
#ifdef CONFIG_REGMAP #ifdef CONFIG_REGMAP
...@@ -307,8 +311,12 @@ typedef void (*regmap_hw_free_context)(void *context); ...@@ -307,8 +311,12 @@ typedef void (*regmap_hw_free_context)(void *context);
* if not implemented on a given device. * if not implemented on a given device.
* @async_write: Write operation which completes asynchronously, optional and * @async_write: Write operation which completes asynchronously, optional and
* must serialise with respect to non-async I/O. * must serialise with respect to non-async I/O.
* @reg_write: Write a single register value to the given register address. This
* write operation has to complete when returning from the function.
* @read: Read operation. Data is returned in the buffer used to transmit * @read: Read operation. Data is returned in the buffer used to transmit
* data. * data.
* @reg_read: Read a single register value from a given register address.
* @free_context: Free context.
* @async_alloc: Allocate a regmap_async() structure. * @async_alloc: Allocate a regmap_async() structure.
* @read_flag_mask: Mask to be set in the top byte of the register when doing * @read_flag_mask: Mask to be set in the top byte of the register when doing
* a read. * a read.
...@@ -318,7 +326,8 @@ typedef void (*regmap_hw_free_context)(void *context); ...@@ -318,7 +326,8 @@ typedef void (*regmap_hw_free_context)(void *context);
* @val_format_endian_default: Default endianness for formatted register * @val_format_endian_default: Default endianness for formatted register
* values. Used when the regmap_config specifies DEFAULT. If this is * values. Used when the regmap_config specifies DEFAULT. If this is
* DEFAULT, BIG is assumed. * DEFAULT, BIG is assumed.
* @async_size: Size of struct used for async work. * @max_raw_read: Max raw read size that can be used on the bus.
* @max_raw_write: Max raw write size that can be used on the bus.
*/ */
struct regmap_bus { struct regmap_bus {
bool fast_io; bool fast_io;
...@@ -333,47 +342,186 @@ struct regmap_bus { ...@@ -333,47 +342,186 @@ struct regmap_bus {
u8 read_flag_mask; u8 read_flag_mask;
enum regmap_endian reg_format_endian_default; enum regmap_endian reg_format_endian_default;
enum regmap_endian val_format_endian_default; enum regmap_endian val_format_endian_default;
size_t max_raw_read;
size_t max_raw_write;
}; };
struct regmap *regmap_init(struct device *dev, /*
* __regmap_init functions.
*
* These functions take a lock key and name parameter, and should not be called
* directly. Instead, use the regmap_init macros that generate a key and name
* for each call.
*/
struct regmap *__regmap_init(struct device *dev,
const struct regmap_bus *bus, const struct regmap_bus *bus,
void *bus_context, void *bus_context,
const struct regmap_config *config); const struct regmap_config *config,
int regmap_attach_dev(struct device *dev, struct regmap *map, struct lock_class_key *lock_key,
const struct regmap_config *config); const char *lock_name);
struct regmap *regmap_init_i2c(struct i2c_client *i2c, struct regmap *__regmap_init_i2c(struct i2c_client *i2c,
const struct regmap_config *config); const struct regmap_config *config,
struct regmap *regmap_init_spi(struct spi_device *dev, struct lock_class_key *lock_key,
const struct regmap_config *config); const char *lock_name);
struct regmap *regmap_init_spmi_base(struct spmi_device *dev, struct regmap *__regmap_init_spi(struct spi_device *dev,
const struct regmap_config *config); const struct regmap_config *config,
struct regmap *regmap_init_spmi_ext(struct spmi_device *dev, struct lock_class_key *lock_key,
const struct regmap_config *config); const char *lock_name);
struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id, struct regmap *__regmap_init_spmi_base(struct spmi_device *dev,
const struct regmap_config *config,
struct lock_class_key *lock_key,
const char *lock_name);
struct regmap *__regmap_init_spmi_ext(struct spmi_device *dev,
const struct regmap_config *config,
struct lock_class_key *lock_key,
const char *lock_name);
struct regmap *__regmap_init_mmio_clk(struct device *dev, const char *clk_id,
void __iomem *regs, void __iomem *regs,
const struct regmap_config *config); const struct regmap_config *config,
struct regmap *regmap_init_ac97(struct snd_ac97 *ac97, struct lock_class_key *lock_key,
const struct regmap_config *config); const char *lock_name);
struct regmap *__regmap_init_ac97(struct snd_ac97 *ac97,
struct regmap *devm_regmap_init(struct device *dev, const struct regmap_config *config,
struct lock_class_key *lock_key,
const char *lock_name);
struct regmap *__devm_regmap_init(struct device *dev,
const struct regmap_bus *bus, const struct regmap_bus *bus,
void *bus_context, void *bus_context,
const struct regmap_config *config); const struct regmap_config *config,
struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c, struct lock_class_key *lock_key,
const struct regmap_config *config); const char *lock_name);
struct regmap *devm_regmap_init_spi(struct spi_device *dev, struct regmap *__devm_regmap_init_i2c(struct i2c_client *i2c,
const struct regmap_config *config); const struct regmap_config *config,
struct regmap *devm_regmap_init_spmi_base(struct spmi_device *dev, struct lock_class_key *lock_key,
const struct regmap_config *config); const char *lock_name);
struct regmap *devm_regmap_init_spmi_ext(struct spmi_device *dev, struct regmap *__devm_regmap_init_spi(struct spi_device *dev,
const struct regmap_config *config); const struct regmap_config *config,
struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id, struct lock_class_key *lock_key,
const char *lock_name);
struct regmap *__devm_regmap_init_spmi_base(struct spmi_device *dev,
const struct regmap_config *config,
struct lock_class_key *lock_key,
const char *lock_name);
struct regmap *__devm_regmap_init_spmi_ext(struct spmi_device *dev,
const struct regmap_config *config,
struct lock_class_key *lock_key,
const char *lock_name);
struct regmap *__devm_regmap_init_mmio_clk(struct device *dev,
const char *clk_id,
void __iomem *regs, void __iomem *regs,
const struct regmap_config *config); const struct regmap_config *config,
struct regmap *devm_regmap_init_ac97(struct snd_ac97 *ac97, struct lock_class_key *lock_key,
const char *lock_name);
struct regmap *__devm_regmap_init_ac97(struct snd_ac97 *ac97,
const struct regmap_config *config,
struct lock_class_key *lock_key,
const char *lock_name);
/*
* Wrapper for regmap_init macros to include a unique lockdep key and name
* for each call. No-op if CONFIG_LOCKDEP is not set.
*
* @fn: Real function to call (in the form __[*_]regmap_init[_*])
* @name: Config variable name (#config in the calling macro)
**/
#ifdef CONFIG_LOCKDEP
#define __regmap_lockdep_wrapper(fn, name, ...) \
( \
({ \
static struct lock_class_key _key; \
fn(__VA_ARGS__, &_key, \
KBUILD_BASENAME ":" \
__stringify(__LINE__) ":" \
"(" name ")->lock"); \
}) \
)
#else
#define __regmap_lockdep_wrapper(fn, name, ...) fn(__VA_ARGS__, NULL, NULL)
#endif
/**
* regmap_init(): Initialise register map
*
* @dev: Device that will be interacted with
* @bus: Bus-specific callbacks to use with device
* @bus_context: Data passed to bus-specific callbacks
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer to
* a struct regmap. This function should generally not be called
* directly, it should be called by bus-specific init functions.
*/
#define regmap_init(dev, bus, bus_context, config) \
__regmap_lockdep_wrapper(__regmap_init, #config, \
dev, bus, bus_context, config)
int regmap_attach_dev(struct device *dev, struct regmap *map,
const struct regmap_config *config); const struct regmap_config *config);
bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg); /**
* regmap_init_i2c(): Initialise register map
*
* @i2c: Device that will be interacted with
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer to
* a struct regmap.
*/
#define regmap_init_i2c(i2c, config) \
__regmap_lockdep_wrapper(__regmap_init_i2c, #config, \
i2c, config)
/**
* regmap_init_spi(): Initialise register map
*
* @spi: Device that will be interacted with
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer to
* a struct regmap.
*/
#define regmap_init_spi(dev, config) \
__regmap_lockdep_wrapper(__regmap_init_spi, #config, \
dev, config)
/**
* regmap_init_spmi_base(): Create regmap for the Base register space
* @sdev: SPMI device that will be interacted with
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer to
* a struct regmap.
*/
#define regmap_init_spmi_base(dev, config) \
__regmap_lockdep_wrapper(__regmap_init_spmi_base, #config, \
dev, config)
/**
* regmap_init_spmi_ext(): Create regmap for Ext register space
* @sdev: Device that will be interacted with
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer to
* a struct regmap.
*/
#define regmap_init_spmi_ext(dev, config) \
__regmap_lockdep_wrapper(__regmap_init_spmi_ext, #config, \
dev, config)
/**
* regmap_init_mmio_clk(): Initialise register map with register clock
*
* @dev: Device that will be interacted with
* @clk_id: register clock consumer ID
* @regs: Pointer to memory-mapped IO region
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer to
* a struct regmap.
*/
#define regmap_init_mmio_clk(dev, clk_id, regs, config) \
__regmap_lockdep_wrapper(__regmap_init_mmio_clk, #config, \
dev, clk_id, regs, config)
/** /**
* regmap_init_mmio(): Initialise register map * regmap_init_mmio(): Initialise register map
...@@ -385,12 +533,109 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg); ...@@ -385,12 +533,109 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
* The return value will be an ERR_PTR() on error or a valid pointer to * The return value will be an ERR_PTR() on error or a valid pointer to
* a struct regmap. * a struct regmap.
*/ */
static inline struct regmap *regmap_init_mmio(struct device *dev, #define regmap_init_mmio(dev, regs, config) \
void __iomem *regs, regmap_init_mmio_clk(dev, NULL, regs, config)
const struct regmap_config *config)
{ /**
return regmap_init_mmio_clk(dev, NULL, regs, config); * regmap_init_ac97(): Initialise AC'97 register map
} *
* @ac97: Device that will be interacted with
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer to
* a struct regmap.
*/
#define regmap_init_ac97(ac97, config) \
__regmap_lockdep_wrapper(__regmap_init_ac97, #config, \
ac97, config)
bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
/**
* devm_regmap_init(): Initialise managed register map
*
* @dev: Device that will be interacted with
* @bus: Bus-specific callbacks to use with device
* @bus_context: Data passed to bus-specific callbacks
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer
* to a struct regmap. This function should generally not be called
* directly, it should be called by bus-specific init functions. The
* map will be automatically freed by the device management code.
*/
#define devm_regmap_init(dev, bus, bus_context, config) \
__regmap_lockdep_wrapper(__devm_regmap_init, #config, \
dev, bus, bus_context, config)
/**
* devm_regmap_init_i2c(): Initialise managed register map
*
* @i2c: Device that will be interacted with
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer
* to a struct regmap. The regmap will be automatically freed by the
* device management code.
*/
#define devm_regmap_init_i2c(i2c, config) \
__regmap_lockdep_wrapper(__devm_regmap_init_i2c, #config, \
i2c, config)
/**
* devm_regmap_init_spi(): Initialise register map
*
* @spi: Device that will be interacted with
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer
* to a struct regmap. The map will be automatically freed by the
* device management code.
*/
#define devm_regmap_init_spi(dev, config) \
__regmap_lockdep_wrapper(__devm_regmap_init_spi, #config, \
dev, config)
/**
* devm_regmap_init_spmi_base(): Create managed regmap for Base register space
* @sdev: SPMI device that will be interacted with
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer
* to a struct regmap. The regmap will be automatically freed by the
* device management code.
*/
#define devm_regmap_init_spmi_base(dev, config) \
__regmap_lockdep_wrapper(__devm_regmap_init_spmi_base, #config, \
dev, config)
/**
* devm_regmap_init_spmi_ext(): Create managed regmap for Ext register space
* @sdev: SPMI device that will be interacted with
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer
* to a struct regmap. The regmap will be automatically freed by the
* device management code.
*/
#define devm_regmap_init_spmi_ext(dev, config) \
__regmap_lockdep_wrapper(__devm_regmap_init_spmi_ext, #config, \
dev, config)
/**
* devm_regmap_init_mmio_clk(): Initialise managed register map with clock
*
* @dev: Device that will be interacted with
* @clk_id: register clock consumer ID
* @regs: Pointer to memory-mapped IO region
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer
* to a struct regmap. The regmap will be automatically freed by the
* device management code.
*/
#define devm_regmap_init_mmio_clk(dev, clk_id, regs, config) \
__regmap_lockdep_wrapper(__devm_regmap_init_mmio_clk, #config, \
dev, clk_id, regs, config)
/** /**
* devm_regmap_init_mmio(): Initialise managed register map * devm_regmap_init_mmio(): Initialise managed register map
...@@ -403,12 +648,22 @@ static inline struct regmap *regmap_init_mmio(struct device *dev, ...@@ -403,12 +648,22 @@ static inline struct regmap *regmap_init_mmio(struct device *dev,
* to a struct regmap. The regmap will be automatically freed by the * to a struct regmap. The regmap will be automatically freed by the
* device management code. * device management code.
*/ */
static inline struct regmap *devm_regmap_init_mmio(struct device *dev, #define devm_regmap_init_mmio(dev, regs, config) \
void __iomem *regs, devm_regmap_init_mmio_clk(dev, NULL, regs, config)
const struct regmap_config *config)
{ /**
return devm_regmap_init_mmio_clk(dev, NULL, regs, config); * devm_regmap_init_ac97(): Initialise AC'97 register map
} *
* @ac97: Device that will be interacted with
* @config: Configuration for register map
*
* The return value will be an ERR_PTR() on error or a valid pointer
* to a struct regmap. The regmap will be automatically freed by the
* device management code.
*/
#define devm_regmap_init_ac97(ac97, config) \
__regmap_lockdep_wrapper(__devm_regmap_init_ac97, #config, \
ac97, config)
void regmap_exit(struct regmap *map); void regmap_exit(struct regmap *map);
int regmap_reinit_cache(struct regmap *map, int regmap_reinit_cache(struct regmap *map,
...@@ -450,6 +705,8 @@ int regmap_get_max_register(struct regmap *map); ...@@ -450,6 +705,8 @@ int regmap_get_max_register(struct regmap *map);
int regmap_get_reg_stride(struct regmap *map); int regmap_get_reg_stride(struct regmap *map);
int regmap_async_complete(struct regmap *map); int regmap_async_complete(struct regmap *map);
bool regmap_can_raw_write(struct regmap *map); bool regmap_can_raw_write(struct regmap *map);
size_t regmap_get_raw_read_max(struct regmap *map);
size_t regmap_get_raw_write_max(struct regmap *map);
int regcache_sync(struct regmap *map); int regcache_sync(struct regmap *map);
int regcache_sync_region(struct regmap *map, unsigned int min, int regcache_sync_region(struct regmap *map, unsigned int min,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment