diff options
Diffstat (limited to 'drivers/base/regmap/regmap.c')
-rw-r--r-- | drivers/base/regmap/regmap.c | 329 |
1 files changed, 160 insertions, 169 deletions
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 4ac63c0e50c7..4b89c95a5dec 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -245,6 +245,28 @@ static void regmap_format_32_native(void *buf, unsigned int val, *(u32 *)buf = val << shift; } +#ifdef CONFIG_64BIT +static void regmap_format_64_be(void *buf, unsigned int val, unsigned int shift) +{ + __be64 *b = buf; + + b[0] = cpu_to_be64((u64)val << shift); +} + +static void regmap_format_64_le(void *buf, unsigned int val, unsigned int shift) +{ + __le64 *b = buf; + + b[0] = cpu_to_le64((u64)val << shift); +} + +static void regmap_format_64_native(void *buf, unsigned int val, + unsigned int shift) +{ + *(u64 *)buf = (u64)val << shift; +} +#endif + static void regmap_parse_inplace_noop(void *buf) { } @@ -332,6 +354,41 @@ static unsigned int regmap_parse_32_native(const void *buf) return *(u32 *)buf; } +#ifdef CONFIG_64BIT +static unsigned int regmap_parse_64_be(const void *buf) +{ + const __be64 *b = buf; + + return be64_to_cpu(b[0]); +} + +static unsigned int regmap_parse_64_le(const void *buf) +{ + const __le64 *b = buf; + + return le64_to_cpu(b[0]); +} + +static void regmap_parse_64_be_inplace(void *buf) +{ + __be64 *b = buf; + + b[0] = be64_to_cpu(b[0]); +} + +static void regmap_parse_64_le_inplace(void *buf) +{ + __le64 *b = buf; + + b[0] = le64_to_cpu(b[0]); +} + +static unsigned int regmap_parse_64_native(const void *buf) +{ + return *(u64 *)buf; +} +#endif + static void regmap_lock_mutex(void *__map) { struct regmap *map = __map; @@ -500,6 +557,8 @@ enum regmap_endian regmap_get_val_endian(struct device *dev, endian = REGMAP_ENDIAN_BIG; else if (of_property_read_bool(np, "little-endian")) endian = REGMAP_ENDIAN_LITTLE; + else if (of_property_read_bool(np, "native-endian")) + endian = REGMAP_ENDIAN_NATIVE; /* If the endianness was specified in DT, use that */ if (endian != REGMAP_ENDIAN_DEFAULT) @@ -712,6 +771,21 @@ struct regmap *__regmap_init(struct device *dev, } break; +#ifdef CONFIG_64BIT + case 64: + switch (reg_endian) { + case REGMAP_ENDIAN_BIG: + map->format.format_reg = regmap_format_64_be; + break; + case REGMAP_ENDIAN_NATIVE: + map->format.format_reg = regmap_format_64_native; + break; + default: + goto err_map; + } + break; +#endif + default: goto err_map; } @@ -771,6 +845,28 @@ struct regmap *__regmap_init(struct device *dev, goto err_map; } break; +#ifdef CONFIG_64BIT + case 64: + switch (val_endian) { + case REGMAP_ENDIAN_BIG: + map->format.format_val = regmap_format_64_be; + map->format.parse_val = regmap_parse_64_be; + map->format.parse_inplace = regmap_parse_64_be_inplace; + break; + case REGMAP_ENDIAN_LITTLE: + map->format.format_val = regmap_format_64_le; + map->format.parse_val = regmap_parse_64_le; + map->format.parse_inplace = regmap_parse_64_le_inplace; + break; + case REGMAP_ENDIAN_NATIVE: + map->format.format_val = regmap_format_64_native; + map->format.parse_val = regmap_parse_64_native; + break; + default: + goto err_map; + } + break; +#endif } if (map->format.format_write) { @@ -1513,7 +1609,7 @@ int regmap_write(struct regmap *map, unsigned int reg, unsigned int val) { int ret; - if (reg % map->reg_stride) + if (!IS_ALIGNED(reg, map->reg_stride)) return -EINVAL; map->lock(map->lock_arg); @@ -1540,7 +1636,7 @@ int regmap_write_async(struct regmap *map, unsigned int reg, unsigned int val) { int ret; - if (reg % map->reg_stride) + if (!IS_ALIGNED(reg, map->reg_stride)) return -EINVAL; map->lock(map->lock_arg); @@ -1596,100 +1692,63 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, EXPORT_SYMBOL_GPL(regmap_raw_write); /** - * regmap_field_write(): Write a value to a single register field - * - * @field: Register field to write to - * @val: Value to be written - * - * A value of zero will be returned on success, a negative errno will - * be returned in error cases. - */ -int regmap_field_write(struct regmap_field *field, unsigned int val) -{ - return regmap_update_bits(field->regmap, field->reg, - field->mask, val << field->shift); -} -EXPORT_SYMBOL_GPL(regmap_field_write); - -/** - * regmap_field_update_bits(): Perform a read/modify/write cycle - * on the register field + * regmap_field_update_bits_base(): + * Perform a read/modify/write cycle on the register field + * with change, async, force option * * @field: Register field to write to * @mask: Bitmask to change * @val: Value to be written + * @change: Boolean indicating if a write was done + * @async: Boolean indicating asynchronously + * @force: Boolean indicating use force update * * A value of zero will be returned on success, a negative errno will * be returned in error cases. */ -int regmap_field_update_bits(struct regmap_field *field, unsigned int mask, unsigned int val) +int regmap_field_update_bits_base(struct regmap_field *field, + unsigned int mask, unsigned int val, + bool *change, bool async, bool force) { mask = (mask << field->shift) & field->mask; - return regmap_update_bits(field->regmap, field->reg, - mask, val << field->shift); -} -EXPORT_SYMBOL_GPL(regmap_field_update_bits); - -/** - * regmap_fields_write(): Write a value to a single register field with port ID - * - * @field: Register field to write to - * @id: port ID - * @val: Value to be written - * - * A value of zero will be returned on success, a negative errno will - * be returned in error cases. - */ -int regmap_fields_write(struct regmap_field *field, unsigned int id, - unsigned int val) -{ - if (id >= field->id_size) - return -EINVAL; - - return regmap_update_bits(field->regmap, - field->reg + (field->id_offset * id), - field->mask, val << field->shift); -} -EXPORT_SYMBOL_GPL(regmap_fields_write); - -int regmap_fields_force_write(struct regmap_field *field, unsigned int id, - unsigned int val) -{ - if (id >= field->id_size) - return -EINVAL; - - return regmap_write_bits(field->regmap, - field->reg + (field->id_offset * id), - field->mask, val << field->shift); + return regmap_update_bits_base(field->regmap, field->reg, + mask, val << field->shift, + change, async, force); } -EXPORT_SYMBOL_GPL(regmap_fields_force_write); +EXPORT_SYMBOL_GPL(regmap_field_update_bits_base); /** - * regmap_fields_update_bits(): Perform a read/modify/write cycle - * on the register field + * regmap_fields_update_bits_base(): + * Perform a read/modify/write cycle on the register field + * with change, async, force option * * @field: Register field to write to * @id: port ID * @mask: Bitmask to change * @val: Value to be written + * @change: Boolean indicating if a write was done + * @async: Boolean indicating asynchronously + * @force: Boolean indicating use force update * * A value of zero will be returned on success, a negative errno will * be returned in error cases. */ -int regmap_fields_update_bits(struct regmap_field *field, unsigned int id, - unsigned int mask, unsigned int val) +int regmap_fields_update_bits_base(struct regmap_field *field, unsigned int id, + unsigned int mask, unsigned int val, + bool *change, bool async, bool force) { if (id >= field->id_size) return -EINVAL; mask = (mask << field->shift) & field->mask; - return regmap_update_bits(field->regmap, - field->reg + (field->id_offset * id), - mask, val << field->shift); + return regmap_update_bits_base(field->regmap, + field->reg + (field->id_offset * id), + mask, val << field->shift, + change, async, force); } -EXPORT_SYMBOL_GPL(regmap_fields_update_bits); +EXPORT_SYMBOL_GPL(regmap_fields_update_bits_base); /* * regmap_bulk_write(): Write multiple registers to the device @@ -1714,7 +1773,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, if (map->bus && !map->format.parse_inplace) return -EINVAL; - if (reg % map->reg_stride) + if (!IS_ALIGNED(reg, map->reg_stride)) return -EINVAL; /* @@ -1983,7 +2042,7 @@ static int _regmap_multi_reg_write(struct regmap *map, int reg = regs[i].reg; if (!map->writeable_reg(map->dev, reg)) return -EINVAL; - if (reg % map->reg_stride) + if (!IS_ALIGNED(reg, map->reg_stride)) return -EINVAL; } @@ -2133,7 +2192,7 @@ int regmap_raw_write_async(struct regmap *map, unsigned int reg, if (val_len % map->format.val_bytes) return -EINVAL; - if (reg % map->reg_stride) + if (!IS_ALIGNED(reg, map->reg_stride)) return -EINVAL; map->lock(map->lock_arg); @@ -2159,6 +2218,9 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, WARN_ON(!map->bus); + if (!map->bus || !map->bus->read) + return -EINVAL; + range = _regmap_range_lookup(map, reg); if (range) { ret = _regmap_select_page(map, ®, range, @@ -2260,7 +2322,7 @@ int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val) { int ret; - if (reg % map->reg_stride) + if (!IS_ALIGNED(reg, map->reg_stride)) return -EINVAL; map->lock(map->lock_arg); @@ -2296,7 +2358,7 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val, return -EINVAL; if (val_len % map->format.val_bytes) return -EINVAL; - if (reg % map->reg_stride) + if (!IS_ALIGNED(reg, map->reg_stride)) return -EINVAL; if (val_count == 0) return -EINVAL; @@ -2414,7 +2476,7 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, size_t val_bytes = map->format.val_bytes; bool vol = regmap_volatile_range(map, reg, val_count); - if (reg % map->reg_stride) + if (!IS_ALIGNED(reg, map->reg_stride)) return -EINVAL; if (map->bus && map->format.parse_inplace && (vol || map->cache_type == REGCACHE_NONE)) { @@ -2488,11 +2550,19 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, * we assume that the values are native * endian. */ +#ifdef CONFIG_64BIT + u64 *u64 = val; +#endif u32 *u32 = val; u16 *u16 = val; u8 *u8 = val; switch (map->format.val_bytes) { +#ifdef CONFIG_64BIT + case 8: + u64[i] = ival; + break; +#endif case 4: u32[i] = ival; break; @@ -2546,76 +2616,36 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg, } /** - * regmap_update_bits: Perform a read/modify/write cycle on the register map - * - * @map: Register map to update - * @reg: Register to update - * @mask: Bitmask to change - * @val: New value for bitmask - * - * Returns zero for success, a negative number on error. - */ -int regmap_update_bits(struct regmap *map, unsigned int reg, - unsigned int mask, unsigned int val) -{ - int ret; - - map->lock(map->lock_arg); - ret = _regmap_update_bits(map, reg, mask, val, NULL, false); - map->unlock(map->lock_arg); - - return ret; -} -EXPORT_SYMBOL_GPL(regmap_update_bits); - -/** - * regmap_write_bits: Perform a read/modify/write cycle on the register map - * - * @map: Register map to update - * @reg: Register to update - * @mask: Bitmask to change - * @val: New value for bitmask - * - * Returns zero for success, a negative number on error. - */ -int regmap_write_bits(struct regmap *map, unsigned int reg, - unsigned int mask, unsigned int val) -{ - int ret; - - map->lock(map->lock_arg); - ret = _regmap_update_bits(map, reg, mask, val, NULL, true); - map->unlock(map->lock_arg); - - return ret; -} -EXPORT_SYMBOL_GPL(regmap_write_bits); - -/** - * regmap_update_bits_async: Perform a read/modify/write cycle on the register - * map asynchronously + * regmap_update_bits_base: + * Perform a read/modify/write cycle on the + * register map with change, async, force option * * @map: Register map to update * @reg: Register to update * @mask: Bitmask to change * @val: New value for bitmask + * @change: Boolean indicating if a write was done + * @async: Boolean indicating asynchronously + * @force: Boolean indicating use force update * + * if async was true, * With most buses the read must be done synchronously so this is most * useful for devices with a cache which do not need to interact with * the hardware to determine the current register value. * * Returns zero for success, a negative number on error. */ -int regmap_update_bits_async(struct regmap *map, unsigned int reg, - unsigned int mask, unsigned int val) +int regmap_update_bits_base(struct regmap *map, unsigned int reg, + unsigned int mask, unsigned int val, + bool *change, bool async, bool force) { int ret; map->lock(map->lock_arg); - map->async = true; + map->async = async; - ret = _regmap_update_bits(map, reg, mask, val, NULL, false); + ret = _regmap_update_bits(map, reg, mask, val, change, force); map->async = false; @@ -2623,69 +2653,30 @@ int regmap_update_bits_async(struct regmap *map, unsigned int reg, return ret; } -EXPORT_SYMBOL_GPL(regmap_update_bits_async); +EXPORT_SYMBOL_GPL(regmap_update_bits_base); /** - * regmap_update_bits_check: Perform a read/modify/write cycle on the - * register map and report if updated - * - * @map: Register map to update - * @reg: Register to update - * @mask: Bitmask to change - * @val: New value for bitmask - * @change: Boolean indicating if a write was done - * - * Returns zero for success, a negative number on error. - */ -int regmap_update_bits_check(struct regmap *map, unsigned int reg, - unsigned int mask, unsigned int val, - bool *change) -{ - int ret; - - map->lock(map->lock_arg); - ret = _regmap_update_bits(map, reg, mask, val, change, false); - map->unlock(map->lock_arg); - return ret; -} -EXPORT_SYMBOL_GPL(regmap_update_bits_check); - -/** - * regmap_update_bits_check_async: Perform a read/modify/write cycle on the - * register map asynchronously and report if - * updated + * regmap_write_bits: Perform a read/modify/write cycle on the register map * * @map: Register map to update * @reg: Register to update * @mask: Bitmask to change * @val: New value for bitmask - * @change: Boolean indicating if a write was done - * - * With most buses the read must be done synchronously so this is most - * useful for devices with a cache which do not need to interact with - * the hardware to determine the current register value. * * Returns zero for success, a negative number on error. */ -int regmap_update_bits_check_async(struct regmap *map, unsigned int reg, - unsigned int mask, unsigned int val, - bool *change) +int regmap_write_bits(struct regmap *map, unsigned int reg, + unsigned int mask, unsigned int val) { int ret; map->lock(map->lock_arg); - - map->async = true; - - ret = _regmap_update_bits(map, reg, mask, val, change, false); - - map->async = false; - + ret = _regmap_update_bits(map, reg, mask, val, NULL, true); map->unlock(map->lock_arg); return ret; } -EXPORT_SYMBOL_GPL(regmap_update_bits_check_async); +EXPORT_SYMBOL_GPL(regmap_write_bits); void regmap_async_complete_cb(struct regmap_async *async, int ret) { |