| /* | |
| * SPDX-License-Identifier: BSD-2-Clause | |
| * | |
| * Copyright (c) 2023 Ventana Micro Systems Inc. | |
| * | |
| * Authors: | |
| * Anup Patel <apatel@ventanamicro.com> | |
| */ | |
| #include <sbi/sbi_error.h> | |
| #include <sbi_utils/regmap/regmap.h> | |
| static SBI_LIST_HEAD(regmap_list); | |
| struct regmap *regmap_find(unsigned int id) | |
| { | |
| struct sbi_dlist *pos; | |
| sbi_list_for_each(pos, &(regmap_list)) { | |
| struct regmap *rmap = to_regmap(pos); | |
| if (rmap->id == id) | |
| return rmap; | |
| } | |
| return NULL; | |
| } | |
| int regmap_add(struct regmap *rmap) | |
| { | |
| if (!rmap) | |
| return SBI_EINVAL; | |
| if (regmap_find(rmap->id)) | |
| return SBI_EALREADY; | |
| sbi_list_add(&(rmap->node), &(regmap_list)); | |
| return 0; | |
| } | |
| void regmap_remove(struct regmap *rmap) | |
| { | |
| if (!rmap) | |
| return; | |
| sbi_list_del(&(rmap->node)); | |
| } | |
| static bool regmap_reg_valid(struct regmap *rmap, unsigned int reg) | |
| { | |
| if ((reg >= rmap->reg_max) || | |
| (reg & (rmap->reg_stride - 1))) | |
| return false; | |
| return true; | |
| } | |
| static unsigned int regmap_reg_addr(struct regmap *rmap, unsigned int reg) | |
| { | |
| reg += rmap->reg_base; | |
| if (rmap->reg_shift > 0) | |
| reg >>= rmap->reg_shift; | |
| else if (rmap->reg_shift < 0) | |
| reg <<= -(rmap->reg_shift); | |
| return reg; | |
| } | |
| int regmap_read(struct regmap *rmap, unsigned int reg, unsigned int *val) | |
| { | |
| if (!rmap || !regmap_reg_valid(rmap, reg)) | |
| return SBI_EINVAL; | |
| if (!rmap->reg_read) | |
| return SBI_ENOSYS; | |
| return rmap->reg_read(rmap, regmap_reg_addr(rmap, reg), val); | |
| } | |
| int regmap_write(struct regmap *rmap, unsigned int reg, unsigned int val) | |
| { | |
| if (!rmap || !regmap_reg_valid(rmap, reg)) | |
| return SBI_EINVAL; | |
| if (!rmap->reg_write) | |
| return SBI_ENOSYS; | |
| return rmap->reg_write(rmap, regmap_reg_addr(rmap, reg), val); | |
| } | |
| int regmap_update_bits(struct regmap *rmap, unsigned int reg, | |
| unsigned int mask, unsigned int val) | |
| { | |
| int rc; | |
| unsigned int reg_val; | |
| if (!rmap || !regmap_reg_valid(rmap, reg)) | |
| return SBI_EINVAL; | |
| if (rmap->reg_update_bits) { | |
| return rmap->reg_update_bits(rmap, regmap_reg_addr(rmap, reg), | |
| mask, val); | |
| } else if (rmap->reg_read && rmap->reg_write) { | |
| reg = regmap_reg_addr(rmap, reg); | |
| rc = rmap->reg_read(rmap, reg, ®_val); | |
| if (rc) | |
| return rc; | |
| reg_val &= ~mask; | |
| reg_val |= val & mask; | |
| return rmap->reg_write(rmap, reg, reg_val); | |
| } | |
| return SBI_ENOSYS; | |
| } |