1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (C) 2016 Atmel Corporation
3*4882a593Smuzhiyun * Wenyou.Yang <wenyou.yang@atmel.com>
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <common.h>
9*4882a593Smuzhiyun #include <clk-uclass.h>
10*4882a593Smuzhiyun #include <dm.h>
11*4882a593Smuzhiyun #include <dm/lists.h>
12*4882a593Smuzhiyun #include <dm/util.h>
13*4882a593Smuzhiyun #include "pmc.h"
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun static const struct udevice_id at91_pmc_match[] = {
18*4882a593Smuzhiyun { .compatible = "atmel,at91rm9200-pmc" },
19*4882a593Smuzhiyun { .compatible = "atmel,at91sam9260-pmc" },
20*4882a593Smuzhiyun { .compatible = "atmel,at91sam9g45-pmc" },
21*4882a593Smuzhiyun { .compatible = "atmel,at91sam9n12-pmc" },
22*4882a593Smuzhiyun { .compatible = "atmel,at91sam9x5-pmc" },
23*4882a593Smuzhiyun { .compatible = "atmel,sama5d3-pmc" },
24*4882a593Smuzhiyun { .compatible = "atmel,sama5d2-pmc" },
25*4882a593Smuzhiyun {}
26*4882a593Smuzhiyun };
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun U_BOOT_DRIVER(at91_pmc) = {
29*4882a593Smuzhiyun .name = "at91-pmc",
30*4882a593Smuzhiyun .id = UCLASS_SIMPLE_BUS,
31*4882a593Smuzhiyun .of_match = at91_pmc_match,
32*4882a593Smuzhiyun };
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun /*---------------------------------------------------------*/
35*4882a593Smuzhiyun
at91_pmc_core_probe(struct udevice * dev)36*4882a593Smuzhiyun int at91_pmc_core_probe(struct udevice *dev)
37*4882a593Smuzhiyun {
38*4882a593Smuzhiyun struct pmc_platdata *plat = dev_get_platdata(dev);
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun dev = dev_get_parent(dev);
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun plat->reg_base = (struct at91_pmc *)devfdt_get_addr_ptr(dev);
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun return 0;
45*4882a593Smuzhiyun }
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun /**
48*4882a593Smuzhiyun * at91_clk_sub_device_bind() - for the at91 clock driver
49*4882a593Smuzhiyun * Recursively bind its children as clk devices.
50*4882a593Smuzhiyun *
51*4882a593Smuzhiyun * @return: 0 on success, or negative error code on failure
52*4882a593Smuzhiyun */
at91_clk_sub_device_bind(struct udevice * dev,const char * drv_name)53*4882a593Smuzhiyun int at91_clk_sub_device_bind(struct udevice *dev, const char *drv_name)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun const void *fdt = gd->fdt_blob;
56*4882a593Smuzhiyun int offset = dev_of_offset(dev);
57*4882a593Smuzhiyun bool pre_reloc_only = !(gd->flags & GD_FLG_RELOC);
58*4882a593Smuzhiyun const char *name;
59*4882a593Smuzhiyun int ret;
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun for (offset = fdt_first_subnode(fdt, offset);
62*4882a593Smuzhiyun offset > 0;
63*4882a593Smuzhiyun offset = fdt_next_subnode(fdt, offset)) {
64*4882a593Smuzhiyun if (pre_reloc_only &&
65*4882a593Smuzhiyun !dm_fdt_pre_reloc(fdt, offset))
66*4882a593Smuzhiyun continue;
67*4882a593Smuzhiyun /*
68*4882a593Smuzhiyun * If this node has "compatible" property, this is not
69*4882a593Smuzhiyun * a clock sub-node, but a normal device. skip.
70*4882a593Smuzhiyun */
71*4882a593Smuzhiyun fdt_get_property(fdt, offset, "compatible", &ret);
72*4882a593Smuzhiyun if (ret >= 0)
73*4882a593Smuzhiyun continue;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun if (ret != -FDT_ERR_NOTFOUND)
76*4882a593Smuzhiyun return ret;
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun name = fdt_get_name(fdt, offset, NULL);
79*4882a593Smuzhiyun if (!name)
80*4882a593Smuzhiyun return -EINVAL;
81*4882a593Smuzhiyun ret = device_bind_driver_to_node(dev, drv_name, name,
82*4882a593Smuzhiyun offset_to_ofnode(offset), NULL);
83*4882a593Smuzhiyun if (ret)
84*4882a593Smuzhiyun return ret;
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun return 0;
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun
at91_clk_of_xlate(struct clk * clk,struct ofnode_phandle_args * args)90*4882a593Smuzhiyun int at91_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun int periph;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun if (args->args_count) {
95*4882a593Smuzhiyun debug("Invalid args_count: %d\n", args->args_count);
96*4882a593Smuzhiyun return -EINVAL;
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun periph = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(clk->dev), "reg",
100*4882a593Smuzhiyun -1);
101*4882a593Smuzhiyun if (periph < 0)
102*4882a593Smuzhiyun return -EINVAL;
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun clk->id = periph;
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun return 0;
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun
at91_clk_probe(struct udevice * dev)109*4882a593Smuzhiyun int at91_clk_probe(struct udevice *dev)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun struct udevice *dev_periph_container, *dev_pmc;
112*4882a593Smuzhiyun struct pmc_platdata *plat = dev_get_platdata(dev);
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun dev_periph_container = dev_get_parent(dev);
115*4882a593Smuzhiyun dev_pmc = dev_get_parent(dev_periph_container);
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun plat->reg_base = (struct at91_pmc *)devfdt_get_addr_ptr(dev_pmc);
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun return 0;
120*4882a593Smuzhiyun }
121