Commit 213fd09e authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull regmap updates from Mark Brown:
 "This has been a very active release for the regmap API for some
  reason, a lot of it due to new devices with odd requirements that can
  sensibly be handled here.

   - Add support for buses implementing a custom reg_update_bits()
     method in case the bus has a native operation for this.

   - Support 16 bit register addresses in SMBus.

   - Allow customization of the device attached to regmap-irq.

   - Helpers for bitfield operations and per-port field initializations"

* tag 'regmap-v5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap:
  regmap: provide helpers for simple bit operations
  regmap: add helper for per-port regfield initialization
  regmap-i2c: add 16-bit width registers support
  regmap: Simplify implementation of the regmap_field_read_poll_timeout() macro
  regmap: Simplify implementation of the regmap_read_poll_timeout() macro
  regmap: add reg_sequence helpers
  regmap-irq: make it possible to add irq_chip do a specific device node
  regmap: Add bus reg_update_bits() support
  regmap: debugfs: check count when read regmap file
parents 129b9a5c 9b98f92c
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -227,6 +227,9 @@ static ssize_t regmap_read_debugfs(struct regmap *map, unsigned int from,
	if (*ppos < 0 || !count)
		return -EINVAL;

	if (count > (PAGE_SIZE << (MAX_ORDER - 1)))
		count = PAGE_SIZE << (MAX_ORDER - 1);

	buf = kmalloc(count, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;
@@ -371,6 +374,9 @@ static ssize_t regmap_reg_ranges_read_file(struct file *file,
	if (*ppos < 0 || !count)
		return -EINVAL;

	if (count > (PAGE_SIZE << (MAX_ORDER - 1)))
		count = PAGE_SIZE << (MAX_ORDER - 1);

	buf = kmalloc(count, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;
+61 −0
Original line number Diff line number Diff line
@@ -246,6 +246,63 @@ static const struct regmap_bus regmap_i2c_smbus_i2c_block = {
	.max_raw_write = I2C_SMBUS_BLOCK_MAX,
};

static int regmap_i2c_smbus_i2c_write_reg16(void *context, const void *data,
				      size_t count)
{
	struct device *dev = context;
	struct i2c_client *i2c = to_i2c_client(dev);

	if (count < 2)
		return -EINVAL;

	count--;
	return i2c_smbus_write_i2c_block_data(i2c, ((u8 *)data)[0], count,
					      (u8 *)data + 1);
}

static int regmap_i2c_smbus_i2c_read_reg16(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, count, len = val_size;

	if (reg_size != 2)
		return -EINVAL;

	ret = i2c_smbus_write_byte_data(i2c, ((u16 *)reg)[0] & 0xff,
					((u16 *)reg)[0] >> 8);
	if (ret < 0)
		return ret;

	count = 0;
	do {
		/* Current Address Read */
		ret = i2c_smbus_read_byte(i2c);
		if (ret < 0)
			break;

		*((u8 *)val++) = ret;
		count++;
		len--;
	} while (len > 0);

	if (count == val_size)
		return 0;
	else if (ret < 0)
		return ret;
	else
		return -EIO;
}

static const struct regmap_bus regmap_i2c_smbus_i2c_block_reg16 = {
	.write = regmap_i2c_smbus_i2c_write_reg16,
	.read = regmap_i2c_smbus_i2c_read_reg16,
	.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,
					const struct regmap_config *config)
{
@@ -255,6 +312,10 @@ static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c,
		 i2c_check_functionality(i2c->adapter,
					 I2C_FUNC_SMBUS_I2C_BLOCK))
		return &regmap_i2c_smbus_i2c_block;
	else if (config->val_bits == 8 && config->reg_bits == 16 &&
		i2c_check_functionality(i2c->adapter,
					I2C_FUNC_SMBUS_I2C_BLOCK))
		return &regmap_i2c_smbus_i2c_block_reg16;
	else if (config->val_bits == 16 && config->reg_bits == 8 &&
		 i2c_check_functionality(i2c->adapter,
					 I2C_FUNC_SMBUS_WORD_DATA))
+68 −16
Original line number Diff line number Diff line
@@ -541,8 +541,9 @@ static const struct irq_domain_ops regmap_domain_ops = {
};

/**
 * regmap_add_irq_chip() - Use standard regmap IRQ controller handling
 * regmap_add_irq_chip_np() - Use standard regmap IRQ controller handling
 *
 * @np: The device_node where the IRQ domain should be added to.
 * @map: The regmap for the device.
 * @irq: The IRQ the device uses to signal interrupts.
 * @irq_flags: The IRQF_ flags to use for the primary interrupt.
@@ -556,8 +557,9 @@ static const struct irq_domain_ops regmap_domain_ops = {
 * register cache.  The chip driver is responsible for restoring the
 * register values used by the IRQ controller over suspend and resume.
 */
int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
			int irq_base, const struct regmap_irq_chip *chip,
int regmap_add_irq_chip_np(struct device_node *np, struct regmap *map, int irq,
			   int irq_flags, int irq_base,
			   const struct regmap_irq_chip *chip,
			   struct regmap_irq_chip_data **data)
{
	struct regmap_irq_chip_data *d;
@@ -769,12 +771,10 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
	}

	if (irq_base)
		d->domain = irq_domain_add_legacy(map->dev->of_node,
						  chip->num_irqs, irq_base, 0,
						  &regmap_domain_ops, d);
		d->domain = irq_domain_add_legacy(np, chip->num_irqs, irq_base,
						  0, &regmap_domain_ops, d);
	else
		d->domain = irq_domain_add_linear(map->dev->of_node,
						  chip->num_irqs,
		d->domain = irq_domain_add_linear(np, chip->num_irqs,
						  &regmap_domain_ops, d);
	if (!d->domain) {
		dev_err(map->dev, "Failed to create IRQ domain\n");
@@ -808,6 +808,30 @@ err_alloc:
	kfree(d);
	return ret;
}
EXPORT_SYMBOL_GPL(regmap_add_irq_chip_np);

/**
 * regmap_add_irq_chip() - Use standard regmap IRQ controller handling
 *
 * @map: The regmap for the device.
 * @irq: The IRQ the device uses to signal interrupts.
 * @irq_flags: The IRQF_ flags to use for the primary interrupt.
 * @irq_base: Allocate at specific IRQ number if irq_base > 0.
 * @chip: Configuration for the interrupt controller.
 * @data: Runtime data structure for the controller, allocated on success.
 *
 * Returns 0 on success or an errno on failure.
 *
 * This is the same as regmap_add_irq_chip_np, except that the device
 * node of the regmap is used.
 */
int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
			int irq_base, const struct regmap_irq_chip *chip,
			struct regmap_irq_chip_data **data)
{
	return regmap_add_irq_chip_np(map->dev->of_node, map, irq, irq_flags,
				      irq_base, chip, data);
}
EXPORT_SYMBOL_GPL(regmap_add_irq_chip);

/**
@@ -875,9 +899,10 @@ static int devm_regmap_irq_chip_match(struct device *dev, void *res, void *data)
}

/**
 * devm_regmap_add_irq_chip() - Resource manager regmap_add_irq_chip()
 * devm_regmap_add_irq_chip_np() - Resource manager regmap_add_irq_chip_np()
 *
 * @dev: The device pointer on which irq_chip belongs to.
 * @np: The device_node where the IRQ domain should be added to.
 * @map: The regmap for the device.
 * @irq: The IRQ the device uses to signal interrupts
 * @irq_flags: The IRQF_ flags to use for the primary interrupt.
@@ -890,8 +915,9 @@ static int devm_regmap_irq_chip_match(struct device *dev, void *res, void *data)
 * The &regmap_irq_chip_data will be automatically released when the device is
 * unbound.
 */
int devm_regmap_add_irq_chip(struct device *dev, struct regmap *map, int irq,
			     int irq_flags, int irq_base,
int devm_regmap_add_irq_chip_np(struct device *dev, struct device_node *np,
				struct regmap *map, int irq, int irq_flags,
				int irq_base,
				const struct regmap_irq_chip *chip,
				struct regmap_irq_chip_data **data)
{
@@ -903,7 +929,7 @@ int devm_regmap_add_irq_chip(struct device *dev, struct regmap *map, int irq,
	if (!ptr)
		return -ENOMEM;

	ret = regmap_add_irq_chip(map, irq, irq_flags, irq_base,
	ret = regmap_add_irq_chip_np(np, map, irq, irq_flags, irq_base,
				     chip, &d);
	if (ret < 0) {
		devres_free(ptr);
@@ -915,6 +941,32 @@ int devm_regmap_add_irq_chip(struct device *dev, struct regmap *map, int irq,
	*data = d;
	return 0;
}
EXPORT_SYMBOL_GPL(devm_regmap_add_irq_chip_np);

/**
 * devm_regmap_add_irq_chip() - Resource manager regmap_add_irq_chip()
 *
 * @dev: The device pointer on which irq_chip belongs to.
 * @map: The regmap for the device.
 * @irq: The IRQ the device uses to signal interrupts
 * @irq_flags: The IRQF_ flags to use for the primary interrupt.
 * @irq_base: Allocate at specific IRQ number if irq_base > 0.
 * @chip: Configuration for the interrupt controller.
 * @data: Runtime data structure for the controller, allocated on success
 *
 * Returns 0 on success or an errno on failure.
 *
 * The &regmap_irq_chip_data will be automatically released when the device is
 * unbound.
 */
int devm_regmap_add_irq_chip(struct device *dev, struct regmap *map, int irq,
			     int irq_flags, int irq_base,
			     const struct regmap_irq_chip *chip,
			     struct regmap_irq_chip_data **data)
{
	return devm_regmap_add_irq_chip_np(dev, map->dev->of_node, map, irq,
					   irq_flags, irq_base, chip, data);
}
EXPORT_SYMBOL_GPL(devm_regmap_add_irq_chip);

/**
+23 −0
Original line number Diff line number Diff line
@@ -827,6 +827,7 @@ struct regmap *__regmap_init(struct device *dev,
	} else if (!bus->read || !bus->write) {
		map->reg_read = _regmap_bus_reg_read;
		map->reg_write = _regmap_bus_reg_write;
		map->reg_update_bits = bus->reg_update_bits;

		map->defer_caching = false;
		goto skip_format_initialization;
@@ -2936,6 +2937,28 @@ int regmap_update_bits_base(struct regmap *map, unsigned int reg,
}
EXPORT_SYMBOL_GPL(regmap_update_bits_base);

/**
 * regmap_test_bits() - Check if all specified bits are set in a register.
 *
 * @map: Register map to operate on
 * @reg: Register to read from
 * @bits: Bits to test
 *
 * Returns -1 if the underlying regmap_read() fails, 0 if at least one of the
 * tested bits is not set and 1 if all tested bits are set.
 */
int regmap_test_bits(struct regmap *map, unsigned int reg, unsigned int bits)
{
	unsigned int val, ret;

	ret = regmap_read(map, reg, &val);
	if (ret)
		return ret;

	return (val & bits) == bits;
}
EXPORT_SYMBOL_GPL(regmap_test_bits);

void regmap_async_complete_cb(struct regmap_async *async, int ret)
{
	struct regmap *map = async->map;
+70 −39
Original line number Diff line number Diff line
@@ -17,10 +17,12 @@
#include <linux/err.h>
#include <linux/bug.h>
#include <linux/lockdep.h>
#include <linux/iopoll.h>

struct module;
struct clk;
struct device;
struct device_node;
struct i2c_client;
struct i3c_device;
struct irq_domain;
@@ -71,6 +73,13 @@ struct reg_sequence {
	unsigned int delay_us;
};

#define REG_SEQ(_reg, _def, _delay_us) {		\
				.reg = _reg,		\
				.def = _def,		\
				.delay_us = _delay_us,	\
				}
#define REG_SEQ0(_reg, _def)	REG_SEQ(_reg, _def, 0)

#define	regmap_update_bits(map, reg, mask, val) \
	regmap_update_bits_base(map, reg, mask, val, NULL, false, false)
#define	regmap_update_bits_async(map, reg, mask, val)\
@@ -122,26 +131,10 @@ struct reg_sequence {
 */
#define regmap_read_poll_timeout(map, addr, val, cond, sleep_us, timeout_us) \
({ \
	u64 __timeout_us = (timeout_us); \
	unsigned long __sleep_us = (sleep_us); \
	ktime_t __timeout = ktime_add_us(ktime_get(), __timeout_us); \
	int __ret; \
	might_sleep_if(__sleep_us); \
	for (;;) { \
		__ret = regmap_read((map), (addr), &(val)); \
		if (__ret) \
			break; \
		if (cond) \
			break; \
		if ((__timeout_us) && \
		    ktime_compare(ktime_get(), __timeout) > 0) { \
			__ret = regmap_read((map), (addr), &(val)); \
			break; \
		} \
		if (__sleep_us) \
			usleep_range((__sleep_us >> 2) + 1, __sleep_us); \
	} \
	__ret ?: ((cond) ? 0 : -ETIMEDOUT); \
	int __ret, __tmp; \
	__tmp = read_poll_timeout(regmap_read, __ret, __ret || (cond), \
			sleep_us, timeout_us, false, (map), (addr), &(val)); \
	__ret ?: __tmp; \
})

/**
@@ -209,25 +202,10 @@ struct reg_sequence {
 */
#define regmap_field_read_poll_timeout(field, val, cond, sleep_us, timeout_us) \
({ \
	u64 __timeout_us = (timeout_us); \
	unsigned long __sleep_us = (sleep_us); \
	ktime_t timeout = ktime_add_us(ktime_get(), __timeout_us); \
	int pollret; \
	might_sleep_if(__sleep_us); \
	for (;;) { \
		pollret = regmap_field_read((field), &(val)); \
		if (pollret) \
			break; \
		if (cond) \
			break; \
		if (__timeout_us && ktime_compare(ktime_get(), timeout) > 0) { \
			pollret = regmap_field_read((field), &(val)); \
			break; \
		} \
		if (__sleep_us) \
			usleep_range((__sleep_us >> 2) + 1, __sleep_us); \
	} \
	pollret ?: ((cond) ? 0 : -ETIMEDOUT); \
	int __ret, __tmp; \
	__tmp = read_poll_timeout(regmap_field_read, __ret, __ret || (cond), \
			sleep_us, timeout_us, false, (field), &(val)); \
	__ret ?: __tmp; \
})

#ifdef CONFIG_REGMAP
@@ -1111,6 +1089,21 @@ bool regmap_reg_in_ranges(unsigned int reg,
			  const struct regmap_range *ranges,
			  unsigned int nranges);

static inline int regmap_set_bits(struct regmap *map,
				  unsigned int reg, unsigned int bits)
{
	return regmap_update_bits_base(map, reg, bits, bits,
				       NULL, false, false);
}

static inline int regmap_clear_bits(struct regmap *map,
				    unsigned int reg, unsigned int bits)
{
	return regmap_update_bits_base(map, reg, bits, 0, NULL, false, false);
}

int regmap_test_bits(struct regmap *map, unsigned int reg, unsigned int bits);

/**
 * struct reg_field - Description of an register field
 *
@@ -1134,6 +1127,14 @@ struct reg_field {
				.msb = _msb,	\
				}

#define REG_FIELD_ID(_reg, _lsb, _msb, _size, _offset) {	\
				.reg = _reg,			\
				.lsb = _lsb,			\
				.msb = _msb,			\
				.id_size = _size,		\
				.id_offset = _offset,		\
				}

struct regmap_field *regmap_field_alloc(struct regmap *regmap,
		struct reg_field reg_field);
void regmap_field_free(struct regmap_field *field);
@@ -1310,12 +1311,21 @@ struct regmap_irq_chip_data;
int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
			int irq_base, const struct regmap_irq_chip *chip,
			struct regmap_irq_chip_data **data);
int regmap_add_irq_chip_np(struct device_node *np, struct regmap *map, int irq,
			   int irq_flags, int irq_base,
			   const struct regmap_irq_chip *chip,
			   struct regmap_irq_chip_data **data);
void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *data);

int devm_regmap_add_irq_chip(struct device *dev, struct regmap *map, int irq,
			     int irq_flags, int irq_base,
			     const struct regmap_irq_chip *chip,
			     struct regmap_irq_chip_data **data);
int devm_regmap_add_irq_chip_np(struct device *dev, struct device_node *np,
				struct regmap *map, int irq, int irq_flags,
				int irq_base,
				const struct regmap_irq_chip *chip,
				struct regmap_irq_chip_data **data);
void devm_regmap_del_irq_chip(struct device *dev, int irq,
			      struct regmap_irq_chip_data *data);

@@ -1410,6 +1420,27 @@ static inline int regmap_update_bits_base(struct regmap *map, unsigned int reg,
	return -EINVAL;
}

static inline int regmap_set_bits(struct regmap *map,
				  unsigned int reg, unsigned int bits)
{
	WARN_ONCE(1, "regmap API is disabled");
	return -EINVAL;
}

static inline int regmap_clear_bits(struct regmap *map,
				    unsigned int reg, unsigned int bits)
{
	WARN_ONCE(1, "regmap API is disabled");
	return -EINVAL;
}

static inline int regmap_test_bits(struct regmap *map,
				   unsigned int reg, unsigned int bits)
{
	WARN_ONCE(1, "regmap API is disabled");
	return -EINVAL;
}

static inline int regmap_field_update_bits_base(struct regmap_field *field,
					unsigned int mask, unsigned int val,
					bool *change, bool async, bool force)