mirror of
https://github.com/torvalds/linux.git
synced 2024-11-15 16:41:58 +00:00
regmap: Updates for v4.8
Several small updates and API enhancements: - Provide transparent unrolling of bulk writes into individual writes so they can be used with devices without raw formatting. - Fix compatibility between I2C controllers supporting block commands and devices with more than 8 bit wide registers. - Add some helpers for iopoll-like functionality and workarounds for weird interrupt controllers. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJXljTLAAoJECTWi3JdVIfQMSMH/1MRirJkwIds0SRbWcnG9hOe nMfUhkuFuCZJN82GwOh7YbAxLB1pGXKsGZq1XGMYFvwJawEizR3o83fgcRy1LQmG KOQHO1O/CWQqRo1ntGl33H2thhq6e67y6lpeMBhdMvp3VjqdyzlILNSva6iWbW/R N0iFSSKd4VdHlg/o+R3k7EzWCLZ4FZI7B9/5OjxWkoUR+tloNI8rR8Ecwl6+Q37K 8+yo6R0Ntx/JXB7JvA5Y8vqPdUGi68+XpcnaAcpM5DaL95+lqzduWCjKfjG5oatZ 3o/ORRVi+WyD95/NLXwKFMvSDSGokVDrU87HNgKph+f4sNF5TIoC/E+JhPUQBSU= =7BlM -----END PGP SIGNATURE----- Merge tag 'regmap-v4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap Pull regmap updates from Mark Brown: "Several small updates and API enhancements: - provide transparent unrolling of bulk writes into individual writes so they can be used with devices without raw formatting. - fix compatibility between I2C controllers supporting block commands and devices with more than 8 bit wide registers. - add some helpers for iopoll-like functionality and workarounds for weird interrupt controllers" * tag 'regmap-v4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap: regmap: add iopoll-like polling macro regmap: Support bulk writes for devices without raw formatting regmap-i2c: Use i2c block command only if register value width is 8 bit regmap: irq: Add support to call client specific pre/post interrupt service regmap: Add file patterns for regmap device tree bindings
This commit is contained in:
commit
ae9799975c
@ -9691,6 +9691,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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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++) {
|
||||
@ -312,7 +315,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
return IRQ_NONE;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
@ -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;
|
||||
|
||||
@ -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) {
|
||||
@ -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;
|
||||
|
@ -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 {
|
||||
@ -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;
|
||||
@ -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…
Reference in New Issue
Block a user