hwmon: (applesmc) Ignore some temperature registers
[pandora-kernel.git] / drivers / base / regmap / regmap-mmio.c
1 /*
2  * Register map access API - MMIO support
3  *
4  * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include <linux/err.h>
20 #include <linux/init.h>
21 #include <linux/io.h>
22 #include <linux/module.h>
23 #include <linux/regmap.h>
24 #include <linux/slab.h>
25
26 struct regmap_mmio_context {
27         void __iomem *regs;
28         unsigned val_bytes;
29 };
30
31 static int regmap_mmio_gather_write(void *context,
32                                     const void *reg, size_t reg_size,
33                                     const void *val, size_t val_size)
34 {
35         struct regmap_mmio_context *ctx = context;
36         u32 offset;
37
38         BUG_ON(reg_size != 4);
39
40         offset = be32_to_cpup(reg);
41
42         while (val_size) {
43                 switch (ctx->val_bytes) {
44                 case 1:
45                         writeb(*(u8 *)val, ctx->regs + offset);
46                         break;
47                 case 2:
48                         writew(be16_to_cpup(val), ctx->regs + offset);
49                         break;
50                 case 4:
51                         writel(be32_to_cpup(val), ctx->regs + offset);
52                         break;
53 #ifdef CONFIG_64BIT
54                 case 8:
55                         writeq(be64_to_cpup(val), ctx->regs + offset);
56                         break;
57 #endif
58                 default:
59                         /* Should be caught by regmap_mmio_check_config */
60                         BUG();
61                 }
62                 val_size -= ctx->val_bytes;
63                 val += ctx->val_bytes;
64                 offset += ctx->val_bytes;
65         }
66
67         return 0;
68 }
69
70 static int regmap_mmio_write(void *context, const void *data, size_t count)
71 {
72         BUG_ON(count < 4);
73
74         return regmap_mmio_gather_write(context, data, 4, data + 4, count - 4);
75 }
76
77 static int regmap_mmio_read(void *context,
78                             const void *reg, size_t reg_size,
79                             void *val, size_t val_size)
80 {
81         struct regmap_mmio_context *ctx = context;
82         u32 offset;
83
84         BUG_ON(reg_size != 4);
85
86         offset = be32_to_cpup(reg);
87
88         while (val_size) {
89                 switch (ctx->val_bytes) {
90                 case 1:
91                         *(u8 *)val = readb(ctx->regs + offset);
92                         break;
93                 case 2:
94                         *(u16 *)val = cpu_to_be16(readw(ctx->regs + offset));
95                         break;
96                 case 4:
97                         *(u32 *)val = cpu_to_be32(readl(ctx->regs + offset));
98                         break;
99 #ifdef CONFIG_64BIT
100                 case 8:
101                         *(u64 *)val = cpu_to_be32(readq(ctx->regs + offset));
102                         break;
103 #endif
104                 default:
105                         /* Should be caught by regmap_mmio_check_config */
106                         BUG();
107                 }
108                 val_size -= ctx->val_bytes;
109                 val += ctx->val_bytes;
110                 offset += ctx->val_bytes;
111         }
112
113         return 0;
114 }
115
116 static void regmap_mmio_free_context(void *context)
117 {
118         kfree(context);
119 }
120
121 static struct regmap_bus regmap_mmio = {
122         .fast_io = true,
123         .write = regmap_mmio_write,
124         .gather_write = regmap_mmio_gather_write,
125         .read = regmap_mmio_read,
126         .free_context = regmap_mmio_free_context,
127 };
128
129 struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs,
130                                         const struct regmap_config *config)
131 {
132         struct regmap_mmio_context *ctx;
133         int min_stride;
134
135         if (config->reg_bits != 32)
136                 return ERR_PTR(-EINVAL);
137
138         if (config->pad_bits)
139                 return ERR_PTR(-EINVAL);
140
141         switch (config->val_bits) {
142         case 8:
143                 /* The core treats 0 as 1 */
144                 min_stride = 0;
145                 break;
146         case 16:
147                 min_stride = 2;
148                 break;
149         case 32:
150                 min_stride = 4;
151                 break;
152 #ifdef CONFIG_64BIT
153         case 64:
154                 min_stride = 8;
155                 break;
156 #endif
157                 break;
158         default:
159                 return ERR_PTR(-EINVAL);
160         }
161
162         if (config->reg_stride < min_stride)
163                 return ERR_PTR(-EINVAL);
164
165         ctx = kzalloc(GFP_KERNEL, sizeof(*ctx));
166         if (!ctx)
167                 return ERR_PTR(-ENOMEM);
168
169         ctx->regs = regs;
170         ctx->val_bytes = config->val_bits / 8;
171
172         return ctx;
173 }
174
175 /**
176  * regmap_init_mmio(): Initialise register map
177  *
178  * @dev: Device that will be interacted with
179  * @regs: Pointer to memory-mapped IO region
180  * @config: Configuration for register map
181  *
182  * The return value will be an ERR_PTR() on error or a valid pointer to
183  * a struct regmap.
184  */
185 struct regmap *regmap_init_mmio(struct device *dev,
186                                 void __iomem *regs,
187                                 const struct regmap_config *config)
188 {
189         struct regmap_mmio_context *ctx;
190
191         ctx = regmap_mmio_gen_context(regs, config);
192         if (IS_ERR(ctx))
193                 return ERR_CAST(ctx);
194
195         return regmap_init(dev, &regmap_mmio, ctx, config);
196 }
197 EXPORT_SYMBOL_GPL(regmap_init_mmio);
198
199 /**
200  * devm_regmap_init_mmio(): Initialise managed register map
201  *
202  * @dev: Device that will be interacted with
203  * @regs: Pointer to memory-mapped IO region
204  * @config: Configuration for register map
205  *
206  * The return value will be an ERR_PTR() on error or a valid pointer
207  * to a struct regmap.  The regmap will be automatically freed by the
208  * device management code.
209  */
210 struct regmap *devm_regmap_init_mmio(struct device *dev,
211                                      void __iomem *regs,
212                                      const struct regmap_config *config)
213 {
214         struct regmap_mmio_context *ctx;
215
216         ctx = regmap_mmio_gen_context(regs, config);
217         if (IS_ERR(ctx))
218                 return ERR_CAST(ctx);
219
220         return devm_regmap_init(dev, &regmap_mmio, ctx, config);
221 }
222 EXPORT_SYMBOL_GPL(devm_regmap_init_mmio);
223
224 MODULE_LICENSE("GPL v2");