Loading MAINTAINERS +1 −0 Original line number Diff line number Diff line Loading @@ -9600,6 +9600,7 @@ M: Mark Brown <broonie@kernel.org> L: linux-kernel@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git S: Supported F: Documentation/devicetree/bindings/regmap/ F: drivers/base/regmap/ F: include/linux/regmap.h Loading drivers/base/regmap/regmap-i2c.c +1 −1 Original line number Diff line number Diff line Loading @@ -259,7 +259,7 @@ static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c, { if (i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) return ®map_i2c; else if (config->reg_bits == 8 && else if (config->val_bits == 8 && config->reg_bits == 8 && i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) return ®map_i2c_smbus_i2c_block; Loading drivers/base/regmap/regmap-irq.c +11 −4 Original line number Diff line number Diff line Loading @@ -268,13 +268,16 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) bool handled = false; u32 reg; if (chip->handle_pre_irq) chip->handle_pre_irq(chip->irq_drv_data); if (chip->runtime_pm) { ret = pm_runtime_get_sync(map->dev); if (ret < 0) { dev_err(map->dev, "IRQ thread failed to resume: %d\n", ret); pm_runtime_put(map->dev); return IRQ_NONE; goto exit; } } Loading @@ -296,7 +299,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) if (ret != 0) { dev_err(map->dev, "Failed to read IRQ status: %d\n", ret); return IRQ_NONE; goto exit; } for (i = 0; i < data->chip->num_regs; i++) { Loading @@ -312,7 +315,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) break; default: BUG(); return IRQ_NONE; goto exit; } } Loading @@ -329,7 +332,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) ret); if (chip->runtime_pm) pm_runtime_put(map->dev); return IRQ_NONE; goto exit; } } } Loading Loading @@ -365,6 +368,10 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) if (chip->runtime_pm) pm_runtime_put(map->dev); exit: if (chip->handle_post_irq) chip->handle_post_irq(chip->irq_drv_data); if (handled) return IRQ_HANDLED; else Loading drivers/base/regmap/regmap.c +28 −3 Original line number Diff line number Diff line Loading @@ -1777,8 +1777,6 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, size_t val_bytes = map->format.val_bytes; size_t total_size = val_bytes * val_count; if (map->bus && !map->format.parse_inplace) return -EINVAL; if (!IS_ALIGNED(reg, map->reg_stride)) return -EINVAL; Loading @@ -1789,7 +1787,8 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, * * 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 * The second one is for busses that do not provide raw I/O. * The third one is used for busses which do not have these limitations * and can write arbitrary value lengths. */ if (!map->bus) { Loading Loading @@ -1825,6 +1824,32 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, } out: map->unlock(map->lock_arg); } else if (map->bus && !map->format.parse_inplace) { const u8 *u8 = val; const u16 *u16 = val; const u32 *u32 = val; unsigned int ival; for (i = 0; i < val_count; i++) { switch (map->format.val_bytes) { case 4: ival = u32[i]; break; case 2: ival = u16[i]; break; case 1: ival = u8[i]; break; default: return -EINVAL; } ret = regmap_write(map, reg + (i * map->reg_stride), ival); if (ret) return ret; } } else if (map->use_single_write || (map->max_raw_write && map->max_raw_write < total_size)) { int chunk_stride = map->reg_stride; Loading include/linux/regmap.h +49 −0 Original line number Diff line number Diff line Loading @@ -95,6 +95,45 @@ struct reg_sequence { #define regmap_fields_force_update_bits(field, id, mask, val) \ regmap_fields_update_bits_base(field, id, mask, val, NULL, false, true) /** * regmap_read_poll_timeout - Poll until a condition is met or a timeout occurs * @map: Regmap to read from * @addr: Address to poll * @val: Unsigned integer variable to read the value into * @cond: Break condition (usually involving @val) * @sleep_us: Maximum time to sleep between reads in us (0 * tight-loops). Should be less than ~20ms since usleep_range * is used (see Documentation/timers/timers-howto.txt). * @timeout_us: Timeout in us, 0 means never timeout * * Returns 0 on success and -ETIMEDOUT upon a timeout or the regmap_read * error return value in case of a error read. In the two former cases, * the last read value at @addr is stored in @val. Must not be called * from atomic context if sleep_us or timeout_us are used. * * This is modelled after the readx_poll_timeout macros in linux/iopoll.h. */ #define regmap_read_poll_timeout(map, addr, val, cond, sleep_us, timeout_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); \ }) #ifdef CONFIG_REGMAP enum regmap_endian { Loading Loading @@ -851,6 +890,12 @@ struct regmap_irq { * @num_type_reg: Number of type registers. * @type_reg_stride: Stride to use for chips where type registers are not * contiguous. * @handle_pre_irq: Driver specific callback to handle interrupt from device * before regmap_irq_handler process the interrupts. * @handle_post_irq: Driver specific callback to handle interrupt from device * after handling the interrupts in regmap_irq_handler(). * @irq_drv_data: Driver specific IRQ data which is passed as parameter when * driver specific pre/post interrupt handler is called. */ struct regmap_irq_chip { const char *name; Loading @@ -877,6 +922,10 @@ struct regmap_irq_chip { int num_type_reg; unsigned int type_reg_stride; int (*handle_pre_irq)(void *irq_drv_data); int (*handle_post_irq)(void *irq_drv_data); void *irq_drv_data; }; struct regmap_irq_chip_data; Loading Loading
MAINTAINERS +1 −0 Original line number Diff line number Diff line Loading @@ -9600,6 +9600,7 @@ M: Mark Brown <broonie@kernel.org> L: linux-kernel@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git S: Supported F: Documentation/devicetree/bindings/regmap/ F: drivers/base/regmap/ F: include/linux/regmap.h Loading
drivers/base/regmap/regmap-i2c.c +1 −1 Original line number Diff line number Diff line Loading @@ -259,7 +259,7 @@ static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c, { if (i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) return ®map_i2c; else if (config->reg_bits == 8 && else if (config->val_bits == 8 && config->reg_bits == 8 && i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) return ®map_i2c_smbus_i2c_block; Loading
drivers/base/regmap/regmap-irq.c +11 −4 Original line number Diff line number Diff line Loading @@ -268,13 +268,16 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) bool handled = false; u32 reg; if (chip->handle_pre_irq) chip->handle_pre_irq(chip->irq_drv_data); if (chip->runtime_pm) { ret = pm_runtime_get_sync(map->dev); if (ret < 0) { dev_err(map->dev, "IRQ thread failed to resume: %d\n", ret); pm_runtime_put(map->dev); return IRQ_NONE; goto exit; } } Loading @@ -296,7 +299,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) if (ret != 0) { dev_err(map->dev, "Failed to read IRQ status: %d\n", ret); return IRQ_NONE; goto exit; } for (i = 0; i < data->chip->num_regs; i++) { Loading @@ -312,7 +315,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) break; default: BUG(); return IRQ_NONE; goto exit; } } Loading @@ -329,7 +332,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) ret); if (chip->runtime_pm) pm_runtime_put(map->dev); return IRQ_NONE; goto exit; } } } Loading Loading @@ -365,6 +368,10 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) if (chip->runtime_pm) pm_runtime_put(map->dev); exit: if (chip->handle_post_irq) chip->handle_post_irq(chip->irq_drv_data); if (handled) return IRQ_HANDLED; else Loading
drivers/base/regmap/regmap.c +28 −3 Original line number Diff line number Diff line Loading @@ -1777,8 +1777,6 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, size_t val_bytes = map->format.val_bytes; size_t total_size = val_bytes * val_count; if (map->bus && !map->format.parse_inplace) return -EINVAL; if (!IS_ALIGNED(reg, map->reg_stride)) return -EINVAL; Loading @@ -1789,7 +1787,8 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, * * 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 * The second one is for busses that do not provide raw I/O. * The third one is used for busses which do not have these limitations * and can write arbitrary value lengths. */ if (!map->bus) { Loading Loading @@ -1825,6 +1824,32 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, } out: map->unlock(map->lock_arg); } else if (map->bus && !map->format.parse_inplace) { const u8 *u8 = val; const u16 *u16 = val; const u32 *u32 = val; unsigned int ival; for (i = 0; i < val_count; i++) { switch (map->format.val_bytes) { case 4: ival = u32[i]; break; case 2: ival = u16[i]; break; case 1: ival = u8[i]; break; default: return -EINVAL; } ret = regmap_write(map, reg + (i * map->reg_stride), ival); if (ret) return ret; } } else if (map->use_single_write || (map->max_raw_write && map->max_raw_write < total_size)) { int chunk_stride = map->reg_stride; Loading
include/linux/regmap.h +49 −0 Original line number Diff line number Diff line Loading @@ -95,6 +95,45 @@ struct reg_sequence { #define regmap_fields_force_update_bits(field, id, mask, val) \ regmap_fields_update_bits_base(field, id, mask, val, NULL, false, true) /** * regmap_read_poll_timeout - Poll until a condition is met or a timeout occurs * @map: Regmap to read from * @addr: Address to poll * @val: Unsigned integer variable to read the value into * @cond: Break condition (usually involving @val) * @sleep_us: Maximum time to sleep between reads in us (0 * tight-loops). Should be less than ~20ms since usleep_range * is used (see Documentation/timers/timers-howto.txt). * @timeout_us: Timeout in us, 0 means never timeout * * Returns 0 on success and -ETIMEDOUT upon a timeout or the regmap_read * error return value in case of a error read. In the two former cases, * the last read value at @addr is stored in @val. Must not be called * from atomic context if sleep_us or timeout_us are used. * * This is modelled after the readx_poll_timeout macros in linux/iopoll.h. */ #define regmap_read_poll_timeout(map, addr, val, cond, sleep_us, timeout_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); \ }) #ifdef CONFIG_REGMAP enum regmap_endian { Loading Loading @@ -851,6 +890,12 @@ struct regmap_irq { * @num_type_reg: Number of type registers. * @type_reg_stride: Stride to use for chips where type registers are not * contiguous. * @handle_pre_irq: Driver specific callback to handle interrupt from device * before regmap_irq_handler process the interrupts. * @handle_post_irq: Driver specific callback to handle interrupt from device * after handling the interrupts in regmap_irq_handler(). * @irq_drv_data: Driver specific IRQ data which is passed as parameter when * driver specific pre/post interrupt handler is called. */ struct regmap_irq_chip { const char *name; Loading @@ -877,6 +922,10 @@ struct regmap_irq_chip { int num_type_reg; unsigned int type_reg_stride; int (*handle_pre_irq)(void *irq_drv_data); int (*handle_post_irq)(void *irq_drv_data); void *irq_drv_data; }; struct regmap_irq_chip_data; Loading