如果在dts下有如下节点
dsa_subctrl: dsa_subctrl@c0000000 {
compatible = "hisilicon,dsa-subctrl", "syscon";
reg = <0x0 0xc0000000 0x0 0x10000>;
};
则会出发drivers/mfd/syscon.c 中的
236 static const struct platform_device_id syscon_ids[] = {
237 { "syscon", },
238 { }
239 };
241 static struct platform_driver syscon_driver = {
242 .driver = {
243 .name = "syscon",
244 },
245 .probe = syscon_probe,
246 .id_table = syscon_ids,
247 };
248
249 static int __init syscon_init(void)
250 {
251 return platform_driver_register(&syscon_driver);
252 }
253 postcore_initcall(syscon_init);
这里就会调用syscon_probe
static int syscon_probe(struct platform_device *pdev)
200 {
201 struct device *dev = &pdev->dev;
202 struct syscon_platform_data *pdata = dev_get_platdata(dev);
203 struct syscon *syscon;
204 struct regmap_config syscon_config = syscon_regmap_config;
205 struct resource *res;
206 void __iomem *base;
207// 申请struct syscon *syscon 结构
208 syscon = devm_kzalloc(dev, sizeof(*syscon), GFP_KERNEL);
209 if (!syscon)
210 return -ENOMEM;
211//得到io mem,就是dts中的reg = <0x0 0xc0000000 0x0 0x10000>;
212 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
213 if (!res)
214 return -ENOENT;
215//通过devm_ioremap 得到虚拟地址
216 base = devm_ioremap(dev, res->start, resource_size(res));
217 if (!base)
218 return -ENOMEM;
219
220 syscon_config.max_register = res->end - res->start - 3;
221 if (pdata)
222 syscon_config.name = pdata->label;
//后面分析
223 syscon->regmap = devm_regmap_init_mmio(dev, base, &syscon_config);
224 if (IS_ERR(syscon->regmap)) {
225 dev_err(dev, "regmap init failed\n");
226 return PTR_ERR(syscon->regmap);
227 }
228 //将syscon设置为platform_device *pdev的drvdata
229 platform_set_drvdata(pdev, syscon);
230
231 dev_dbg(dev, "regmap %pR registered\n", res);
232
233 return 0;
234 }
可以从开机log中搜regmap,来查看remap的寄存器
继续看devm_regmap_init_mmio的实现
741 #define devm_regmap_init_mmio(dev, regs, config) \
742 devm_regmap_init_mmio_clk(dev, NULL, regs, config)
726 #define devm_regmap_init_mmio_clk(dev, clk_id, regs, config) \
727 __regmap_lockdep_wrapper(__devm_regmap_init_mmio_clk, #config, \
728 dev, clk_id, regs, config)
继续看__regmap_lockdep_wrapper
#ifdef CONFIG_LOCKDEP
515 #define __regmap_lockdep_wrapper(fn, name, ...) \
516 ( \
517 ({ \
518 static struct lock_class_key _key; \
519 fn(__VA_ARGS__, &_key, \
520 KBUILD_BASENAME ":" \
521 __stringify(__LINE__) ":" \
522 "(" name ")->lock"); \
523 }) \
524 )
525 #else
526 #define __regmap_lockdep_wrapper(fn, name, ...) fn(__VA_ARGS__, NULL, NULL)
527 #endif
这里假定没有定义CONFIG_LOCKDEP,则__regmap_lockdep_wrapper 就等于__devm_regmap_init_mmio_clk
struct regmap *__devm_regmap_init_mmio_clk(struct device *dev,
349 const char *clk_id,
350 void __iomem *regs,
351 const struct regmap_config *config,
352 struct lock_class_key *lock_key,
353 const char *lock_name)
354 {
355 struct regmap_mmio_context *ctx;
356 //首先调用regmap_mmio_gen_context 得到struct regmap_mmio_context *ctx;
357 ctx = regmap_mmio_gen_context(dev, clk_id, regs, config);
358 if (IS_ERR(ctx))
359 return ERR_CAST(ctx);
360 //然后继续调用__devm_regmap_init 初始化
361 return __devm_regmap_init(dev, ®map_mmio, ctx, config,
362 lock_key, lock_name);
363 }
注意这里的
212 static const struct regmap_bus regmap_mmio = {
213 .fast_io = true,
214 .reg_write = regmap_mmio_write,
215 .reg_read = regmap_mmio_read,
216 .free_context = regmap_mmio_free_context,
217 .val_format_endian_default = REGMAP_ENDIAN_LITTLE,
218 };
regmap_mmio的reg_write最终还是调用ctx->reg_write,这里的struct regmap_mmio_context *ctx 是通过regmap_mmio_gen_context得到的
static int regmap_mmio_write(void *context, unsigned int reg, unsigned int val)
126 {
127 struct regmap_mmio_context *ctx = context;
128 int ret;
129
130 if (!IS_ERR(ctx->clk)) {
131 ret = clk_enable(ctx->clk);
132 if (ret < 0)
133 return ret;
134 }
135
136 ctx->reg_write(ctx, reg, val);
137
138 if (!IS_ERR(ctx->clk))
139 clk_disable(ctx->clk);
140
141 return 0;
142 }
继续看regmap_mmio_gen_context。其主要是申请struct regmap_mmio_context *ctx 占用的空间,并给ctx赋值
继续看__devm_regmap_init
struct regmap *__devm_regmap_init(struct device *dev,
1057 const struct regmap_bus *bus,
1058 void *bus_context,
1059 const struct regmap_config *config,
1060 struct lock_class_key *lock_key,
1061 const char *lock_name)
1062 {
1063 struct regmap **ptr, *regmap;
1064 //申请空间
1065 ptr = devres_alloc(devm_regmap_release, sizeof(*ptr), GFP_KERNEL);
1066 if (!ptr)
1067 return ERR_PTR(-ENOMEM);
1068 赋值
1069 regmap = __regmap_init(dev, bus, bus_context, config,
1070 lock_key, lock_name);
1071 if (!IS_ERR(regmap)) {
1072 *ptr = regmap;
1073 devres_add(dev, ptr);
1074 } else {
1075 devres_free(ptr);
1076 }
1077
1078 return regmap;
1079 }
最终返回regmap。回到syscon_probe 中最终将syscon->regmap = devm_regmap_init_mmio(dev, base, &syscon_config);保存