diff options
| -rw-r--r-- | drivers/base/regmap/regmap-i2c.c | 61 | ||||
| -rw-r--r-- | drivers/base/regmap/regmap-irq.c | 84 | ||||
| -rw-r--r-- | drivers/base/regmap/regmap.c | 1 | ||||
| -rw-r--r-- | include/linux/regmap.h | 73 | 
4 files changed, 164 insertions, 55 deletions
| diff --git a/drivers/base/regmap/regmap-i2c.c b/drivers/base/regmap/regmap-i2c.c index 008f8da69d97..62b95a9212ae 100644 --- a/drivers/base/regmap/regmap-i2c.c +++ b/drivers/base/regmap/regmap-i2c.c @@ -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 ®map_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 ®map_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)) diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index 3d64c9331a82..4340e1d268b6 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c @@ -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,9 +557,10 @@ 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, -			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)  {  	struct regmap_irq_chip_data *d;  	int i; @@ -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, -						  ®map_domain_ops, d); +		d->domain = irq_domain_add_legacy(np, chip->num_irqs, irq_base, +						  0, ®map_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,  						  ®map_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,10 +915,11 @@ static int devm_regmap_irq_chip_match(struct device *dev, void *res, void *data)   * The ®map_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) +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)  {  	struct regmap_irq_chip_data **ptr, *d;  	int ret; @@ -903,8 +929,8 @@ 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, -				  chip, &d); +	ret = regmap_add_irq_chip_np(np, map, irq, irq_flags, irq_base, +				     chip, &d);  	if (ret < 0) {  		devres_free(ptr);  		return ret; @@ -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 ®map_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);  /** diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 4ad5c5adc0a3..c472f624382d 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -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; diff --git a/include/linux/regmap.h b/include/linux/regmap.h index ddf0baff195d..cb666b9c6b6a 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -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 @@ -1149,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); @@ -1325,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); | 
