diff --git a/drivers/core/Makefile b/drivers/core/Makefile
index ed21fedbc08fed64d78462c47d395393083061a2..785182414341753eda24679c60158b9159509472 100644
--- a/drivers/core/Makefile
+++ b/drivers/core/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_OF_CONTROL) += simple-bus.o
 endif
 obj-$(CONFIG_DM_DEVICE_REMOVE)	+= device-remove.o
 obj-$(CONFIG_DM)	+= dump.o
+obj-$(CONFIG_OF_CONTROL)	+= regmap.o
diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c
new file mode 100644
index 0000000000000000000000000000000000000000..519832f173307e95a9862e33679c9f0707218696
--- /dev/null
+++ b/drivers/core/regmap.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <libfdt.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <regmap.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int regmap_init_mem(struct udevice *dev, struct regmap **mapp)
+{
+	const void *blob = gd->fdt_blob;
+	struct regmap_range *range;
+	const fdt32_t *cell;
+	struct regmap *map;
+	int count;
+	int addr_len, size_len, both_len;
+	int parent;
+	int len;
+
+	parent = dev->parent->of_offset;
+	addr_len = fdt_address_cells(blob, parent);
+	size_len = fdt_size_cells(blob, parent);
+	both_len = addr_len + size_len;
+
+	cell = fdt_getprop(blob, dev->of_offset, "reg", &len);
+	len /= sizeof(*cell);
+	count = len / both_len;
+	if (!cell || !count)
+		return -EINVAL;
+
+	map = malloc(sizeof(struct regmap));
+	if (!map)
+		return -ENOMEM;
+
+	if (count <= 1) {
+		map->range = &map->base_range;
+	} else {
+		map->range = malloc(count * sizeof(struct regmap_range));
+		if (!map->range) {
+			free(map);
+			return -ENOMEM;
+		}
+	}
+
+	map->base = fdtdec_get_number(cell, addr_len);
+	map->range_count = count;
+
+	for (range = map->range; count > 0;
+	     count--, cell += both_len, range++) {
+		range->start = fdtdec_get_number(cell, addr_len);
+		range->size = fdtdec_get_number(cell + addr_len, size_len);
+	}
+
+	*mapp = map;
+
+	return 0;
+}
+
+void *regmap_get_range(struct regmap *map, unsigned int range_num)
+{
+	struct regmap_range *range;
+
+	if (range_num >= map->range_count)
+		return NULL;
+	range = &map->range[range_num];
+
+	return map_sysmem(range->start, range->size);
+}
+
+int regmap_uninit(struct regmap *map)
+{
+	if (map->range_count > 1)
+		free(map->range);
+	free(map);
+
+	return 0;
+}
diff --git a/include/regmap.h b/include/regmap.h
new file mode 100644
index 0000000000000000000000000000000000000000..eccf7707f456568de6cd371d6d971e71bd403ee6
--- /dev/null
+++ b/include/regmap.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __REGMAP_H
+#define __REGMAP_H
+
+/**
+ * struct regmap_range - a register map range
+ *
+ * @start:	Start address
+ * @size:	Size in bytes
+ */
+struct regmap_range {
+	ulong start;
+	ulong size;
+};
+
+/**
+ * struct regmap - a way of accessing hardware/bus registers
+ *
+ * @base:	Base address of register map
+ * @range_count: Number of ranges available within the map
+ * @range:	Pointer to the list of ranges, allocated if @range_count > 1
+ * @base_range:	If @range_count is <= 1, @range points here
+ */
+struct regmap {
+	phys_addr_t base;
+	int range_count;
+	struct regmap_range *range, base_range;
+};
+
+/*
+ * Interface to provide access to registers either through a direct memory
+ * bus or through a peripheral bus like I2C, SPI.
+ */
+int regmap_write(struct regmap *map, uint offset, uint val);
+int regmap_read(struct regmap *map, uint offset, uint *valp);
+
+#define regmap_write32(map, ptr, member, val) \
+	regmap_write(map, (uint32_t *)(ptr)->member - (uint32_t *)(ptr), val)
+
+#define regmap_read32(map, ptr, member, valp) \
+	regmap_read(map, (uint32_t *)(ptr)->member - (uint32_t *)(ptr), valp)
+
+/**
+ * regmap_init_mem() - Set up a new register map that uses memory access
+ *
+ * Use regmap_uninit() to free it.
+ *
+ * @dev:	Device that uses this map
+ * @mapp:	Returns allocated map
+ */
+int regmap_init_mem(struct udevice *dev, struct regmap **mapp);
+
+/**
+ * regmap_get_range() - Obtain the base memory address of a regmap range
+ *
+ * @map:	Regmap to query
+ * @range_num:	Range to look up
+ */
+void *regmap_get_range(struct regmap *map, unsigned int range_num);
+
+/**
+ * regmap_uninit() - free a previously inited regmap
+ */
+int regmap_uninit(struct regmap *map);
+
+#endif