148264d9bSMasahiro Yamada /* 24e3d8406SMasahiro Yamada * Copyright (C) 2016 Socionext Inc. 34e3d8406SMasahiro Yamada * Author: Masahiro Yamada <yamada.masahiro@socionext.com> 448264d9bSMasahiro Yamada * 548264d9bSMasahiro Yamada * SPDX-License-Identifier: GPL-2.0+ 648264d9bSMasahiro Yamada */ 748264d9bSMasahiro Yamada 848264d9bSMasahiro Yamada #include <common.h> 9*805dc44cSMasahiro Yamada #include <clk-uclass.h> 10*805dc44cSMasahiro Yamada #include <dm/device.h> 1148264d9bSMasahiro Yamada #include <linux/bitops.h> 1248264d9bSMasahiro Yamada #include <linux/io.h> 1345a3b1fdSMasahiro Yamada #include <linux/sizes.h> 1448264d9bSMasahiro Yamada 1548264d9bSMasahiro Yamada #include "clk-uniphier.h" 1648264d9bSMasahiro Yamada 17102e3187SMasahiro Yamada /** 18102e3187SMasahiro Yamada * struct uniphier_clk_priv - private data for UniPhier clock driver 19102e3187SMasahiro Yamada * 20102e3187SMasahiro Yamada * @base: base address of the clock provider 21*805dc44cSMasahiro Yamada * @data: SoC specific data 22102e3187SMasahiro Yamada */ 23102e3187SMasahiro Yamada struct uniphier_clk_priv { 24102e3187SMasahiro Yamada void __iomem *base; 25*805dc44cSMasahiro Yamada const struct uniphier_clk_data *data; 26102e3187SMasahiro Yamada }; 27102e3187SMasahiro Yamada 28*805dc44cSMasahiro Yamada static int uniphier_clk_enable(struct clk *clk) 29*805dc44cSMasahiro Yamada { 30*805dc44cSMasahiro Yamada struct uniphier_clk_priv *priv = dev_get_priv(clk->dev); 31*805dc44cSMasahiro Yamada unsigned long id = clk->id; 32*805dc44cSMasahiro Yamada const struct uniphier_clk_gate_data *p; 33*805dc44cSMasahiro Yamada 34*805dc44cSMasahiro Yamada for (p = priv->data->gate; p->id != UNIPHIER_CLK_ID_END; p++) { 35*805dc44cSMasahiro Yamada u32 val; 36*805dc44cSMasahiro Yamada 37*805dc44cSMasahiro Yamada if (p->id != id) 38*805dc44cSMasahiro Yamada continue; 39*805dc44cSMasahiro Yamada 40*805dc44cSMasahiro Yamada val = readl(priv->base + p->reg); 41*805dc44cSMasahiro Yamada val |= BIT(p->bit); 42*805dc44cSMasahiro Yamada writel(val, priv->base + p->reg); 43*805dc44cSMasahiro Yamada 44*805dc44cSMasahiro Yamada return 0; 45*805dc44cSMasahiro Yamada } 46*805dc44cSMasahiro Yamada 47*805dc44cSMasahiro Yamada dev_err(priv->dev, "clk_id=%lu was not handled\n", id); 48*805dc44cSMasahiro Yamada return -EINVAL; 49*805dc44cSMasahiro Yamada } 50*805dc44cSMasahiro Yamada 51*805dc44cSMasahiro Yamada static const struct uniphier_clk_mux_data * 52*805dc44cSMasahiro Yamada uniphier_clk_get_mux_data(struct uniphier_clk_priv *priv, unsigned long id) 53*805dc44cSMasahiro Yamada { 54*805dc44cSMasahiro Yamada const struct uniphier_clk_mux_data *p; 55*805dc44cSMasahiro Yamada 56*805dc44cSMasahiro Yamada for (p = priv->data->mux; p->id != UNIPHIER_CLK_ID_END; p++) { 57*805dc44cSMasahiro Yamada if (p->id == id) 58*805dc44cSMasahiro Yamada return p; 59*805dc44cSMasahiro Yamada } 60*805dc44cSMasahiro Yamada 61*805dc44cSMasahiro Yamada return NULL; 62*805dc44cSMasahiro Yamada } 63*805dc44cSMasahiro Yamada 64*805dc44cSMasahiro Yamada static ulong uniphier_clk_get_rate(struct clk *clk) 65*805dc44cSMasahiro Yamada { 66*805dc44cSMasahiro Yamada struct uniphier_clk_priv *priv = dev_get_priv(clk->dev); 67*805dc44cSMasahiro Yamada const struct uniphier_clk_mux_data *mux; 68*805dc44cSMasahiro Yamada u32 val; 69*805dc44cSMasahiro Yamada int i; 70*805dc44cSMasahiro Yamada 71*805dc44cSMasahiro Yamada mux = uniphier_clk_get_mux_data(priv, clk->id); 72*805dc44cSMasahiro Yamada if (!mux) 73*805dc44cSMasahiro Yamada return 0; 74*805dc44cSMasahiro Yamada 75*805dc44cSMasahiro Yamada if (!mux->nr_muxs) /* fixed-rate */ 76*805dc44cSMasahiro Yamada return mux->rates[0]; 77*805dc44cSMasahiro Yamada 78*805dc44cSMasahiro Yamada val = readl(priv->base + mux->reg); 79*805dc44cSMasahiro Yamada 80*805dc44cSMasahiro Yamada for (i = 0; i < mux->nr_muxs; i++) 81*805dc44cSMasahiro Yamada if ((mux->masks[i] & val) == mux->vals[i]) 82*805dc44cSMasahiro Yamada return mux->rates[i]; 83*805dc44cSMasahiro Yamada 84*805dc44cSMasahiro Yamada return -EINVAL; 85*805dc44cSMasahiro Yamada } 86*805dc44cSMasahiro Yamada 87*805dc44cSMasahiro Yamada static ulong uniphier_clk_set_rate(struct clk *clk, ulong rate) 88*805dc44cSMasahiro Yamada { 89*805dc44cSMasahiro Yamada struct uniphier_clk_priv *priv = dev_get_priv(clk->dev); 90*805dc44cSMasahiro Yamada const struct uniphier_clk_mux_data *mux; 91*805dc44cSMasahiro Yamada u32 val; 92*805dc44cSMasahiro Yamada int i, best_rate_id = -1; 93*805dc44cSMasahiro Yamada ulong best_rate = 0; 94*805dc44cSMasahiro Yamada 95*805dc44cSMasahiro Yamada mux = uniphier_clk_get_mux_data(priv, clk->id); 96*805dc44cSMasahiro Yamada if (!mux) 97*805dc44cSMasahiro Yamada return 0; 98*805dc44cSMasahiro Yamada 99*805dc44cSMasahiro Yamada if (!mux->nr_muxs) /* fixed-rate */ 100*805dc44cSMasahiro Yamada return mux->rates[0]; 101*805dc44cSMasahiro Yamada 102*805dc44cSMasahiro Yamada /* first, decide the best match rate */ 103*805dc44cSMasahiro Yamada for (i = 0; i < mux->nr_muxs; i++) { 104*805dc44cSMasahiro Yamada if (mux->rates[i] > best_rate && mux->rates[i] <= rate) { 105*805dc44cSMasahiro Yamada best_rate = mux->rates[i]; 106*805dc44cSMasahiro Yamada best_rate_id = i; 107*805dc44cSMasahiro Yamada } 108*805dc44cSMasahiro Yamada } 109*805dc44cSMasahiro Yamada 110*805dc44cSMasahiro Yamada if (best_rate_id < 0) 111*805dc44cSMasahiro Yamada return -EINVAL; 112*805dc44cSMasahiro Yamada 113*805dc44cSMasahiro Yamada val = readl(priv->base + mux->reg); 114*805dc44cSMasahiro Yamada val &= ~mux->masks[best_rate_id]; 115*805dc44cSMasahiro Yamada val |= mux->vals[best_rate_id]; 116*805dc44cSMasahiro Yamada writel(val, priv->base + mux->reg); 117*805dc44cSMasahiro Yamada 118*805dc44cSMasahiro Yamada debug("%s: requested rate = %lu, set rate = %lu\n", __func__, 119*805dc44cSMasahiro Yamada rate, best_rate); 120*805dc44cSMasahiro Yamada 121*805dc44cSMasahiro Yamada return best_rate; 122*805dc44cSMasahiro Yamada } 123*805dc44cSMasahiro Yamada 124*805dc44cSMasahiro Yamada const struct clk_ops uniphier_clk_ops = { 125*805dc44cSMasahiro Yamada .enable = uniphier_clk_enable, 126*805dc44cSMasahiro Yamada .get_rate = uniphier_clk_get_rate, 127*805dc44cSMasahiro Yamada .set_rate = uniphier_clk_set_rate, 128*805dc44cSMasahiro Yamada }; 129*805dc44cSMasahiro Yamada 130*805dc44cSMasahiro Yamada static int uniphier_clk_probe(struct udevice *dev) 131102e3187SMasahiro Yamada { 132102e3187SMasahiro Yamada struct uniphier_clk_priv *priv = dev_get_priv(dev); 133102e3187SMasahiro Yamada fdt_addr_t addr; 134102e3187SMasahiro Yamada 1356dc5b6b1SMasahiro Yamada addr = dev_get_addr(dev->parent); 136102e3187SMasahiro Yamada if (addr == FDT_ADDR_T_NONE) 137102e3187SMasahiro Yamada return -EINVAL; 138102e3187SMasahiro Yamada 139102e3187SMasahiro Yamada priv->base = devm_ioremap(dev, addr, SZ_4K); 140102e3187SMasahiro Yamada if (!priv->base) 141102e3187SMasahiro Yamada return -ENOMEM; 142102e3187SMasahiro Yamada 143*805dc44cSMasahiro Yamada priv->data = (void *)dev_get_driver_data(dev); 144102e3187SMasahiro Yamada 145102e3187SMasahiro Yamada return 0; 146102e3187SMasahiro Yamada } 147102e3187SMasahiro Yamada 148102e3187SMasahiro Yamada static const struct udevice_id uniphier_clk_match[] = { 14948264d9bSMasahiro Yamada { 1506dc5b6b1SMasahiro Yamada .compatible = "socionext,uniphier-sld3-mio-clock", 151102e3187SMasahiro Yamada .data = (ulong)&uniphier_mio_clk_data, 152102e3187SMasahiro Yamada }, 153102e3187SMasahiro Yamada { 1546dc5b6b1SMasahiro Yamada .compatible = "socionext,uniphier-ld4-mio-clock", 155102e3187SMasahiro Yamada .data = (ulong)&uniphier_mio_clk_data, 156102e3187SMasahiro Yamada }, 157102e3187SMasahiro Yamada { 1586dc5b6b1SMasahiro Yamada .compatible = "socionext,uniphier-pro4-mio-clock", 159102e3187SMasahiro Yamada .data = (ulong)&uniphier_mio_clk_data, 160102e3187SMasahiro Yamada }, 161102e3187SMasahiro Yamada { 1626dc5b6b1SMasahiro Yamada .compatible = "socionext,uniphier-sld8-mio-clock", 163102e3187SMasahiro Yamada .data = (ulong)&uniphier_mio_clk_data, 164102e3187SMasahiro Yamada }, 165102e3187SMasahiro Yamada { 1666dc5b6b1SMasahiro Yamada .compatible = "socionext,uniphier-pro5-mio-clock", 167102e3187SMasahiro Yamada .data = (ulong)&uniphier_mio_clk_data, 168102e3187SMasahiro Yamada }, 169102e3187SMasahiro Yamada { 1706dc5b6b1SMasahiro Yamada .compatible = "socionext,uniphier-pxs2-mio-clock", 171102e3187SMasahiro Yamada .data = (ulong)&uniphier_mio_clk_data, 172102e3187SMasahiro Yamada }, 173102e3187SMasahiro Yamada { 1746dc5b6b1SMasahiro Yamada .compatible = "socionext,uniphier-ld11-mio-clock", 175102e3187SMasahiro Yamada .data = (ulong)&uniphier_mio_clk_data, 176102e3187SMasahiro Yamada }, 177102e3187SMasahiro Yamada { 1786dc5b6b1SMasahiro Yamada .compatible = "socionext,uniphier-ld20-mio-clock", 179102e3187SMasahiro Yamada .data = (ulong)&uniphier_mio_clk_data, 180102e3187SMasahiro Yamada }, 181102e3187SMasahiro Yamada { /* sentinel */ } 182102e3187SMasahiro Yamada }; 18348264d9bSMasahiro Yamada 184102e3187SMasahiro Yamada U_BOOT_DRIVER(uniphier_clk) = { 185102e3187SMasahiro Yamada .name = "uniphier-clk", 186102e3187SMasahiro Yamada .id = UCLASS_CLK, 187102e3187SMasahiro Yamada .of_match = uniphier_clk_match, 188102e3187SMasahiro Yamada .probe = uniphier_clk_probe, 189102e3187SMasahiro Yamada .priv_auto_alloc_size = sizeof(struct uniphier_clk_priv), 190102e3187SMasahiro Yamada .ops = &uniphier_clk_ops, 191102e3187SMasahiro Yamada }; 192