struct regmap *syscon;初始化

来源:互联网 发布:2017亚吉铁路现状知乎 编辑:程序博客网 时间:2024/05/24 00:28
如果在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, &regmap_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);保存

原创粉丝点击