123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- // SPDX-License-Identifier: GPL-2.0+
- /*
- * Slow clock support for AT91 architectures.
- *
- * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
- *
- * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
- */
- #include <common.h>
- #include <clk-uclass.h>
- #include <dm.h>
- #include <dt-bindings/clk/at91.h>
- #include <linux/clk-provider.h>
- #include "pmc.h"
- #define UBOOT_DM_CLK_AT91_SAM9X60_TD_SLCK "at91-sam9x60-td-slck"
- #define UBOOT_DM_CLK_AT91_SCKC "at91-sckc"
- #define AT91_OSC_SEL BIT(24)
- #define AT91_OSC_SEL_SHIFT (24)
- struct sam9x60_sckc {
- void __iomem *reg;
- const char **parent_names;
- unsigned int num_parents;
- struct clk clk;
- };
- #define to_sam9x60_sckc(c) container_of(c, struct sam9x60_sckc, clk)
- static int sam9x60_sckc_of_xlate(struct clk *clk,
- struct ofnode_phandle_args *args)
- {
- if (args->args_count != 1) {
- debug("AT91: SCKC: Invalid args_count: %d\n", args->args_count);
- return -EINVAL;
- }
- clk->id = AT91_TO_CLK_ID(PMC_TYPE_SLOW, args->args[0]);
- return 0;
- }
- static const struct clk_ops sam9x60_sckc_ops = {
- .of_xlate = sam9x60_sckc_of_xlate,
- .get_rate = clk_generic_get_rate,
- };
- static int sam9x60_td_slck_set_parent(struct clk *clk, struct clk *parent)
- {
- struct sam9x60_sckc *sckc = to_sam9x60_sckc(clk);
- u32 i;
- for (i = 0; i < sckc->num_parents; i++) {
- if (!strcmp(parent->dev->name, sckc->parent_names[i]))
- break;
- }
- if (i == sckc->num_parents)
- return -EINVAL;
- pmc_update_bits(sckc->reg, 0, AT91_OSC_SEL, (i << AT91_OSC_SEL_SHIFT));
- return 0;
- }
- static const struct clk_ops sam9x60_td_slck_ops = {
- .get_rate = clk_generic_get_rate,
- .set_parent = sam9x60_td_slck_set_parent,
- };
- static struct clk *at91_sam9x60_clk_register_td_slck(struct sam9x60_sckc *sckc,
- const char *name, const char * const *parent_names,
- int num_parents)
- {
- struct clk *clk;
- int ret = -ENOMEM;
- u32 val, i;
- if (!sckc || !name || !parent_names || num_parents != 2)
- return ERR_PTR(-EINVAL);
- sckc->parent_names = kzalloc(sizeof(*sckc->parent_names) * num_parents,
- GFP_KERNEL);
- if (!sckc->parent_names)
- return ERR_PTR(ret);
- for (i = 0; i < num_parents; i++) {
- sckc->parent_names[i] = kmemdup(parent_names[i],
- strlen(parent_names[i]) + 1, GFP_KERNEL);
- if (!sckc->parent_names[i])
- goto free;
- }
- sckc->num_parents = num_parents;
- pmc_read(sckc->reg, 0, &val);
- val = (val & AT91_OSC_SEL) >> AT91_OSC_SEL_SHIFT;
- clk = &sckc->clk;
- ret = clk_register(clk, UBOOT_DM_CLK_AT91_SAM9X60_TD_SLCK, name,
- parent_names[val]);
- if (ret)
- goto free;
- return clk;
- free:
- for (; i >= 0; i--)
- kfree(sckc->parent_names[i]);
- kfree(sckc->parent_names);
- return ERR_PTR(ret);
- }
- U_BOOT_DRIVER(at91_sam9x60_td_slck) = {
- .name = UBOOT_DM_CLK_AT91_SAM9X60_TD_SLCK,
- .id = UCLASS_CLK,
- .ops = &sam9x60_td_slck_ops,
- .flags = DM_FLAG_PRE_RELOC,
- };
- static int at91_sam9x60_sckc_probe(struct udevice *dev)
- {
- struct sam9x60_sckc *sckc = dev_get_priv(dev);
- void __iomem *base = (void *)devfdt_get_addr(dev);
- const char *slow_rc_osc, *slow_osc;
- const char *parents[2];
- struct clk *clk, c;
- int ret;
- ret = clk_get_by_index(dev, 0, &c);
- if (ret)
- return ret;
- slow_rc_osc = clk_hw_get_name(&c);
- ret = clk_get_by_index(dev, 1, &c);
- if (ret)
- return ret;
- slow_osc = clk_hw_get_name(&c);
- clk = clk_register_fixed_factor(NULL, "md_slck", slow_rc_osc, 0, 1, 1);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
- clk_dm(AT91_TO_CLK_ID(PMC_TYPE_SLOW, 0), clk);
- parents[0] = slow_rc_osc;
- parents[1] = slow_osc;
- sckc[1].reg = base;
- clk = at91_sam9x60_clk_register_td_slck(&sckc[1], "td_slck",
- parents, 2);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
- clk_dm(AT91_TO_CLK_ID(PMC_TYPE_SLOW, 1), clk);
- return 0;
- }
- static const struct udevice_id sam9x60_sckc_ids[] = {
- { .compatible = "microchip,sam9x60-sckc" },
- { /* Sentinel. */ },
- };
- U_BOOT_DRIVER(at91_sckc) = {
- .name = UBOOT_DM_CLK_AT91_SCKC,
- .id = UCLASS_CLK,
- .of_match = sam9x60_sckc_ids,
- .priv_auto_alloc_size = sizeof(struct sam9x60_sckc) * 2,
- .ops = &sam9x60_sckc_ops,
- .probe = at91_sam9x60_sckc_probe,
- .flags = DM_FLAG_PRE_RELOC,
- };
|