regmap: clean up regmap allocation
[platform/kernel/u-boot.git] / drivers / core / regmap.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2015 Google, Inc
4  * Written by Simon Glass <sjg@chromium.org>
5  */
6
7 #include <common.h>
8 #include <dm.h>
9 #include <errno.h>
10 #include <linux/libfdt.h>
11 #include <malloc.h>
12 #include <mapmem.h>
13 #include <regmap.h>
14 #include <asm/io.h>
15 #include <dm/of_addr.h>
16 #include <linux/ioport.h>
17
18 DECLARE_GLOBAL_DATA_PTR;
19
20 static struct regmap *regmap_alloc(int count)
21 {
22         struct regmap *map;
23
24         map = malloc(sizeof(*map) + sizeof(map->ranges[0]) * count);
25         if (!map)
26                 return NULL;
27         map->range_count = count;
28
29         return map;
30 }
31
32 #if CONFIG_IS_ENABLED(OF_PLATDATA)
33 int regmap_init_mem_platdata(struct udevice *dev, fdt_val_t *reg, int count,
34                              struct regmap **mapp)
35 {
36         struct regmap_range *range;
37         struct regmap *map;
38
39         map = regmap_alloc(count);
40         if (!map)
41                 return -ENOMEM;
42
43         for (range = map->ranges; count > 0; reg += 2, range++, count--) {
44                 range->start = *reg;
45                 range->size = reg[1];
46         }
47
48         *mapp = map;
49
50         return 0;
51 }
52 #else
53 int regmap_init_mem(struct udevice *dev, struct regmap **mapp)
54 {
55         struct regmap_range *range;
56         struct regmap *map;
57         int count;
58         int addr_len, size_len, both_len;
59         int len;
60         int index;
61         ofnode node = dev_ofnode(dev);
62         struct resource r;
63
64         addr_len = dev_read_simple_addr_cells(dev->parent);
65         size_len = dev_read_simple_size_cells(dev->parent);
66         both_len = addr_len + size_len;
67
68         len = dev_read_size(dev, "reg");
69         if (len < 0)
70                 return len;
71         len /= sizeof(fdt32_t);
72         count = len / both_len;
73         if (!count)
74                 return -EINVAL;
75
76         map = regmap_alloc(count);
77         if (!map)
78                 return -ENOMEM;
79
80         for (range = map->ranges, index = 0; count > 0;
81              count--, range++, index++) {
82                 fdt_size_t sz;
83                 if (of_live_active()) {
84                         of_address_to_resource(ofnode_to_np(node), index, &r);
85                         range->start = r.start;
86                         range->size = r.end - r.start + 1;
87                 } else {
88                         range->start = fdtdec_get_addr_size_fixed(gd->fdt_blob,
89                                         dev_of_offset(dev), "reg", index,
90                                         addr_len, size_len, &sz, true);
91                         range->size = sz;
92                 }
93         }
94
95         *mapp = map;
96
97         return 0;
98 }
99 #endif
100
101 void *regmap_get_range(struct regmap *map, unsigned int range_num)
102 {
103         struct regmap_range *range;
104
105         if (range_num >= map->range_count)
106                 return NULL;
107         range = &map->ranges[range_num];
108
109         return map_sysmem(range->start, range->size);
110 }
111
112 int regmap_uninit(struct regmap *map)
113 {
114         free(map);
115
116         return 0;
117 }
118
119 int regmap_read(struct regmap *map, uint offset, uint *valp)
120 {
121         u32 *ptr = map_physmem(map->ranges[0].start + offset, 4, MAP_NOCACHE);
122
123         *valp = le32_to_cpu(readl(ptr));
124
125         return 0;
126 }
127
128 int regmap_write(struct regmap *map, uint offset, uint val)
129 {
130         u32 *ptr = map_physmem(map->ranges[0].start + offset, 4, MAP_NOCACHE);
131
132         writel(cpu_to_le32(val), ptr);
133
134         return 0;
135 }