]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
clk: at91: Improve the clock implementation
authorWenyou Yang <wenyou.yang@atmel.com>
Tue, 27 Sep 2016 03:00:29 +0000 (11:00 +0800)
committerAndreas Bießmann <andreas@biessmann.org>
Fri, 28 Oct 2016 16:37:14 +0000 (18:37 +0200)
For the peripheral clock, provide the clock ops for the clock
provider, such as spi0_clk. The .of_xlate is to get the clk->id,
the .enable is to enable the spi0 peripheral clock, the .get_rate
is to get the clock frequency.

The driver for periph32ck node is responsible for recursively
binding its children as clk devices, not provide the clock ops.

So do the generated clock and system clock.

Signed-off-by: Wenyou Yang <wenyou.yang@atmel.com>
Acked-by: Stephen Warren <swarren@nvidia.com>
drivers/clk/at91/Kconfig
drivers/clk/at91/clk-generated.c
drivers/clk/at91/clk-peripheral.c
drivers/clk/at91/clk-system.c
drivers/clk/at91/pmc.c
drivers/clk/at91/pmc.h

index 10050d8a44216adc93ced1ddf121b6bf4eaac02a..904ed48e51e0f071629afb9b41042d7765891cbb 100644 (file)
@@ -1,6 +1,7 @@
 config CLK_AT91
        bool "AT91 clock drivers"
        depends on CLK
+       select MISC
        help
          This option is used to enable the AT91 clock driver.
          The driver supports the AT91 clock generator, including
index f6164cc8ca1c8ac1b5430502710d911bc832e3f6..d36f64ffdf81b7df371b67f77c70cb356ef210d9 100644 (file)
@@ -17,15 +17,41 @@ DECLARE_GLOBAL_DATA_PTR;
 #define GENERATED_SOURCE_MAX   6
 #define GENERATED_MAX_DIV      255
 
-struct generated_clk_priv {
+/**
+ * generated_clk_bind() - for the generated clock driver
+ * Recursively bind its children as clk devices.
+ *
+ * @return: 0 on success, or negative error code on failure
+ */
+static int generated_clk_bind(struct udevice *dev)
+{
+       return at91_clk_sub_device_bind(dev, "generic-clk");
+}
+
+static const struct udevice_id generated_clk_match[] = {
+       { .compatible = "atmel,sama5d2-clk-generated" },
+       {}
+};
+
+U_BOOT_DRIVER(generated_clk) = {
+       .name = "generated-clk",
+       .id = UCLASS_MISC,
+       .of_match = generated_clk_match,
+       .bind = generated_clk_bind,
+};
+
+/*-------------------------------------------------------------*/
+
+struct generic_clk_priv {
        u32 num_parents;
 };
 
-static ulong generated_clk_get_rate(struct clk *clk)
+static ulong generic_clk_get_rate(struct clk *clk)
 {
        struct pmc_platdata *plat = dev_get_platdata(clk->dev);
        struct at91_pmc *pmc = plat->reg_base;
        struct clk parent;
+       ulong clk_rate;
        u32 tmp, gckdiv;
        u8 parent_id;
        int ret;
@@ -36,18 +62,22 @@ static ulong generated_clk_get_rate(struct clk *clk)
                    AT91_PMC_PCR_GCKCSS_MASK;
        gckdiv = (tmp >> AT91_PMC_PCR_GCKDIV_OFFSET) & AT91_PMC_PCR_GCKDIV_MASK;
 
-       ret = clk_get_by_index(clk->dev, parent_id, &parent);
+       ret = clk_get_by_index(dev_get_parent(clk->dev), parent_id, &parent);
        if (ret)
                return 0;
 
-       return clk_get_rate(&parent) / (gckdiv + 1);
+       clk_rate = clk_get_rate(&parent) / (gckdiv + 1);
+
+       clk_free(&parent);
+
+       return clk_rate;
 }
 
-static ulong generated_clk_set_rate(struct clk *clk, ulong rate)
+static ulong generic_clk_set_rate(struct clk *clk, ulong rate)
 {
        struct pmc_platdata *plat = dev_get_platdata(clk->dev);
        struct at91_pmc *pmc = plat->reg_base;
-       struct generated_clk_priv *priv = dev_get_priv(clk->dev);
+       struct generic_clk_priv *priv = dev_get_priv(clk->dev);
        struct clk parent, best_parent;
        ulong tmp_rate, best_rate = rate, parent_rate;
        int tmp_diff, best_diff = -1;
@@ -58,7 +88,7 @@ static ulong generated_clk_set_rate(struct clk *clk, ulong rate)
        int ret;
 
        for (i = 0; i < priv->num_parents; i++) {
-               ret = clk_get_by_index(clk->dev, i, &parent);
+               ret = clk_get_by_index(dev_get_parent(clk->dev), i, &parent);
                if (ret)
                        return ret;
 
@@ -111,18 +141,20 @@ static ulong generated_clk_set_rate(struct clk *clk, ulong rate)
        return 0;
 }
 
-static struct clk_ops generated_clk_ops = {
-       .get_rate = generated_clk_get_rate,
-       .set_rate = generated_clk_set_rate,
+static struct clk_ops generic_clk_ops = {
+       .of_xlate = at91_clk_of_xlate,
+       .get_rate = generic_clk_get_rate,
+       .set_rate = generic_clk_set_rate,
 };
 
-static int generated_clk_ofdata_to_platdata(struct udevice *dev)
+static int generic_clk_ofdata_to_platdata(struct udevice *dev)
 {
-       struct generated_clk_priv *priv = dev_get_priv(dev);
+       struct generic_clk_priv *priv = dev_get_priv(dev);
        u32 cells[GENERATED_SOURCE_MAX];
        u32 num_parents;
 
-       num_parents = fdtdec_get_int_array_count(gd->fdt_blob, dev->of_offset,
+       num_parents = fdtdec_get_int_array_count(gd->fdt_blob,
+                                                dev_get_parent(dev)->of_offset,
                                                 "clocks", cells,
                                                 GENERATED_SOURCE_MAX);
 
@@ -134,29 +166,12 @@ static int generated_clk_ofdata_to_platdata(struct udevice *dev)
        return 0;
 }
 
-static int generated_clk_bind(struct udevice *dev)
-{
-       return at91_pmc_clk_node_bind(dev);
-}
-
-static int generated_clk_probe(struct udevice *dev)
-{
-       return at91_pmc_core_probe(dev);
-}
-
-static const struct udevice_id generated_clk_match[] = {
-       { .compatible = "atmel,sama5d2-clk-generated" },
-       {}
-};
-
-U_BOOT_DRIVER(generated_clk) = {
-       .name = "generated-clk",
+U_BOOT_DRIVER(generic_clk) = {
+       .name = "generic-clk",
        .id = UCLASS_CLK,
-       .of_match = generated_clk_match,
-       .bind = generated_clk_bind,
-       .probe = generated_clk_probe,
-       .ofdata_to_platdata = generated_clk_ofdata_to_platdata,
-       .priv_auto_alloc_size = sizeof(struct generated_clk_priv),
+       .probe = at91_clk_probe,
+       .ofdata_to_platdata = generic_clk_ofdata_to_platdata,
+       .priv_auto_alloc_size = sizeof(struct generic_clk_priv),
        .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
-       .ops = &generated_clk_ops,
+       .ops = &generic_clk_ops,
 };
index 16688e90b417fc1ed9a3996f848f7be606eb822c..e1ed447133e077201c5b7f638ef23b5e6d0850b8 100644 (file)
 #define PERIPHERAL_ID_MAX      31
 #define PERIPHERAL_MASK(id)    (1 << ((id) & PERIPHERAL_ID_MAX))
 
-static int sam9x5_periph_clk_enable(struct clk *clk)
+/**
+ * sam9x5_periph_clk_bind() - for the periph clock driver
+ * Recursively bind its children as clk devices.
+ *
+ * @return: 0 on success, or negative error code on failure
+ */
+static int sam9x5_periph_clk_bind(struct udevice *dev)
+{
+       return at91_clk_sub_device_bind(dev, "periph-clk");
+}
+
+static const struct udevice_id sam9x5_periph_clk_match[] = {
+       { .compatible = "atmel,at91sam9x5-clk-peripheral" },
+       {}
+};
+
+U_BOOT_DRIVER(sam9x5_periph_clk) = {
+       .name = "sam9x5-periph-clk",
+       .id = UCLASS_MISC,
+       .of_match = sam9x5_periph_clk_match,
+       .bind = sam9x5_periph_clk_bind,
+};
+
+/*---------------------------------------------------------*/
+
+static int periph_clk_enable(struct clk *clk)
 {
        struct pmc_platdata *plat = dev_get_platdata(clk->dev);
        struct at91_pmc *pmc = plat->reg_base;
@@ -30,31 +55,36 @@ static int sam9x5_periph_clk_enable(struct clk *clk)
        return 0;
 }
 
-static struct clk_ops sam9x5_periph_clk_ops = {
-       .enable = sam9x5_periph_clk_enable,
-};
-
-static int sam9x5_periph_clk_bind(struct udevice *dev)
+static ulong periph_get_rate(struct clk *clk)
 {
-       return at91_pmc_clk_node_bind(dev);
-}
+       struct udevice *dev;
+       struct clk clk_dev;
+       ulong clk_rate;
+       int ret;
 
-static int sam9x5_periph_clk_probe(struct udevice *dev)
-{
-       return at91_pmc_core_probe(dev);
+       dev = dev_get_parent(clk->dev);
+
+       ret = clk_get_by_index(dev, 0, &clk_dev);
+       if (ret)
+               return ret;
+
+       clk_rate = clk_get_rate(&clk_dev);
+
+       clk_free(&clk_dev);
+
+       return clk_rate;
 }
 
-static const struct udevice_id sam9x5_periph_clk_match[] = {
-       { .compatible = "atmel,at91sam9x5-clk-peripheral" },
-       {}
+static struct clk_ops periph_clk_ops = {
+       .of_xlate = at91_clk_of_xlate,
+       .enable = periph_clk_enable,
+       .get_rate = periph_get_rate,
 };
 
-U_BOOT_DRIVER(sam9x5_periph_clk) = {
-       .name = "sam9x5-periph-clk",
-       .id = UCLASS_CLK,
-       .of_match = sam9x5_periph_clk_match,
-       .bind = sam9x5_periph_clk_bind,
-       .probe = sam9x5_periph_clk_probe,
+U_BOOT_DRIVER(clk_periph) = {
+       .name   = "periph-clk",
+       .id     = UCLASS_CLK,
        .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
-       .ops = &sam9x5_periph_clk_ops,
+       .probe = at91_clk_probe,
+       .ops    = &periph_clk_ops,
 };
index fa80bade7a91e80bc530cbfee1163165b06d846a..5b59a0c85204fda795ca6877732bbf66a0e43f39 100644 (file)
 
 #define SYSTEM_MAX_ID          31
 
+/**
+ * at91_system_clk_bind() - for the system clock driver
+ * Recursively bind its children as clk devices.
+ *
+ * @return: 0 on success, or negative error code on failure
+ */
+static int at91_system_clk_bind(struct udevice *dev)
+{
+       return at91_clk_sub_device_bind(dev, "system-clk");
+}
+
+static const struct udevice_id at91_system_clk_match[] = {
+       { .compatible = "atmel,at91rm9200-clk-system" },
+       {}
+};
+
+U_BOOT_DRIVER(at91_system_clk) = {
+       .name = "at91-system-clk",
+       .id = UCLASS_MISC,
+       .of_match = at91_system_clk_match,
+       .bind = at91_system_clk_bind,
+};
+
+/*----------------------------------------------------------*/
+
 static inline int is_pck(int id)
 {
        return (id >= 8) && (id <= 15);
 }
 
-static int at91_system_clk_enable(struct clk *clk)
+static int system_clk_enable(struct clk *clk)
 {
        struct pmc_platdata *plat = dev_get_platdata(clk->dev);
        struct at91_pmc *pmc = plat->reg_base;
@@ -46,31 +71,15 @@ static int at91_system_clk_enable(struct clk *clk)
        return 0;
 }
 
-static struct clk_ops at91_system_clk_ops = {
-       .enable = at91_system_clk_enable,
+static struct clk_ops system_clk_ops = {
+       .of_xlate = at91_clk_of_xlate,
+       .enable = system_clk_enable,
 };
 
-static int at91_system_clk_bind(struct udevice *dev)
-{
-       return at91_pmc_clk_node_bind(dev);
-}
-
-static int at91_system_clk_probe(struct udevice *dev)
-{
-       return at91_pmc_core_probe(dev);
-}
-
-static const struct udevice_id at91_system_clk_match[] = {
-       { .compatible = "atmel,at91rm9200-clk-system" },
-       {}
-};
-
-U_BOOT_DRIVER(at91_system_clk) = {
-       .name = "at91-system-clk",
+U_BOOT_DRIVER(system_clk) = {
+       .name = "system-clk",
        .id = UCLASS_CLK,
-       .of_match = at91_system_clk_match,
-       .bind = at91_system_clk_bind,
-       .probe = at91_system_clk_probe,
+       .probe = at91_clk_probe,
        .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
-       .ops = &at91_system_clk_ops,
+       .ops = &system_clk_ops,
 };
index 76ff3871d0b490316a6f54f369897f782e939715..76ba91af81209296585eae984e6143b3719c0db0 100644 (file)
@@ -25,6 +25,8 @@ U_BOOT_DRIVER(at91_pmc) = {
        .of_match = at91_pmc_match,
 };
 
+/*---------------------------------------------------------*/
+
 int at91_pmc_core_probe(struct udevice *dev)
 {
        struct pmc_platdata *plat = dev_get_platdata(dev);
@@ -36,21 +38,41 @@ int at91_pmc_core_probe(struct udevice *dev)
        return 0;
 }
 
-int at91_pmc_clk_node_bind(struct udevice *dev)
+/**
+ * at91_clk_sub_device_bind() - for the at91 clock driver
+ * Recursively bind its children as clk devices.
+ *
+ * @return: 0 on success, or negative error code on failure
+ */
+int at91_clk_sub_device_bind(struct udevice *dev, const char *drv_name)
 {
        const void *fdt = gd->fdt_blob;
        int offset = dev->of_offset;
+       bool pre_reloc_only = !(gd->flags & GD_FLG_RELOC);
        const char *name;
        int ret;
 
        for (offset = fdt_first_subnode(fdt, offset);
             offset > 0;
             offset = fdt_next_subnode(fdt, offset)) {
+               if (pre_reloc_only &&
+                   !fdt_getprop(fdt, offset, "u-boot,dm-pre-reloc", NULL))
+                       continue;
+               /*
+                * If this node has "compatible" property, this is not
+                * a clock sub-node, but a normal device. skip.
+                */
+               fdt_get_property(fdt, offset, "compatible", &ret);
+               if (ret >= 0)
+                       continue;
+
+               if (ret != -FDT_ERR_NOTFOUND)
+                       return ret;
+
                name = fdt_get_name(fdt, offset, NULL);
                if (!name)
                        return -EINVAL;
-
-               ret = device_bind_driver_to_node(dev, "clk", name,
+               ret = device_bind_driver_to_node(dev, drv_name, name,
                                                 offset, NULL);
                if (ret)
                        return ret;
@@ -59,7 +81,33 @@ int at91_pmc_clk_node_bind(struct udevice *dev)
        return 0;
 }
 
-U_BOOT_DRIVER(clk_generic) = {
-       .id     = UCLASS_CLK,
-       .name   = "clk",
-};
+int at91_clk_of_xlate(struct clk *clk, struct fdtdec_phandle_args *args)
+{
+       int periph;
+
+       if (args->args_count) {
+               debug("Invalid args_count: %d\n", args->args_count);
+               return -EINVAL;
+       }
+
+       periph = fdtdec_get_uint(gd->fdt_blob, clk->dev->of_offset, "reg", -1);
+       if (periph < 0)
+               return -EINVAL;
+
+       clk->id = periph;
+
+       return 0;
+}
+
+int at91_clk_probe(struct udevice *dev)
+{
+       struct udevice *dev_periph_container, *dev_pmc;
+       struct pmc_platdata *plat = dev_get_platdata(dev);
+
+       dev_periph_container = dev_get_parent(dev);
+       dev_pmc = dev_get_parent(dev_periph_container);
+
+       plat->reg_base = (struct at91_pmc *)dev_get_addr_ptr(dev_pmc);
+
+       return 0;
+}
index 5444c84db66cc76dabc5f165ddb14bf13f6f7a7e..f222fce11f427aef09625993994c97fe0f44a89b 100644 (file)
@@ -13,6 +13,9 @@ struct pmc_platdata {
 };
 
 int at91_pmc_core_probe(struct udevice *dev);
-int at91_pmc_clk_node_bind(struct udevice *dev);
+int at91_clk_sub_device_bind(struct udevice *dev, const char *drv_name);
+
+int at91_clk_of_xlate(struct clk *clk, struct fdtdec_phandle_args *args);
+int at91_clk_probe(struct udevice *dev);
 
 #endif