diff options
author | Simon Glass <sjg@chromium.org> | 2015-06-23 15:38:42 -0600 |
---|---|---|
committer | Simon Glass <sjg@chromium.org> | 2015-07-21 17:39:23 -0600 |
commit | 6f98b7504f7097ea36df451c58d718f3ad2aa4ea (patch) | |
tree | 6cc45f592bf1fb09a25d4d40b17d647c69b2741e /drivers | |
parent | efa677fb481aec0888d3d37803643219d4ea57d1 (diff) | |
download | u-boot-imx-6f98b7504f7097ea36df451c58d718f3ad2aa4ea.zip u-boot-imx-6f98b7504f7097ea36df451c58d718f3ad2aa4ea.tar.gz u-boot-imx-6f98b7504f7097ea36df451c58d718f3ad2aa4ea.tar.bz2 |
dm: Add support for register maps (regmap)
Add a simple implementaton of register maps, supporting only direct I/O
for now. This can be enhanced later to support buses which have registers,
such as I2C, SPI and PCI.
It allows drivers which can operate with multiple buses to avoid dealing
with the particulars of register access on that bus.
Signed-off-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/core/Makefile | 1 | ||||
-rw-r--r-- | drivers/core/regmap.c | 86 |
2 files changed, 87 insertions, 0 deletions
diff --git a/drivers/core/Makefile b/drivers/core/Makefile index ed21fed..7851824 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 0000000..519832f --- /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; +} |