syscon 的使用

来源:互联网 发布:多益网络面试经验 编辑:程序博客网 时间:2024/06/07 20:37
如果在dts中有如下节点,               
 dsaf0: dsa@c7000000 {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        compatible = "hisilicon,hns-dsaf-v2";
                        mode = "6port-16rss";
                        reg = <0x0 0xc5000000 0x0 0x890000
                               0x0 0xc7000000 0x0 0x600000>;
                        reg-names = "ppe-base", "dsaf-base";
                        interrupt-parent = <&mbigen_dsaf0>;
                        subctrl-syscon = <&dsa_subctrl>;
            }
我们可以通过of_parse_phandle 就能拿到subctrl-syscon
np_temp = of_parse_phandle(np, "subctrl-syscon", 0);

这里subctrl-syscon的之定义如下:


dsa_subctrl: dsa_subctrl@c0000000 {
     compatible = "hisilicon,dsa-subctrl", "syscon";
     reg = <0x0 0xc0000000 0x0 0x10000>;
     };
然后我们就可以通过syscon_node_to_regmap来为np_temp 做映射,这里的syscon的类型是    struct regmap *syscon;

syscon = syscon_node_to_regmap(np_temp);

这样后续就可以通过写dsa_subctrl 中定义的reg寄存器
dsaf_write_syscon(dsaf_dev->sub_ctrl, reg, val);
static inline void dsaf_write_syscon(struct regmap *base, u32 reg, u32 value)
{
    regmap_write(base, reg, value);
}


那下来我们看看syscon_node_to_regmap的实现,其源代码同样在/drivers/mfd/syscon.c 中
struct regmap *syscon_node_to_regmap(struct device_node *np)
118    {
119        struct syscon *entry, *syscon = NULL;
120    
121        spin_lock(&syscon_list_slock);
122    //首先在syscon_list 中查找是否已经有syscon,第一次的话,肯定是没有
123        list_for_each_entry(entry, &syscon_list, list)
124            if (entry->np == np) {
125                syscon = entry;
126                break;
127            }
128    
129        spin_unlock(&syscon_list_slock);
130    //第一次syscon是空的,调用of_syscon_register
131        if (!syscon)
132            syscon = of_syscon_register(np);
133    
134        if (IS_ERR(syscon))
135            return ERR_CAST(syscon);
136    
137        return syscon->regmap;
138    }


45    static struct syscon *of_syscon_register(struct device_node *np)
46    {
47        struct syscon *syscon;
48        struct regmap *regmap;
49        void __iomem *base;
50        u32 reg_io_width;
51        int ret;
52        struct regmap_config syscon_config = syscon_regmap_config;
53        struct resource res;
54    //如果dts中不包含syscon,则直接退出
55        if (!of_device_is_compatible(np, "syscon"))
56            return ERR_PTR(-EINVAL);
57    //申请空间,调用kzalloc申请的空间自动清零了,免去额外调用memset清零的动作
58        syscon = kzalloc(sizeof(*syscon), GFP_KERNEL);
59        if (!syscon)
60            return ERR_PTR(-ENOMEM);
61    //得到resource 资源,也就是上面dts中定义的reg
62        if (of_address_to_resource(np, 0, &res)) {
63            ret = -ENOMEM;
64            goto err_map;
65        }
66    //对res做虚拟地址的映射
67        base = ioremap(res.start, resource_size(&res));
68        if (!base) {
69            ret = -ENOMEM;
70            goto err_map;
71        }
72    //字符的格式是big-endian/little-endian/native-endian
73        /* Parse the device's DT node for an endianness specification */
74        if (of_property_read_bool(np, "big-endian"))
75            syscon_config.val_format_endian = REGMAP_ENDIAN_BIG;
76        else if (of_property_read_bool(np, "little-endian"))
77            syscon_config.val_format_endian = REGMAP_ENDIAN_LITTLE;
78        else if (of_property_read_bool(np, "native-endian"))
79            syscon_config.val_format_endian = REGMAP_ENDIAN_NATIVE;
80    
81        /*
82         * search for reg-io-width property in DT. If it is not provided,
83         * default to 4 bytes. regmap_init_mmio will return an error if values
84         * are invalid so there is no need to check them here.
85         */
        得到寄存器的长度,默认是4个byte
86        ret = of_property_read_u32(np, "reg-io-width", &reg_io_width);
87        if (ret)
88            reg_io_width = 4;
89    
90        syscon_config.reg_stride = reg_io_width;
91        syscon_config.val_bits = reg_io_width * 8;
92        syscon_config.max_register = resource_size(&res) - reg_io_width;
93    
94        regmap = regmap_init_mmio(NULL, base, &syscon_config);
95        if (IS_ERR(regmap)) {
96            pr_err("regmap init failed\n");
97            ret = PTR_ERR(regmap);
98            goto err_regmap;
99        }
100    
101        syscon->regmap = regmap;
102        syscon->np = np;
103    
104        spin_lock(&syscon_list_slock);
    //将这里初始化的syscon 添加到全局变量syscon_list 中,这样下一次调用syscon_node_to_regmap 时就会在syscon_list 中找到了
105        list_add_tail(&syscon->list, &syscon_list);
106        spin_unlock(&syscon_list_slock);
107    
108        return syscon;
109    
110    err_regmap:
111        iounmap(base);
112    err_map:
113        kfree(syscon);
114        return ERR_PTR(ret);
115    }

继续看regmap_init_mmio

624    #define regmap_init_mmio(dev, regs, config)        \
625        regmap_init_mmio_clk(dev, NULL, regs, config)
626    

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)
729    
前面的文章分析过__regmap_lockdep_wrapper 是空函数,因此devm_regmap_init_mmio_clk 就等于__devm_regmap_init_mmio_clk,而这个函数之前已经分析过了。


原创粉丝点击