1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * OMAP clock controller support 4 * 5 * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it> 6 */ 7 8#include <common.h> 9#include <dm.h> 10#include <dm/device_compat.h> 11#include <clk-uclass.h> 12#include <asm/arch-am33xx/clock.h> 13 14struct clk_ti_ctrl_offs { 15 fdt_addr_t start; 16 fdt_size_t end; 17}; 18 19struct clk_ti_ctrl_priv { 20 int offs_num; 21 struct clk_ti_ctrl_offs *offs; 22}; 23 24static int clk_ti_ctrl_check_offs(struct clk *clk, fdt_addr_t offs) 25{ 26 struct clk_ti_ctrl_priv *priv = dev_get_priv(clk->dev); 27 int i; 28 29 for (i = 0; i < priv->offs_num; i++) { 30 if (offs >= priv->offs[i].start && offs <= priv->offs[i].end) 31 return 0; 32 } 33 34 return -EFAULT; 35} 36 37static int clk_ti_ctrl_disable(struct clk *clk) 38{ 39 struct clk_ti_ctrl_priv *priv = dev_get_priv(clk->dev); 40 u32 *clk_modules[2] = { }; 41 fdt_addr_t offs; 42 int err; 43 44 offs = priv->offs[0].start + clk->id; 45 err = clk_ti_ctrl_check_offs(clk, offs); 46 if (err) { 47 dev_err(clk->dev, "invalid offset: 0x%llx\n", (fdt64_t)offs); 48 return err; 49 } 50 51 clk_modules[0] = (u32 *)(offs); 52 dev_dbg(clk->dev, "disable module @ %p\n", clk_modules[0]); 53 do_disable_clocks(NULL, clk_modules, 1); 54 return 0; 55} 56 57static int clk_ti_ctrl_enable(struct clk *clk) 58{ 59 struct clk_ti_ctrl_priv *priv = dev_get_priv(clk->dev); 60 u32 *clk_modules[2] = { }; 61 fdt_addr_t offs; 62 int err; 63 64 offs = priv->offs[0].start + clk->id; 65 err = clk_ti_ctrl_check_offs(clk, offs); 66 if (err) { 67 dev_err(clk->dev, "invalid offset: 0x%llx\n", (fdt64_t)offs); 68 return err; 69 } 70 71 clk_modules[0] = (u32 *)(offs); 72 dev_dbg(clk->dev, "enable module @ %p\n", clk_modules[0]); 73 do_enable_clocks(NULL, clk_modules, 1); 74 return 0; 75} 76 77static ulong clk_ti_ctrl_get_rate(struct clk *clk) 78{ 79 return 0; 80} 81 82static int clk_ti_ctrl_of_xlate(struct clk *clk, 83 struct ofnode_phandle_args *args) 84{ 85 if (args->args_count != 2) { 86 dev_err(clk->dev, "invalid args_count: %d\n", args->args_count); 87 return -EINVAL; 88 } 89 90 if (args->args_count) 91 clk->id = args->args[0]; 92 else 93 clk->id = 0; 94 95 dev_dbg(clk->dev, "name=%s, id=%ld\n", clk->dev->name, clk->id); 96 return 0; 97} 98 99static int clk_ti_ctrl_of_to_plat(struct udevice *dev) 100{ 101 struct clk_ti_ctrl_priv *priv = dev_get_priv(dev); 102 fdt_size_t fdt_size; 103 int i, size; 104 105 size = dev_read_size(dev, "reg"); 106 if (size < 0) { 107 dev_err(dev, "failed to get 'reg' size\n"); 108 return size; 109 } 110 111 priv->offs_num = size / 2 / sizeof(u32); 112 dev_dbg(dev, "size=%d, regs_num=%d\n", size, priv->offs_num); 113 114 priv->offs = kmalloc_array(priv->offs_num, sizeof(*priv->offs), 115 GFP_KERNEL); 116 if (!priv->offs) 117 return -ENOMEM; 118 119 for (i = 0; i < priv->offs_num; i++) { 120 priv->offs[i].start = 121 dev_read_addr_size_index(dev, i, &fdt_size); 122 if (priv->offs[i].start == FDT_ADDR_T_NONE) { 123 dev_err(dev, "failed to get offset %d\n", i); 124 return -EINVAL; 125 } 126 127 priv->offs[i].end = priv->offs[i].start + fdt_size; 128 dev_dbg(dev, "start=0x%016llx, end=0x%016llx\n", 129 (fdt64_t)priv->offs[i].start, 130 (fdt64_t)priv->offs[i].end); 131 } 132 133 return 0; 134} 135 136static struct clk_ops clk_ti_ctrl_ops = { 137 .of_xlate = clk_ti_ctrl_of_xlate, 138 .enable = clk_ti_ctrl_enable, 139 .disable = clk_ti_ctrl_disable, 140 .get_rate = clk_ti_ctrl_get_rate, 141}; 142 143static const struct udevice_id clk_ti_ctrl_ids[] = { 144 {.compatible = "ti,clkctrl"}, 145 {}, 146}; 147 148U_BOOT_DRIVER(clk_ti_ctrl) = { 149 .name = "ti_ctrl_clk", 150 .id = UCLASS_CLK, 151 .of_match = clk_ti_ctrl_ids, 152 .of_to_plat = clk_ti_ctrl_of_to_plat, 153 .ops = &clk_ti_ctrl_ops, 154 .priv_auto = sizeof(struct clk_ti_ctrl_priv), 155}; 156