Commit 57218d7f authored by Linus Torvalds's avatar Linus Torvalds

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

Pull regmap updates from Mark Brown:
 "Quite a busy release for regmap, mostly support for new features
  useful on fairly small subsets of devices. The user visible features
  are:

   - A new API for registering large numbers of regmap fields at once.

   - Support for Intel AVMM buses connected via SPI.

   - Support for 12/20 address/value layouts.

   - Support for yet another scheme for acknowledging interrupts used on
     some Qualcomm devices"

* tag 'regmap-v5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap:
  regmap: irq: Add support to clear ack registers
  regmap: add support to regmap_field_bulk_alloc/free apis
  regmap: destroy mutex (if used) in regmap_exit()
  regmap: debugfs: use semicolons rather than commas to separate statements
  regmap: debugfs: Fix more error path regressions
  regmap: Add support for 12/20 register formatting
  regmap: Add can_sleep configuration option
  regmap: soundwire: remove unused header mod_devicetable.h
  regmap: Use flexible sleep
  regmap: add Intel SPI Slave to AVMM Bus Bridge support
parents fd5c32d8 6e0545c4
......@@ -4,7 +4,7 @@
# subsystems should select the appropriate symbols.
config REGMAP
default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SOUNDWIRE || REGMAP_SCCB || REGMAP_I3C)
default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SOUNDWIRE || REGMAP_SCCB || REGMAP_I3C || REGMAP_SPI_AVMM)
select IRQ_DOMAIN if REGMAP_IRQ
bool
......@@ -53,3 +53,7 @@ config REGMAP_SCCB
config REGMAP_I3C
tristate
depends on I3C
config REGMAP_SPI_AVMM
tristate
depends on SPI
......@@ -17,3 +17,4 @@ obj-$(CONFIG_REGMAP_W1) += regmap-w1.o
obj-$(CONFIG_REGMAP_SOUNDWIRE) += regmap-sdw.o
obj-$(CONFIG_REGMAP_SCCB) += regmap-sccb.o
obj-$(CONFIG_REGMAP_I3C) += regmap-i3c.o
obj-$(CONFIG_REGMAP_SPI_AVMM) += regmap-spi-avmm.o
......@@ -161,6 +161,9 @@ struct regmap {
void *selector_work_buf; /* Scratch buffer used for selector */
struct hwspinlock *hwlock;
/* if set, the regmap core can sleep */
bool can_sleep;
};
struct regcache_ops {
......
......@@ -183,7 +183,7 @@ static inline void regmap_calc_tot_len(struct regmap *map,
{
/* Calculate the length of a fixed format */
if (!map->debugfs_tot_len) {
map->debugfs_reg_len = regmap_calc_reg_len(map->max_register),
map->debugfs_reg_len = regmap_calc_reg_len(map->max_register);
map->debugfs_val_len = 2 * map->format.val_bytes;
map->debugfs_tot_len = map->debugfs_reg_len +
map->debugfs_val_len + 3; /* : \n */
......
......@@ -168,6 +168,14 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
ret = regmap_write(map, reg, ~d->mask_buf[i]);
else
ret = regmap_write(map, reg, d->mask_buf[i]);
if (d->chip->clear_ack) {
if (d->chip->ack_invert && !ret)
ret = regmap_write(map, reg,
d->mask_buf[i]);
else if (!ret)
ret = regmap_write(map, reg,
~d->mask_buf[i]);
}
if (ret != 0)
dev_err(d->map->dev, "Failed to ack 0x%x: %d\n",
reg, ret);
......@@ -493,7 +501,20 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
if (data->status_buf[i] && (chip->ack_base || chip->use_ack)) {
reg = chip->ack_base +
(i * map->reg_stride * data->irq_reg_stride);
ret = regmap_write(map, reg, data->status_buf[i]);
if (chip->ack_invert)
ret = regmap_write(map, reg,
~data->status_buf[i]);
else
ret = regmap_write(map, reg,
data->status_buf[i]);
if (chip->clear_ack) {
if (chip->ack_invert && !ret)
ret = regmap_write(map, reg,
data->status_buf[i]);
else if (!ret)
ret = regmap_write(map, reg,
~data->status_buf[i]);
}
if (ret != 0)
dev_err(map->dev, "Failed to ack 0x%x: %d\n",
reg, ret);
......@@ -722,6 +743,16 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
else
ret = regmap_write(map, reg,
d->status_buf[i] & d->mask_buf[i]);
if (chip->clear_ack) {
if (chip->ack_invert && !ret)
ret = regmap_write(map, reg,
(d->status_buf[i] &
d->mask_buf[i]));
else if (!ret)
ret = regmap_write(map, reg,
~(d->status_buf[i] &
d->mask_buf[i]));
}
if (ret != 0) {
dev_err(map->dev, "Failed to ack 0x%x: %d\n",
reg, ret);
......
......@@ -2,7 +2,6 @@
// Copyright(c) 2015-17 Intel Corporation.
#include <linux/device.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/soundwire/sdw.h>
#include "internal.h"
......
This diff is collapsed.
......@@ -209,6 +209,18 @@ static bool regmap_volatile_range(struct regmap *map, unsigned int reg,
return true;
}
static void regmap_format_12_20_write(struct regmap *map,
unsigned int reg, unsigned int val)
{
u8 *out = map->work_buf;
out[0] = reg >> 4;
out[1] = (reg << 4) | (val >> 16);
out[2] = val >> 8;
out[3] = val;
}
static void regmap_format_2_6_write(struct regmap *map,
unsigned int reg, unsigned int val)
{
......@@ -711,13 +723,17 @@ struct regmap *__regmap_init(struct device *dev,
if (ret)
goto err_map;
ret = -EINVAL; /* Later error paths rely on this */
if (config->disable_locking) {
map->lock = map->unlock = regmap_lock_unlock_none;
map->can_sleep = config->can_sleep;
regmap_debugfs_disable(map);
} else if (config->lock && config->unlock) {
map->lock = config->lock;
map->unlock = config->unlock;
map->lock_arg = config->lock_arg;
map->can_sleep = config->can_sleep;
} else if (config->use_hwlock) {
map->hwlock = hwspin_lock_request_specific(config->hwlock_id);
if (!map->hwlock) {
......@@ -753,6 +769,7 @@ struct regmap *__regmap_init(struct device *dev,
mutex_init(&map->mutex);
map->lock = regmap_lock_mutex;
map->unlock = regmap_unlock_mutex;
map->can_sleep = true;
lockdep_set_class_and_name(&map->mutex,
lock_key, lock_name);
}
......@@ -883,6 +900,16 @@ struct regmap *__regmap_init(struct device *dev,
}
break;
case 12:
switch (config->val_bits) {
case 20:
map->format.format_write = regmap_format_12_20_write;
break;
default:
goto err_hwlock;
}
break;
case 8:
map->format.format_reg = regmap_format_8;
break;
......@@ -1243,6 +1270,106 @@ struct regmap_field *devm_regmap_field_alloc(struct device *dev,
}
EXPORT_SYMBOL_GPL(devm_regmap_field_alloc);
/**
* regmap_field_bulk_alloc() - Allocate and initialise a bulk register field.
*
* @regmap: regmap bank in which this register field is located.
* @rm_field: regmap register fields within the bank.
* @reg_field: Register fields within the bank.
* @num_fields: Number of register fields.
*
* The return value will be an -ENOMEM on error or zero for success.
* Newly allocated regmap_fields should be freed by calling
* regmap_field_bulk_free()
*/
int regmap_field_bulk_alloc(struct regmap *regmap,
struct regmap_field **rm_field,
struct reg_field *reg_field,
int num_fields)
{
struct regmap_field *rf;
int i;
rf = kcalloc(num_fields, sizeof(*rf), GFP_KERNEL);
if (!rf)
return -ENOMEM;
for (i = 0; i < num_fields; i++) {
regmap_field_init(&rf[i], regmap, reg_field[i]);
rm_field[i] = &rf[i];
}
return 0;
}
EXPORT_SYMBOL_GPL(regmap_field_bulk_alloc);
/**
* devm_regmap_field_bulk_alloc() - Allocate and initialise a bulk register
* fields.
*
* @dev: Device that will be interacted with
* @regmap: regmap bank in which this register field is located.
* @rm_field: regmap register fields within the bank.
* @reg_field: Register fields within the bank.
* @num_fields: Number of register fields.
*
* The return value will be an -ENOMEM on error or zero for success.
* Newly allocated regmap_fields will be automatically freed by the
* device management code.
*/
int devm_regmap_field_bulk_alloc(struct device *dev,
struct regmap *regmap,
struct regmap_field **rm_field,
struct reg_field *reg_field,
int num_fields)
{
struct regmap_field *rf;
int i;
rf = devm_kcalloc(dev, num_fields, sizeof(*rf), GFP_KERNEL);
if (!rf)
return -ENOMEM;
for (i = 0; i < num_fields; i++) {
regmap_field_init(&rf[i], regmap, reg_field[i]);
rm_field[i] = &rf[i];
}
return 0;
}
EXPORT_SYMBOL_GPL(devm_regmap_field_bulk_alloc);
/**
* regmap_field_bulk_free() - Free register field allocated using
* regmap_field_bulk_alloc.
*
* @field: regmap fields which should be freed.
*/
void regmap_field_bulk_free(struct regmap_field *field)
{
kfree(field);
}
EXPORT_SYMBOL_GPL(regmap_field_bulk_free);
/**
* devm_regmap_field_bulk_free() - Free a bulk register field allocated using
* devm_regmap_field_bulk_alloc.
*
* @dev: Device that will be interacted with
* @field: regmap field which should be freed.
*
* Free register field allocated using devm_regmap_field_bulk_alloc(). Usually
* drivers need not call this function, as the memory allocated via devm
* will be freed as per device-driver life-cycle.
*/
void devm_regmap_field_bulk_free(struct device *dev,
struct regmap_field *field)
{
devm_kfree(dev, field);
}
EXPORT_SYMBOL_GPL(devm_regmap_field_bulk_free);
/**
* devm_regmap_field_free() - Free a register field allocated using
* devm_regmap_field_alloc.
......@@ -1365,6 +1492,8 @@ void regmap_exit(struct regmap *map)
}
if (map->hwlock)
hwspin_lock_free(map->hwlock);
if (map->lock == regmap_lock_mutex)
mutex_destroy(&map->mutex);
kfree_const(map->name);
kfree(map->patch);
kfree(map);
......@@ -2253,8 +2382,12 @@ static int _regmap_range_multi_paged_reg_write(struct regmap *map,
if (ret != 0)
return ret;
if (regs[i].delay_us)
udelay(regs[i].delay_us);
if (regs[i].delay_us) {
if (map->can_sleep)
fsleep(regs[i].delay_us);
else
udelay(regs[i].delay_us);
}
base += n;
n = 0;
......@@ -2290,8 +2423,12 @@ static int _regmap_multi_reg_write(struct regmap *map,
if (ret != 0)
return ret;
if (regs[i].delay_us)
udelay(regs[i].delay_us);
if (regs[i].delay_us) {
if (map->can_sleep)
fsleep(regs[i].delay_us);
else
udelay(regs[i].delay_us);
}
}
return 0;
}
......
......@@ -342,6 +342,7 @@ typedef void (*regmap_unlock)(void *);
* @hwlock_id: Specify the hardware spinlock id.
* @hwlock_mode: The hardware spinlock mode, should be HWLOCK_IRQSTATE,
* HWLOCK_IRQ or 0.
* @can_sleep: Optional, specifies whether regmap operations can sleep.
*/
struct regmap_config {
const char *name;
......@@ -398,6 +399,8 @@ struct regmap_config {
bool use_hwlock;
unsigned int hwlock_id;
unsigned int hwlock_mode;
bool can_sleep;
};
/**
......@@ -567,6 +570,10 @@ struct regmap *__regmap_init_sdw(struct sdw_slave *sdw,
const struct regmap_config *config,
struct lock_class_key *lock_key,
const char *lock_name);
struct regmap *__regmap_init_spi_avmm(struct spi_device *spi,
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,
......@@ -620,6 +627,10 @@ struct regmap *__devm_regmap_init_i3c(struct i3c_device *i3c,
const struct regmap_config *config,
struct lock_class_key *lock_key,
const char *lock_name);
struct regmap *__devm_regmap_init_spi_avmm(struct spi_device *spi,
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.
......@@ -806,6 +817,19 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
__regmap_lockdep_wrapper(__regmap_init_sdw, #config, \
sdw, config)
/**
* regmap_init_spi_avmm() - Initialize register map for Intel SPI Slave
* to AVMM Bus Bridge
*
* @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_avmm(spi, config) \
__regmap_lockdep_wrapper(__regmap_init_spi_avmm, #config, \
spi, config)
/**
* devm_regmap_init() - Initialise managed register map
......@@ -993,6 +1017,21 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
__regmap_lockdep_wrapper(__devm_regmap_init_i3c, #config, \
i3c, config)
/**
* devm_regmap_init_spi_avmm() - Initialize register map for Intel SPI Slave
* to AVMM Bus Bridge
*
* @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_avmm(spi, config) \
__regmap_lockdep_wrapper(__devm_regmap_init_spi_avmm, #config, \
spi, config)
int regmap_mmio_attach_clk(struct regmap *map, struct clk *clk);
void regmap_mmio_detach_clk(struct regmap *map);
void regmap_exit(struct regmap *map);
......@@ -1150,6 +1189,17 @@ struct regmap_field *devm_regmap_field_alloc(struct device *dev,
struct regmap *regmap, struct reg_field reg_field);
void devm_regmap_field_free(struct device *dev, struct regmap_field *field);
int regmap_field_bulk_alloc(struct regmap *regmap,
struct regmap_field **rm_field,
struct reg_field *reg_field,
int num_fields);
void regmap_field_bulk_free(struct regmap_field *field);
int devm_regmap_field_bulk_alloc(struct device *dev, struct regmap *regmap,
struct regmap_field **field,
struct reg_field *reg_field, int num_fields);
void devm_regmap_field_bulk_free(struct device *dev,
struct regmap_field *field);
int regmap_field_read(struct regmap_field *field, unsigned int *val);
int regmap_field_update_bits_base(struct regmap_field *field,
unsigned int mask, unsigned int val,
......@@ -1305,6 +1355,7 @@ struct regmap_irq_sub_irq_map {
* @mask_invert: Inverted mask register: cleared bits are masked out.
* @use_ack: Use @ack register even if it is zero.
* @ack_invert: Inverted ack register: cleared bits for ack.
* @clear_ack: Use this to set 1 and 0 or vice-versa to clear interrupts.
* @wake_invert: Inverted wake register: cleared bits are wake enabled.
* @type_invert: Invert the type flags.
* @type_in_mask: Use the mask registers for controlling irq type. For
......@@ -1353,6 +1404,7 @@ struct regmap_irq_chip {
bool mask_invert:1;
bool use_ack:1;
bool ack_invert:1;
bool clear_ack:1;
bool wake_invert:1;
bool runtime_pm:1;
bool type_invert:1;
......
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