regmap: Add documentation
[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 /**
21  * regmap_alloc() - Allocate a regmap with a given number of ranges.
22  *
23  * @count: Number of ranges to be allocated for the regmap.
24  * Return: A pointer to the newly allocated regmap, or NULL on error.
25  */
26 static struct regmap *regmap_alloc(int count)
27 {
28         struct regmap *map;
29
30         map = malloc(sizeof(*map) + sizeof(map->ranges[0]) * count);
31         if (!map)
32                 return NULL;
33         map->range_count = count;
34
35         return map;
36 }
37
38 #if CONFIG_IS_ENABLED(OF_PLATDATA)
39 int regmap_init_mem_platdata(struct udevice *dev, fdt_val_t *reg, int count,
40                              struct regmap **mapp)
41 {
42         struct regmap_range *range;
43         struct regmap *map;
44
45         map = regmap_alloc(count);
46         if (!map)
47                 return -ENOMEM;
48
49         for (range = map->ranges; count > 0; reg += 2, range++, count--) {
50                 range->start = *reg;
51                 range->size = reg[1];
52         }
53
54         *mapp = map;
55
56         return 0;
57 }
58 #else
59 int regmap_init_mem(ofnode node, struct regmap **mapp)
60 {
61         struct regmap_range *range;
62         struct regmap *map;
63         int count;
64         int addr_len, size_len, both_len;
65         int len;
66         int index;
67         struct resource r;
68
69         addr_len = ofnode_read_simple_addr_cells(ofnode_get_parent(node));
70         size_len = ofnode_read_simple_size_cells(ofnode_get_parent(node));
71         both_len = addr_len + size_len;
72
73         len = ofnode_read_size(node, "reg");
74         if (len < 0)
75                 return len;
76         len /= sizeof(fdt32_t);
77         count = len / both_len;
78         if (!count)
79                 return -EINVAL;
80
81         map = regmap_alloc(count);
82         if (!map)
83                 return -ENOMEM;
84
85         for (range = map->ranges, index = 0; count > 0;
86              count--, range++, index++) {
87                 fdt_size_t sz;
88                 if (of_live_active()) {
89                         of_address_to_resource(ofnode_to_np(node), index, &r);
90                         range->start = r.start;
91                         range->size = r.end - r.start + 1;
92                 } else {
93                         range->start = fdtdec_get_addr_size_fixed(gd->fdt_blob,
94                                         ofnode_to_offset(node), "reg", index,
95                                         addr_len, size_len, &sz, true);
96                         range->size = sz;
97                 }
98         }
99
100         *mapp = map;
101
102         return 0;
103 }
104 #endif
105
106 void *regmap_get_range(struct regmap *map, unsigned int range_num)
107 {
108         struct regmap_range *range;
109
110         if (range_num >= map->range_count)
111                 return NULL;
112         range = &map->ranges[range_num];
113
114         return map_sysmem(range->start, range->size);
115 }
116
117 int regmap_uninit(struct regmap *map)
118 {
119         free(map);
120
121         return 0;
122 }
123
124 int regmap_read(struct regmap *map, uint offset, uint *valp)
125 {
126         u32 *ptr = map_physmem(map->ranges[0].start + offset, 4, MAP_NOCACHE);
127
128         *valp = le32_to_cpu(readl(ptr));
129
130         return 0;
131 }
132
133 int regmap_write(struct regmap *map, uint offset, uint val)
134 {
135         u32 *ptr = map_physmem(map->ranges[0].start + offset, 4, MAP_NOCACHE);
136
137         writel(cpu_to_le32(val), ptr);
138
139         return 0;
140 }
141
142 int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val)
143 {
144         uint reg;
145         int ret;
146
147         ret = regmap_read(map, offset, &reg);
148         if (ret)
149                 return ret;
150
151         reg &= ~mask;
152
153         return regmap_write(map, offset, reg | val);
154 }