/* Base test of register maps */ static int dm_test_regmap_base(struct unit_test_state *uts) { struct udevice *dev; struct regmap *map; ofnode node; int i; ut_assertok(uclass_get_device(UCLASS_SYSCON, 0, &dev)); map = syscon_get_regmap(dev); ut_assertok_ptr(map); ut_asserteq(1, map->range_count); ut_asserteq(0x10, map->ranges[0].start); ut_asserteq(4, map->ranges[0].size); ut_asserteq(0x10, map_to_sysmem(regmap_get_range(map, 0))); ut_assertok(uclass_get_device(UCLASS_SYSCON, 1, &dev)); map = syscon_get_regmap(dev); ut_assertok_ptr(map); ut_asserteq(4, map->range_count); ut_asserteq(0x20, map->ranges[0].start); for (i = 0; i < 4; i++) { const unsigned long addr = 0x20 + 8 * i; ut_asserteq(addr, map->ranges[i].start); ut_asserteq(5 + i, map->ranges[i].size); ut_asserteq(addr, map_to_sysmem(regmap_get_range(map, i))); } /* Check that we can't pretend a different device is a syscon */ ut_assertok(uclass_get_device(UCLASS_I2C, 0, &dev)); map = syscon_get_regmap(dev); ut_asserteq_ptr(ERR_PTR(-ENOEXEC), map); /* A different device can be a syscon by using Linux-compat API */ node = ofnode_path("/syscon@2"); ut_assert(ofnode_valid(node)); map = syscon_node_to_regmap(node); ut_assertok_ptr(map); ut_asserteq(4, map->range_count); ut_asserteq(0x40, map->ranges[0].start); for (i = 0; i < 4; i++) { const unsigned long addr = 0x40 + 8 * i; ut_asserteq(addr, map->ranges[i].start); ut_asserteq(5 + i, map->ranges[i].size); ut_asserteq(addr, map_to_sysmem(regmap_get_range(map, i))); } return 0; }
int syscon_reboot_probe(struct udevice *dev) { struct udevice *syscon; struct syscon_reboot_priv *priv = dev_get_priv(dev); int err; err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, "regmap", &syscon); if (err) { error("unable to find syscon device\n"); return err; } priv->regmap = syscon_get_regmap(syscon); if (!priv->regmap) { error("unable to find regmap\n"); return -ENODEV; } priv->offset = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), "offset", 0); priv->mask = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), "mask", 0); return 0; }
struct regmap *syscon_regmap_lookup_by_phandle(struct udevice *dev, const char *name) { struct udevice *syscon; struct regmap *r; u32 phandle; ofnode node; int err; err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, name, &syscon); if (err) { /* found node with "syscon" compatible, not bounded to SYSCON */ err = ofnode_read_u32(dev_ofnode(dev), name, &phandle); if (err) return ERR_PTR(err); node = ofnode_get_by_phandle(phandle); if (!ofnode_valid(node)) { dev_dbg(dev, "unable to find syscon device\n"); return ERR_PTR(-EINVAL); } err = syscon_probe_by_ofnode(node, &syscon); if (err) return ERR_PTR(-ENODEV); } r = syscon_get_regmap(syscon); if (!r) { dev_dbg(dev, "unable to find regmap\n"); return ERR_PTR(-ENODEV); } return r; }
static int utmi_clk_ofdata_to_platdata(struct udevice *dev) { struct pmc_platdata *plat = dev_get_platdata(dev); struct udevice *syscon; uclass_get_device_by_phandle(UCLASS_SYSCON, dev, "regmap-sfr", &syscon); if (syscon) plat->regmap_sfr = syscon_get_regmap(syscon); return 0; }
/* Base test of register maps */ static int dm_test_regmap_base(struct unit_test_state *uts) { struct udevice *dev; struct regmap *map; int i; ut_assertok(uclass_get_device(UCLASS_SYSCON, 0, &dev)); map = syscon_get_regmap(dev); ut_assertok_ptr(map); ut_asserteq(1, map->range_count); ut_asserteq(0x10, map->base); ut_asserteq(0x10, map->range->start); ut_asserteq(4, map->range->size); ut_asserteq_ptr(&map->base_range, map->range); ut_asserteq(0x10, map_to_sysmem(regmap_get_range(map, 0))); ut_assertok(uclass_get_device(UCLASS_SYSCON, 1, &dev)); map = syscon_get_regmap(dev); ut_assertok_ptr(map); ut_asserteq(4, map->range_count); ut_asserteq(0x20, map->base); ut_assert(&map->base_range != map->range); for (i = 0; i < 4; i++) { const unsigned long addr = 0x20 + 8 * i; ut_asserteq(addr, map->range[i].start); ut_asserteq(5 + i, map->range[i].size); ut_asserteq(addr, map_to_sysmem(regmap_get_range(map, i))); } /* Check that we can't pretend a different device is a syscon */ ut_assertok(uclass_get_device(UCLASS_I2C, 0, &dev)); map = syscon_get_regmap(dev); ut_asserteq_ptr(ERR_PTR(-ENOEXEC), map); return 0; }
/* * Linux-compatible syscon-to-regmap * The syscon node can be bound to another driver, but still works * as a syscon provider. */ struct regmap *syscon_node_to_regmap(ofnode node) { struct udevice *dev; struct regmap *r; if (uclass_get_device_by_ofnode(UCLASS_SYSCON, node, &dev)) if (syscon_probe_by_ofnode(node, &dev)) return ERR_PTR(-ENODEV); r = syscon_get_regmap(dev); if (!r) { dev_dbg(dev, "unable to find regmap\n"); return ERR_PTR(-ENODEV); } return r; }
/* Read/Write/Modify test */ static int dm_test_regmap_rw(struct unit_test_state *uts) { struct udevice *dev; struct regmap *map; uint reg; ut_assertok(uclass_get_device(UCLASS_SYSCON, 0, &dev)); map = syscon_get_regmap(dev); ut_assertok_ptr(map); ut_assertok(regmap_write(map, 0, 0xcacafafa)); ut_assertok(regmap_write(map, 3, 0x55aa2211)); ut_assertok(regmap_read(map, 0, ®)); ut_assertok(regmap_read(map, 3, ®)); ut_assertok(regmap_update_bits(map, 0, 0xff00ff00, 0x55aa2211)); ut_assertok(regmap_update_bits(map, 3, 0x00ff00ff, 0xcacafada)); return 0; }
static void *map_syscon_chipselects(struct udevice *bus) { #if CONFIG_IS_ENABLED(SYSCON) struct udevice *syscon; struct regmap *regmap; const fdt32_t *cell; int len, err; err = uclass_get_device_by_phandle(UCLASS_SYSCON, bus, "syscon-chipselects", &syscon); if (err) { debug("%s: unable to find syscon device (%d)\n", __func__, err); return NULL; } regmap = syscon_get_regmap(syscon); if (IS_ERR(regmap)) { debug("%s: unable to find regmap (%ld)\n", __func__, PTR_ERR(regmap)); return NULL; } cell = fdt_getprop(gd->fdt_blob, dev_of_offset(bus), "syscon-chipselects", &len); if (len < 2*sizeof(fdt32_t)) { debug("%s: offset not available\n", __func__); return NULL; } return fdtdec_get_number(cell + 1, 1) + regmap_get_range(regmap, 0); #else fdt_addr_t addr; addr = devfdt_get_addr_index(bus, 2); return (addr == FDT_ADDR_T_NONE) ? NULL : map_physmem(addr, 0, MAP_NOCACHE); #endif }
static void *get_reg(struct udevice *dev, const char *name) { struct udevice *syscon; struct regmap *regmap; const fdt32_t *cell; int len, err; void *base; err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, name, &syscon); if (err) { pr_err("unable to find syscon device for %s (%d)\n", name, err); return NULL; } regmap = syscon_get_regmap(syscon); if (IS_ERR(regmap)) { pr_err("unable to find regmap for %s (%ld)\n", name, PTR_ERR(regmap)); return NULL; } cell = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), name, &len); if (len < 2*sizeof(fdt32_t)) { pr_err("offset not available for %s\n", name); return NULL; } base = regmap_get_range(regmap, 0); if (!base) return NULL; return fdtdec_get_number(cell + 1, 1) + base; }
int syscon_reboot_probe(struct udevice *dev) { struct udevice *syscon; struct syscon_reboot_priv *priv = dev_get_priv(dev); int err; err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, "regmap", &syscon); if (err) { pr_err("unable to find syscon device\n"); return err; } priv->regmap = syscon_get_regmap(syscon); if (!priv->regmap) { pr_err("unable to find regmap\n"); return -ENODEV; } priv->offset = dev_read_u32_default(dev, "offset", 0); priv->mask = dev_read_u32_default(dev, "mask", 0); return 0; }
static int sti_sysreset_probe(struct udevice *dev) { struct sti_sysreset_priv *priv = dev_get_priv(dev); struct udevice *syscon; struct regmap *regmap; struct fdtdec_phandle_args syscfg_phandle; int ret; /* get corresponding syscon phandle */ ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev_of_offset(dev), "st,syscfg", NULL, 0, 0, &syscfg_phandle); if (ret < 0) { pr_err("Can't get syscfg phandle: %d\n", ret); return ret; } ret = uclass_get_device_by_of_offset(UCLASS_SYSCON, syscfg_phandle.node, &syscon); if (ret) { pr_err("%s: uclass_get_device_by_of_offset failed: %d\n", __func__, ret); return ret; } regmap = syscon_get_regmap(syscon); if (!regmap) { pr_err("unable to get regmap for %s\n", syscon->name); return -ENODEV; } priv->base = regmap->base; return 0; }