// SPDX-License-Identifier: GPL-2.0//// Register map access API//// Copyright 2011 Wolfson Microelectronics plc//// Author: Mark Brown <broonie@opensource.wolfsonmicro.com> #include <linux/device.h>#include <linux/slab.h>#include <linux/export.h>#include <linux/mutex.h>#include <linux/err.h>#include <linux/of.h>#include <linux/rbtree.h>#include <linux/sched.h>#include <linux/delay.h>#include <linux/log2.h>#include <linux/hwspinlock.h> #define CREATE_TRACE_POINTS#include "trace.h" #include "internal.h" /* * Sometimes for failures during very early init the trace * infrastructure isn't available early enough to be used. For this * sort of problem defining LOG_DEVICE will add printks for basic * register I/O on a specific device. */#undef LOG_DEVICE #ifdef LOG_DEVICEstatic inline bool regmap_should_log(struct regmap *map){ return (map->dev && strcmp(dev_name(map->dev), LOG_DEVICE) == 0);}#elsestatic inline bool regmap_should_log(struct regmap *map) { return false; }#endif static int _regmap_update_bits(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val, bool *change, bool force_write); static int _regmap_bus_reg_read(void *context, unsigned int reg, unsigned int *val);static int _regmap_bus_read(void *context, unsigned int reg, unsigned int *val);static int _regmap_bus_formatted_write(void *context, unsigned int reg, unsigned int val);static int _regmap_bus_reg_write(void *context, unsigned int reg, unsigned int val);static int _regmap_bus_raw_write(void *context, unsigned int reg, unsigned int val); bool regmap_reg_in_ranges(unsigned int reg, const struct regmap_range *ranges, unsigned int nranges){ const struct regmap_range *r; int i; for (i = 0, r = ranges; i < nranges; i++, r++) if (regmap_reg_in_range(reg, r)) return true; return false;}EXPORT_SYMBOL_GPL(regmap_reg_in_ranges); bool regmap_check_range_table(struct regmap *map, unsigned int reg, const struct regmap_access_table *table){ /* Check "no ranges" first */ if (regmap_reg_in_ranges(reg, table->no_ranges, table->n_no_ranges)) return false; /* In case zero "yes ranges" are supplied, any reg is OK */ if (!table->n_yes_ranges) return true; return regmap_reg_in_ranges(reg, table->yes_ranges, table->n_yes_ranges);}EXPORT_SYMBOL_GPL(regmap_check_range_table); bool regmap_writeable(struct regmap *map, unsigned int reg){ if (map->max_register && reg > map->max_register) return false; if (map->writeable_reg) return map->writeable_reg(map->dev, reg); if (map->wr_table) return regmap_check_range_table(map, reg, map->wr_table); return true;} bool regmap_cached(struct regmap *map, unsigned int reg){ int ret; unsigned int val; if (map->cache_type == REGCACHE_NONE) return false; if (!map->cache_ops) return false; if (map->max_register && reg > map->max_register) return false; map->lock(map->lock_arg); ret = regcache_read(map, reg, &val); map->unlock(map->lock_arg); if (ret) return false; return true;} bool regmap_readable(struct regmap *map, unsigned int reg){ if (!map->reg_read) return false; if (map->max_register && reg > map->max_register) return false; if (map->format.format_write) return false; if (map->readable_reg) return map->readable_reg(map->dev, reg); if (map->rd_table) return regmap_check_range_table(map, reg, map->rd_table); return true;} bool regmap_volatile(struct regmap *map, unsigned int reg){ if (!map->format.format_write && !regmap_readable(map, reg)) return false; if (map->volatile_reg) return map->volatile_reg(map->dev, reg); if (map->volatile_table) return regmap_check_range_table(map, reg, map->volatile_table); if (map->cache_ops) return false; else return true;} bool regmap_precious(struct regmap *map, unsigned int reg){ if (!regmap_readable(map, reg)) return false; if (map->precious_reg) return map->precious_reg(map->dev, reg); if (map->precious_table) return regmap_check_range_table(map, reg, map->precious_table); return false;} bool regmap_writeable_noinc(struct regmap *map, unsigned int reg){ if (map->writeable_noinc_reg) return map->writeable_noinc_reg(map->dev, reg); if (map->wr_noinc_table) return regmap_check_range_table(map, reg, map->wr_noinc_table); return true;} bool regmap_readable_noinc(struct regmap *map, unsigned int reg){ if (map->readable_noinc_reg) return map->readable_noinc_reg(map->dev, reg); if (map->rd_noinc_table) return regmap_check_range_table(map, reg, map->rd_noinc_table); return true;} static bool regmap_volatile_range(struct regmap *map, unsigned int reg, size_t num){ unsigned int i; for (i = 0; i < num; i++) if (!regmap_volatile(map, reg + regmap_get_offset(map, i))) return false; return true;} static void regmap_format_2_6_write(struct regmap *map, unsigned int reg, unsigned int val){ u8 *out = map->work_buf; *out = (reg << 6) | val;} static void regmap_format_4_12_write(struct regmap *map, unsigned int reg, unsigned int val){ __be16 *out = map->work_buf; *out = cpu_to_be16((reg << 12) | val);} static void regmap_format_7_9_write(struct regmap *map, unsigned int reg, unsigned int val){ __be16 *out = map->work_buf; *out = cpu_to_be16((reg << 9) | val);} static void regmap_format_10_14_write(struct regmap *map, unsigned int reg, unsigned int val){ u8 *out = map->work_buf; out[2] = val; out[1] = (val >> 8) | (reg << 6); out[0] = reg >> 2;} static void regmap_format_8(void *buf, unsigned int val, unsigned int shift){ u8 *b = buf; b[0] = val << shift;} static void regmap_format_16_be(void *buf, unsigned int val, unsigned int shift){ __be16 *b = buf; b[0] = cpu_to_be16(val << shift);} static void regmap_format_16_le(void *buf, unsigned int val, unsigned int shift){ __le16 *b = buf; b[0] = cpu_to_le16(val << shift);} static void regmap_format_16_native(void *buf, unsigned int val, unsigned int shift){ *(u16 *)buf = val << shift;} static void regmap_format_24(void *buf, unsigned int val, unsigned int shift){ u8 *b = buf; val <<= shift; b[0] = val >> 16; b[1] = val >> 8; b[2] = val;} static void regmap_format_32_be(void *buf, unsigned int val, unsigned int shift){ __be32 *b = buf; b[0] = cpu_to_be32(val << shift);} static void regmap_format_32_le(void *buf, unsigned int val, unsigned int shift){ __le32 *b = buf; b[0] = cpu_to_le32(val << shift);} static void regmap_format_32_native(void *buf, unsigned int val, unsigned int shift){ *(u32 *)buf = val << shift;} #ifdef CONFIG_64BITstatic 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){} static unsigned int regmap_parse_8(const void *buf){ const u8 *b = buf; return b[0];} static unsigned int regmap_parse_16_be(const void *buf){ const __be16 *b = buf; return be16_to_cpu(b[0]);} static unsigned int regmap_parse_16_le(const void *buf){ const __le16 *b = buf; return le16_to_cpu(b[0]);} static void regmap_parse_16_be_inplace(void *buf){ __be16 *b = buf; b[0] = be16_to_cpu(b[0]);} static void regmap_parse_16_le_inplace(void *buf){ __le16 *b = buf; b[0] = le16_to_cpu(b[0]);} static unsigned int regmap_parse_16_native(const void *buf){ return *(u16 *)buf;} static unsigned int regmap_parse_24(const void *buf){ const u8 *b = buf; unsigned int ret = b[2]; ret |= ((unsigned int)b[1]) << 8; ret |= ((unsigned int)b[0]) << 16; return ret;} static unsigned int regmap_parse_32_be(const void *buf){ const __be32 *b = buf; return be32_to_cpu(b[0]);} static unsigned int regmap_parse_32_le(const void *buf){ const __le32 *b = buf; return le32_to_cpu(b[0]);} static void regmap_parse_32_be_inplace(void *buf){ __be32 *b = buf; b[0] = be32_to_cpu(b[0]);} static void regmap_parse_32_le_inplace(void *buf){ __le32 *b = buf; b[0] = le32_to_cpu(b[0]);} static unsigned int regmap_parse_32_native(const void *buf){ return *(u32 *)buf;} #ifdef CONFIG_64BITstatic 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_hwlock(void *__map){ struct regmap *map = __map; hwspin_lock_timeout(map->hwlock, UINT_MAX);} static void regmap_lock_hwlock_irq(void *__map){ struct regmap *map = __map; hwspin_lock_timeout_irq(map->hwlock, UINT_MAX);} static void regmap_lock_hwlock_irqsave(void *__map){ struct regmap *map = __map; hwspin_lock_timeout_irqsave(map->hwlock, UINT_MAX, &map->spinlock_flags);} static void regmap_unlock_hwlock(void *__map){ struct regmap *map = __map; hwspin_unlock(map->hwlock);} static void regmap_unlock_hwlock_irq(void *__map){ struct regmap *map = __map; hwspin_unlock_irq(map->hwlock);} static void regmap_unlock_hwlock_irqrestore(void *__map){ struct regmap *map = __map; hwspin_unlock_irqrestore(map->hwlock, &map->spinlock_flags);} static void regmap_lock_unlock_none(void *__map){ } static void regmap_lock_mutex(void *__map){ struct regmap *map = __map; mutex_lock(&map->mutex);} static void regmap_unlock_mutex(void *__map){Lines 1–500 of 3117. Load more
// SPDX-License-Identifier: GPL-2.0 // // Register map access API // // Copyright 2011 Wolfson Microelectronics plc // // Author: Mark Brown <broonie@opensource.wolfsonmicro.com> #include <linux/device.h> #include <linux/slab.h> #include <linux/export.h> #include <linux/mutex.h> #include <linux/err.h> #include <linux/of.h> #include <linux/rbtree.h> #include <linux/sched.h> #include <linux/delay.h> #include <linux/log2.h> #include <linux/hwspinlock.h> #define CREATE_TRACE_POINTS #include "trace.h" #include "internal.h" /* * Sometimes for failures during very early init the trace * infrastructure isn't available early enough to be used. For this * sort of problem defining LOG_DEVICE will add printks for basic * register I/O on a specific device. */ #undef LOG_DEVICE #ifdef LOG_DEVICE static inline bool regmap_should_log(struct regmap *map) { return (map->dev && strcmp(dev_name(map->dev), LOG_DEVICE) == 0); } #else static inline bool regmap_should_log(struct regmap *map) { return false; } #endif static int _regmap_update_bits(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val, bool *change, bool force_write); static int _regmap_bus_reg_read(void *context, unsigned int reg, unsigned int *val); static int _regmap_bus_read(void *context, unsigned int reg, unsigned int *val); static int _regmap_bus_formatted_write(void *context, unsigned int reg, unsigned int val); static int _regmap_bus_reg_write(void *context, unsigned int reg, unsigned int val); static int _regmap_bus_raw_write(void *context, unsigned int reg, unsigned int val); bool regmap_reg_in_ranges(unsigned int reg, const struct regmap_range *ranges, unsigned int nranges) { const struct regmap_range *r; int i; for (i = 0, r = ranges; i < nranges; i++, r++) if (regmap_reg_in_range(reg, r)) return true; return false; } EXPORT_SYMBOL_GPL(regmap_reg_in_ranges); bool regmap_check_range_table(struct regmap *map, unsigned int reg, const struct regmap_access_table *table) { /* Check "no ranges" first */ if (regmap_reg_in_ranges(reg, table->no_ranges, table->n_no_ranges)) return false; /* In case zero "yes ranges" are supplied, any reg is OK */ if (!table->n_yes_ranges) return true; return regmap_reg_in_ranges(reg, table->yes_ranges, table->n_yes_ranges); } EXPORT_SYMBOL_GPL(regmap_check_range_table); bool regmap_writeable(struct regmap *map, unsigned int reg) { if (map->max_register && reg > map->max_register) return false; if (map->writeable_reg) return map->writeable_reg(map->dev, reg); if (map->wr_table) return regmap_check_range_table(map, reg, map->wr_table); return true; } bool regmap_cached(struct regmap *map, unsigned int reg) { int ret; unsigned int val; if (map->cache_type == REGCACHE_NONE) return false; if (!map->cache_ops) return false; if (map->max_register && reg > map->max_register) return false; map->lock(map->lock_arg); ret = regcache_read(map, reg, &val); map->unlock(map->lock_arg); if (ret) return false; return true; } bool regmap_readable(struct regmap *map, unsigned int reg) { if (!map->reg_read) return false; if (map->max_register && reg > map->max_register) return false; if (map->format.format_write) return false; if (map->readable_reg) return map->readable_reg(map->dev, reg); if (map->rd_table) return regmap_check_range_table(map, reg, map->rd_table); return true; } bool regmap_volatile(struct regmap *map, unsigned int reg) { if (!map->format.format_write && !regmap_readable(map, reg)) return false; if (map->volatile_reg) return map->volatile_reg(map->dev, reg); if (map->volatile_table) return regmap_check_range_table(map, reg, map->volatile_table); if (map->cache_ops) return false; else return true; } bool regmap_precious(struct regmap *map, unsigned int reg) { if (!regmap_readable(map, reg)) return false; if (map->precious_reg) return map->precious_reg(map->dev, reg); if (map->precious_table) return regmap_check_range_table(map, reg, map->precious_table); return false; } bool regmap_writeable_noinc(struct regmap *map, unsigned int reg) { if (map->writeable_noinc_reg) return map->writeable_noinc_reg(map->dev, reg); if (map->wr_noinc_table) return regmap_check_range_table(map, reg, map->wr_noinc_table); return true; } bool regmap_readable_noinc(struct regmap *map, unsigned int reg) { if (map->readable_noinc_reg) return map->readable_noinc_reg(map->dev, reg); if (map->rd_noinc_table) return regmap_check_range_table(map, reg, map->rd_noinc_table); return true; } static bool regmap_volatile_range(struct regmap *map, unsigned int reg, size_t num) { unsigned int i; for (i = 0; i < num; i++) if (!regmap_volatile(map, reg + regmap_get_offset(map, i))) return false; return true; } static void regmap_format_2_6_write(struct regmap *map, unsigned int reg, unsigned int val) { u8 *out = map->work_buf; *out = (reg << 6) | val; } static void regmap_format_4_12_write(struct regmap *map, unsigned int reg, unsigned int val) { __be16 *out = map->work_buf; *out = cpu_to_be16((reg << 12) | val); } static void regmap_format_7_9_write(struct regmap *map, unsigned int reg, unsigned int val) { __be16 *out = map->work_buf; *out = cpu_to_be16((reg << 9) | val); } static void regmap_format_10_14_write(struct regmap *map, unsigned int reg, unsigned int val) { u8 *out = map->work_buf; out[2] = val; out[1] = (val >> 8) | (reg << 6); out[0] = reg >> 2; } static void regmap_format_8(void *buf, unsigned int val, unsigned int shift) { u8 *b = buf; b[0] = val << shift; } static void regmap_format_16_be(void *buf, unsigned int val, unsigned int shift) { __be16 *b = buf; b[0] = cpu_to_be16(val << shift); } static void regmap_format_16_le(void *buf, unsigned int val, unsigned int shift) { __le16 *b = buf; b[0] = cpu_to_le16(val << shift); } static void regmap_format_16_native(void *buf, unsigned int val, unsigned int shift) { *(u16 *)buf = val << shift; } static void regmap_format_24(void *buf, unsigned int val, unsigned int shift) { u8 *b = buf; val <<= shift; b[0] = val >> 16; b[1] = val >> 8; b[2] = val; } static void regmap_format_32_be(void *buf, unsigned int val, unsigned int shift) { __be32 *b = buf; b[0] = cpu_to_be32(val << shift); } static void regmap_format_32_le(void *buf, unsigned int val, unsigned int shift) { __le32 *b = buf; b[0] = cpu_to_le32(val << shift); } static void regmap_format_32_native(void *buf, unsigned int val, unsigned int shift) { *(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) { } static unsigned int regmap_parse_8(const void *buf) { const u8 *b = buf; return b[0]; } static unsigned int regmap_parse_16_be(const void *buf) { const __be16 *b = buf; return be16_to_cpu(b[0]); } static unsigned int regmap_parse_16_le(const void *buf) { const __le16 *b = buf; return le16_to_cpu(b[0]); } static void regmap_parse_16_be_inplace(void *buf) { __be16 *b = buf; b[0] = be16_to_cpu(b[0]); } static void regmap_parse_16_le_inplace(void *buf) { __le16 *b = buf; b[0] = le16_to_cpu(b[0]); } static unsigned int regmap_parse_16_native(const void *buf) { return *(u16 *)buf; } static unsigned int regmap_parse_24(const void *buf) { const u8 *b = buf; unsigned int ret = b[2]; ret |= ((unsigned int)b[1]) << 8; ret |= ((unsigned int)b[0]) << 16; return ret; } static unsigned int regmap_parse_32_be(const void *buf) { const __be32 *b = buf; return be32_to_cpu(b[0]); } static unsigned int regmap_parse_32_le(const void *buf) { const __le32 *b = buf; return le32_to_cpu(b[0]); } static void regmap_parse_32_be_inplace(void *buf) { __be32 *b = buf; b[0] = be32_to_cpu(b[0]); } static void regmap_parse_32_le_inplace(void *buf) { __le32 *b = buf; b[0] = le32_to_cpu(b[0]); } 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_hwlock(void *__map) { struct regmap *map = __map; hwspin_lock_timeout(map->hwlock, UINT_MAX); } static void regmap_lock_hwlock_irq(void *__map) { struct regmap *map = __map; hwspin_lock_timeout_irq(map->hwlock, UINT_MAX); } static void regmap_lock_hwlock_irqsave(void *__map) { struct regmap *map = __map; hwspin_lock_timeout_irqsave(map->hwlock, UINT_MAX, &map->spinlock_flags); } static void regmap_unlock_hwlock(void *__map) { struct regmap *map = __map; hwspin_unlock(map->hwlock); } static void regmap_unlock_hwlock_irq(void *__map) { struct regmap *map = __map; hwspin_unlock_irq(map->hwlock); } static void regmap_unlock_hwlock_irqrestore(void *__map) { struct regmap *map = __map; hwspin_unlock_irqrestore(map->hwlock, &map->spinlock_flags); } static void regmap_lock_unlock_none(void *__map) { } static void regmap_lock_mutex(void *__map) { struct regmap *map = __map; mutex_lock(&map->mutex); } static void regmap_unlock_mutex(void *__map) {