19e5935c0SWenyou Yang /* 29e5935c0SWenyou Yang * Copyright (C) 2016 Atmel Corporation 39e5935c0SWenyou Yang * Wenyou.Yang <wenyou.yang@atmel.com> 49e5935c0SWenyou Yang * 59e5935c0SWenyou Yang * SPDX-License-Identifier: GPL-2.0+ 69e5935c0SWenyou Yang */ 79e5935c0SWenyou Yang 89e5935c0SWenyou Yang #include <common.h> 99e5935c0SWenyou Yang #include <clk-uclass.h> 109e5935c0SWenyou Yang #include <dm/device.h> 119e5935c0SWenyou Yang #include <linux/io.h> 129e5935c0SWenyou Yang #include <mach/at91_pmc.h> 139e5935c0SWenyou Yang #include "pmc.h" 149e5935c0SWenyou Yang 159e5935c0SWenyou Yang #define PERIPHERAL_ID_MIN 2 169e5935c0SWenyou Yang #define PERIPHERAL_ID_MAX 31 179e5935c0SWenyou Yang #define PERIPHERAL_MASK(id) (1 << ((id) & PERIPHERAL_ID_MAX)) 189e5935c0SWenyou Yang 19*6cadaa04SWenyou Yang /** 20*6cadaa04SWenyou Yang * sam9x5_periph_clk_bind() - for the periph clock driver 21*6cadaa04SWenyou Yang * Recursively bind its children as clk devices. 22*6cadaa04SWenyou Yang * 23*6cadaa04SWenyou Yang * @return: 0 on success, or negative error code on failure 24*6cadaa04SWenyou Yang */ 25*6cadaa04SWenyou Yang static int sam9x5_periph_clk_bind(struct udevice *dev) 26*6cadaa04SWenyou Yang { 27*6cadaa04SWenyou Yang return at91_clk_sub_device_bind(dev, "periph-clk"); 28*6cadaa04SWenyou Yang } 29*6cadaa04SWenyou Yang 30*6cadaa04SWenyou Yang static const struct udevice_id sam9x5_periph_clk_match[] = { 31*6cadaa04SWenyou Yang { .compatible = "atmel,at91sam9x5-clk-peripheral" }, 32*6cadaa04SWenyou Yang {} 33*6cadaa04SWenyou Yang }; 34*6cadaa04SWenyou Yang 35*6cadaa04SWenyou Yang U_BOOT_DRIVER(sam9x5_periph_clk) = { 36*6cadaa04SWenyou Yang .name = "sam9x5-periph-clk", 37*6cadaa04SWenyou Yang .id = UCLASS_MISC, 38*6cadaa04SWenyou Yang .of_match = sam9x5_periph_clk_match, 39*6cadaa04SWenyou Yang .bind = sam9x5_periph_clk_bind, 40*6cadaa04SWenyou Yang }; 41*6cadaa04SWenyou Yang 42*6cadaa04SWenyou Yang /*---------------------------------------------------------*/ 43*6cadaa04SWenyou Yang 44*6cadaa04SWenyou Yang static int periph_clk_enable(struct clk *clk) 459e5935c0SWenyou Yang { 469e5935c0SWenyou Yang struct pmc_platdata *plat = dev_get_platdata(clk->dev); 479e5935c0SWenyou Yang struct at91_pmc *pmc = plat->reg_base; 489e5935c0SWenyou Yang 499e5935c0SWenyou Yang if (clk->id < PERIPHERAL_ID_MIN) 509e5935c0SWenyou Yang return -1; 519e5935c0SWenyou Yang 529e5935c0SWenyou Yang writel(clk->id & AT91_PMC_PCR_PID_MASK, &pmc->pcr); 539e5935c0SWenyou Yang setbits_le32(&pmc->pcr, AT91_PMC_PCR_CMD_WRITE | AT91_PMC_PCR_EN); 549e5935c0SWenyou Yang 559e5935c0SWenyou Yang return 0; 569e5935c0SWenyou Yang } 579e5935c0SWenyou Yang 58*6cadaa04SWenyou Yang static ulong periph_get_rate(struct clk *clk) 599e5935c0SWenyou Yang { 60*6cadaa04SWenyou Yang struct udevice *dev; 61*6cadaa04SWenyou Yang struct clk clk_dev; 62*6cadaa04SWenyou Yang ulong clk_rate; 63*6cadaa04SWenyou Yang int ret; 64*6cadaa04SWenyou Yang 65*6cadaa04SWenyou Yang dev = dev_get_parent(clk->dev); 66*6cadaa04SWenyou Yang 67*6cadaa04SWenyou Yang ret = clk_get_by_index(dev, 0, &clk_dev); 68*6cadaa04SWenyou Yang if (ret) 69*6cadaa04SWenyou Yang return ret; 70*6cadaa04SWenyou Yang 71*6cadaa04SWenyou Yang clk_rate = clk_get_rate(&clk_dev); 72*6cadaa04SWenyou Yang 73*6cadaa04SWenyou Yang clk_free(&clk_dev); 74*6cadaa04SWenyou Yang 75*6cadaa04SWenyou Yang return clk_rate; 769e5935c0SWenyou Yang } 779e5935c0SWenyou Yang 78*6cadaa04SWenyou Yang static struct clk_ops periph_clk_ops = { 79*6cadaa04SWenyou Yang .of_xlate = at91_clk_of_xlate, 80*6cadaa04SWenyou Yang .enable = periph_clk_enable, 81*6cadaa04SWenyou Yang .get_rate = periph_get_rate, 829e5935c0SWenyou Yang }; 839e5935c0SWenyou Yang 84*6cadaa04SWenyou Yang U_BOOT_DRIVER(clk_periph) = { 85*6cadaa04SWenyou Yang .name = "periph-clk", 869e5935c0SWenyou Yang .id = UCLASS_CLK, 879e5935c0SWenyou Yang .platdata_auto_alloc_size = sizeof(struct pmc_platdata), 88*6cadaa04SWenyou Yang .probe = at91_clk_probe, 89*6cadaa04SWenyou Yang .ops = &periph_clk_ops, 909e5935c0SWenyou Yang }; 91