1*635e5e73SDaire McNamara // SPDX-License-Identifier: GPL-2.0-only 2*635e5e73SDaire McNamara /* 3*635e5e73SDaire McNamara * Daire McNamara,<daire.mcnamara@microchip.com> 4*635e5e73SDaire McNamara * Copyright (C) 2020 Microchip Technology Inc. All rights reserved. 5*635e5e73SDaire McNamara */ 6*635e5e73SDaire McNamara #include <linux/clk-provider.h> 7*635e5e73SDaire McNamara #include <linux/io.h> 8*635e5e73SDaire McNamara #include <linux/module.h> 9*635e5e73SDaire McNamara #include <linux/platform_device.h> 10*635e5e73SDaire McNamara #include <linux/slab.h> 11*635e5e73SDaire McNamara #include <dt-bindings/clock/microchip,mpfs-clock.h> 12*635e5e73SDaire McNamara 13*635e5e73SDaire McNamara /* address offset of control registers */ 14*635e5e73SDaire McNamara #define REG_CLOCK_CONFIG_CR 0x08u 15*635e5e73SDaire McNamara #define REG_SUBBLK_CLOCK_CR 0x84u 16*635e5e73SDaire McNamara #define REG_SUBBLK_RESET_CR 0x88u 17*635e5e73SDaire McNamara 18*635e5e73SDaire McNamara struct mpfs_clock_data { 19*635e5e73SDaire McNamara void __iomem *base; 20*635e5e73SDaire McNamara struct clk_hw_onecell_data hw_data; 21*635e5e73SDaire McNamara }; 22*635e5e73SDaire McNamara 23*635e5e73SDaire McNamara struct mpfs_cfg_clock { 24*635e5e73SDaire McNamara const struct clk_div_table *table; 25*635e5e73SDaire McNamara unsigned int id; 26*635e5e73SDaire McNamara u8 shift; 27*635e5e73SDaire McNamara u8 width; 28*635e5e73SDaire McNamara }; 29*635e5e73SDaire McNamara 30*635e5e73SDaire McNamara struct mpfs_cfg_hw_clock { 31*635e5e73SDaire McNamara struct mpfs_cfg_clock cfg; 32*635e5e73SDaire McNamara void __iomem *sys_base; 33*635e5e73SDaire McNamara struct clk_hw hw; 34*635e5e73SDaire McNamara struct clk_init_data init; 35*635e5e73SDaire McNamara }; 36*635e5e73SDaire McNamara 37*635e5e73SDaire McNamara #define to_mpfs_cfg_clk(_hw) container_of(_hw, struct mpfs_cfg_hw_clock, hw) 38*635e5e73SDaire McNamara 39*635e5e73SDaire McNamara struct mpfs_periph_clock { 40*635e5e73SDaire McNamara unsigned int id; 41*635e5e73SDaire McNamara u8 shift; 42*635e5e73SDaire McNamara }; 43*635e5e73SDaire McNamara 44*635e5e73SDaire McNamara struct mpfs_periph_hw_clock { 45*635e5e73SDaire McNamara struct mpfs_periph_clock periph; 46*635e5e73SDaire McNamara void __iomem *sys_base; 47*635e5e73SDaire McNamara struct clk_hw hw; 48*635e5e73SDaire McNamara }; 49*635e5e73SDaire McNamara 50*635e5e73SDaire McNamara #define to_mpfs_periph_clk(_hw) container_of(_hw, struct mpfs_periph_hw_clock, hw) 51*635e5e73SDaire McNamara 52*635e5e73SDaire McNamara /* 53*635e5e73SDaire McNamara * mpfs_clk_lock prevents anything else from writing to the 54*635e5e73SDaire McNamara * mpfs clk block while a software locked register is being written. 55*635e5e73SDaire McNamara */ 56*635e5e73SDaire McNamara static DEFINE_SPINLOCK(mpfs_clk_lock); 57*635e5e73SDaire McNamara 58*635e5e73SDaire McNamara static const struct clk_parent_data mpfs_cfg_parent[] = { 59*635e5e73SDaire McNamara { .index = 0 }, 60*635e5e73SDaire McNamara }; 61*635e5e73SDaire McNamara 62*635e5e73SDaire McNamara static const struct clk_div_table mpfs_div_cpu_axi_table[] = { 63*635e5e73SDaire McNamara { 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 }, 64*635e5e73SDaire McNamara { 0, 0 } 65*635e5e73SDaire McNamara }; 66*635e5e73SDaire McNamara 67*635e5e73SDaire McNamara static const struct clk_div_table mpfs_div_ahb_table[] = { 68*635e5e73SDaire McNamara { 1, 2 }, { 2, 4}, { 3, 8 }, 69*635e5e73SDaire McNamara { 0, 0 } 70*635e5e73SDaire McNamara }; 71*635e5e73SDaire McNamara 72*635e5e73SDaire McNamara static unsigned long mpfs_cfg_clk_recalc_rate(struct clk_hw *hw, unsigned long prate) 73*635e5e73SDaire McNamara { 74*635e5e73SDaire McNamara struct mpfs_cfg_hw_clock *cfg_hw = to_mpfs_cfg_clk(hw); 75*635e5e73SDaire McNamara struct mpfs_cfg_clock *cfg = &cfg_hw->cfg; 76*635e5e73SDaire McNamara void __iomem *base_addr = cfg_hw->sys_base; 77*635e5e73SDaire McNamara u32 val; 78*635e5e73SDaire McNamara 79*635e5e73SDaire McNamara val = readl_relaxed(base_addr + REG_CLOCK_CONFIG_CR) >> cfg->shift; 80*635e5e73SDaire McNamara val &= clk_div_mask(cfg->width); 81*635e5e73SDaire McNamara 82*635e5e73SDaire McNamara return prate / (1u << val); 83*635e5e73SDaire McNamara } 84*635e5e73SDaire McNamara 85*635e5e73SDaire McNamara static long mpfs_cfg_clk_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate) 86*635e5e73SDaire McNamara { 87*635e5e73SDaire McNamara struct mpfs_cfg_hw_clock *cfg_hw = to_mpfs_cfg_clk(hw); 88*635e5e73SDaire McNamara struct mpfs_cfg_clock *cfg = &cfg_hw->cfg; 89*635e5e73SDaire McNamara 90*635e5e73SDaire McNamara return divider_round_rate(hw, rate, prate, cfg->table, cfg->width, 0); 91*635e5e73SDaire McNamara } 92*635e5e73SDaire McNamara 93*635e5e73SDaire McNamara static int mpfs_cfg_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long prate) 94*635e5e73SDaire McNamara { 95*635e5e73SDaire McNamara struct mpfs_cfg_hw_clock *cfg_hw = to_mpfs_cfg_clk(hw); 96*635e5e73SDaire McNamara struct mpfs_cfg_clock *cfg = &cfg_hw->cfg; 97*635e5e73SDaire McNamara void __iomem *base_addr = cfg_hw->sys_base; 98*635e5e73SDaire McNamara unsigned long flags; 99*635e5e73SDaire McNamara u32 val; 100*635e5e73SDaire McNamara int divider_setting; 101*635e5e73SDaire McNamara 102*635e5e73SDaire McNamara divider_setting = divider_get_val(rate, prate, cfg->table, cfg->width, 0); 103*635e5e73SDaire McNamara 104*635e5e73SDaire McNamara if (divider_setting < 0) 105*635e5e73SDaire McNamara return divider_setting; 106*635e5e73SDaire McNamara 107*635e5e73SDaire McNamara spin_lock_irqsave(&mpfs_clk_lock, flags); 108*635e5e73SDaire McNamara 109*635e5e73SDaire McNamara val = readl_relaxed(base_addr + REG_CLOCK_CONFIG_CR); 110*635e5e73SDaire McNamara val &= ~(clk_div_mask(cfg->width) << cfg_hw->cfg.shift); 111*635e5e73SDaire McNamara val |= divider_setting << cfg->shift; 112*635e5e73SDaire McNamara writel_relaxed(val, base_addr + REG_CLOCK_CONFIG_CR); 113*635e5e73SDaire McNamara 114*635e5e73SDaire McNamara spin_unlock_irqrestore(&mpfs_clk_lock, flags); 115*635e5e73SDaire McNamara 116*635e5e73SDaire McNamara return 0; 117*635e5e73SDaire McNamara } 118*635e5e73SDaire McNamara 119*635e5e73SDaire McNamara static const struct clk_ops mpfs_clk_cfg_ops = { 120*635e5e73SDaire McNamara .recalc_rate = mpfs_cfg_clk_recalc_rate, 121*635e5e73SDaire McNamara .round_rate = mpfs_cfg_clk_round_rate, 122*635e5e73SDaire McNamara .set_rate = mpfs_cfg_clk_set_rate, 123*635e5e73SDaire McNamara }; 124*635e5e73SDaire McNamara 125*635e5e73SDaire McNamara #define CLK_CFG(_id, _name, _parent, _shift, _width, _table, _flags) { \ 126*635e5e73SDaire McNamara .cfg.id = _id, \ 127*635e5e73SDaire McNamara .cfg.shift = _shift, \ 128*635e5e73SDaire McNamara .cfg.width = _width, \ 129*635e5e73SDaire McNamara .cfg.table = _table, \ 130*635e5e73SDaire McNamara .hw.init = CLK_HW_INIT_PARENTS_DATA(_name, _parent, &mpfs_clk_cfg_ops, \ 131*635e5e73SDaire McNamara _flags), \ 132*635e5e73SDaire McNamara } 133*635e5e73SDaire McNamara 134*635e5e73SDaire McNamara static struct mpfs_cfg_hw_clock mpfs_cfg_clks[] = { 135*635e5e73SDaire McNamara CLK_CFG(CLK_CPU, "clk_cpu", mpfs_cfg_parent, 0, 2, mpfs_div_cpu_axi_table, 0), 136*635e5e73SDaire McNamara CLK_CFG(CLK_AXI, "clk_axi", mpfs_cfg_parent, 2, 2, mpfs_div_cpu_axi_table, 0), 137*635e5e73SDaire McNamara CLK_CFG(CLK_AHB, "clk_ahb", mpfs_cfg_parent, 4, 2, mpfs_div_ahb_table, 0), 138*635e5e73SDaire McNamara }; 139*635e5e73SDaire McNamara 140*635e5e73SDaire McNamara static int mpfs_clk_register_cfg(struct device *dev, struct mpfs_cfg_hw_clock *cfg_hw, 141*635e5e73SDaire McNamara void __iomem *sys_base) 142*635e5e73SDaire McNamara { 143*635e5e73SDaire McNamara cfg_hw->sys_base = sys_base; 144*635e5e73SDaire McNamara 145*635e5e73SDaire McNamara return devm_clk_hw_register(dev, &cfg_hw->hw); 146*635e5e73SDaire McNamara } 147*635e5e73SDaire McNamara 148*635e5e73SDaire McNamara static int mpfs_clk_register_cfgs(struct device *dev, struct mpfs_cfg_hw_clock *cfg_hws, 149*635e5e73SDaire McNamara unsigned int num_clks, struct mpfs_clock_data *data) 150*635e5e73SDaire McNamara { 151*635e5e73SDaire McNamara void __iomem *sys_base = data->base; 152*635e5e73SDaire McNamara unsigned int i, id; 153*635e5e73SDaire McNamara int ret; 154*635e5e73SDaire McNamara 155*635e5e73SDaire McNamara for (i = 0; i < num_clks; i++) { 156*635e5e73SDaire McNamara struct mpfs_cfg_hw_clock *cfg_hw = &cfg_hws[i]; 157*635e5e73SDaire McNamara 158*635e5e73SDaire McNamara ret = mpfs_clk_register_cfg(dev, cfg_hw, sys_base); 159*635e5e73SDaire McNamara if (ret) 160*635e5e73SDaire McNamara return dev_err_probe(dev, ret, "failed to register clock id: %d\n", 161*635e5e73SDaire McNamara cfg_hw->cfg.id); 162*635e5e73SDaire McNamara 163*635e5e73SDaire McNamara id = cfg_hws[i].cfg.id; 164*635e5e73SDaire McNamara data->hw_data.hws[id] = &cfg_hw->hw; 165*635e5e73SDaire McNamara } 166*635e5e73SDaire McNamara 167*635e5e73SDaire McNamara return 0; 168*635e5e73SDaire McNamara } 169*635e5e73SDaire McNamara 170*635e5e73SDaire McNamara static int mpfs_periph_clk_enable(struct clk_hw *hw) 171*635e5e73SDaire McNamara { 172*635e5e73SDaire McNamara struct mpfs_periph_hw_clock *periph_hw = to_mpfs_periph_clk(hw); 173*635e5e73SDaire McNamara struct mpfs_periph_clock *periph = &periph_hw->periph; 174*635e5e73SDaire McNamara void __iomem *base_addr = periph_hw->sys_base; 175*635e5e73SDaire McNamara u32 reg, val; 176*635e5e73SDaire McNamara unsigned long flags; 177*635e5e73SDaire McNamara 178*635e5e73SDaire McNamara spin_lock_irqsave(&mpfs_clk_lock, flags); 179*635e5e73SDaire McNamara 180*635e5e73SDaire McNamara reg = readl_relaxed(base_addr + REG_SUBBLK_RESET_CR); 181*635e5e73SDaire McNamara val = reg & ~(1u << periph->shift); 182*635e5e73SDaire McNamara writel_relaxed(val, base_addr + REG_SUBBLK_RESET_CR); 183*635e5e73SDaire McNamara 184*635e5e73SDaire McNamara reg = readl_relaxed(base_addr + REG_SUBBLK_CLOCK_CR); 185*635e5e73SDaire McNamara val = reg | (1u << periph->shift); 186*635e5e73SDaire McNamara writel_relaxed(val, base_addr + REG_SUBBLK_CLOCK_CR); 187*635e5e73SDaire McNamara 188*635e5e73SDaire McNamara spin_unlock_irqrestore(&mpfs_clk_lock, flags); 189*635e5e73SDaire McNamara 190*635e5e73SDaire McNamara return 0; 191*635e5e73SDaire McNamara } 192*635e5e73SDaire McNamara 193*635e5e73SDaire McNamara static void mpfs_periph_clk_disable(struct clk_hw *hw) 194*635e5e73SDaire McNamara { 195*635e5e73SDaire McNamara struct mpfs_periph_hw_clock *periph_hw = to_mpfs_periph_clk(hw); 196*635e5e73SDaire McNamara struct mpfs_periph_clock *periph = &periph_hw->periph; 197*635e5e73SDaire McNamara void __iomem *base_addr = periph_hw->sys_base; 198*635e5e73SDaire McNamara u32 reg, val; 199*635e5e73SDaire McNamara unsigned long flags; 200*635e5e73SDaire McNamara 201*635e5e73SDaire McNamara spin_lock_irqsave(&mpfs_clk_lock, flags); 202*635e5e73SDaire McNamara 203*635e5e73SDaire McNamara reg = readl_relaxed(base_addr + REG_SUBBLK_RESET_CR); 204*635e5e73SDaire McNamara val = reg | (1u << periph->shift); 205*635e5e73SDaire McNamara writel_relaxed(val, base_addr + REG_SUBBLK_RESET_CR); 206*635e5e73SDaire McNamara 207*635e5e73SDaire McNamara reg = readl_relaxed(base_addr + REG_SUBBLK_CLOCK_CR); 208*635e5e73SDaire McNamara val = reg & ~(1u << periph->shift); 209*635e5e73SDaire McNamara writel_relaxed(val, base_addr + REG_SUBBLK_CLOCK_CR); 210*635e5e73SDaire McNamara 211*635e5e73SDaire McNamara spin_unlock_irqrestore(&mpfs_clk_lock, flags); 212*635e5e73SDaire McNamara } 213*635e5e73SDaire McNamara 214*635e5e73SDaire McNamara static int mpfs_periph_clk_is_enabled(struct clk_hw *hw) 215*635e5e73SDaire McNamara { 216*635e5e73SDaire McNamara struct mpfs_periph_hw_clock *periph_hw = to_mpfs_periph_clk(hw); 217*635e5e73SDaire McNamara struct mpfs_periph_clock *periph = &periph_hw->periph; 218*635e5e73SDaire McNamara void __iomem *base_addr = periph_hw->sys_base; 219*635e5e73SDaire McNamara u32 reg; 220*635e5e73SDaire McNamara 221*635e5e73SDaire McNamara reg = readl_relaxed(base_addr + REG_SUBBLK_RESET_CR); 222*635e5e73SDaire McNamara if ((reg & (1u << periph->shift)) == 0u) { 223*635e5e73SDaire McNamara reg = readl_relaxed(base_addr + REG_SUBBLK_CLOCK_CR); 224*635e5e73SDaire McNamara if (reg & (1u << periph->shift)) 225*635e5e73SDaire McNamara return 1; 226*635e5e73SDaire McNamara } 227*635e5e73SDaire McNamara 228*635e5e73SDaire McNamara return 0; 229*635e5e73SDaire McNamara } 230*635e5e73SDaire McNamara 231*635e5e73SDaire McNamara static const struct clk_ops mpfs_periph_clk_ops = { 232*635e5e73SDaire McNamara .enable = mpfs_periph_clk_enable, 233*635e5e73SDaire McNamara .disable = mpfs_periph_clk_disable, 234*635e5e73SDaire McNamara .is_enabled = mpfs_periph_clk_is_enabled, 235*635e5e73SDaire McNamara }; 236*635e5e73SDaire McNamara 237*635e5e73SDaire McNamara #define CLK_PERIPH(_id, _name, _parent, _shift, _flags) { \ 238*635e5e73SDaire McNamara .periph.id = _id, \ 239*635e5e73SDaire McNamara .periph.shift = _shift, \ 240*635e5e73SDaire McNamara .hw.init = CLK_HW_INIT_HW(_name, _parent, &mpfs_periph_clk_ops, \ 241*635e5e73SDaire McNamara _flags), \ 242*635e5e73SDaire McNamara } 243*635e5e73SDaire McNamara 244*635e5e73SDaire McNamara #define PARENT_CLK(PARENT) (&mpfs_cfg_clks[CLK_##PARENT].hw) 245*635e5e73SDaire McNamara 246*635e5e73SDaire McNamara /* 247*635e5e73SDaire McNamara * Critical clocks: 248*635e5e73SDaire McNamara * - CLK_ENVM: reserved by hart software services (hss) superloop monitor/m mode interrupt 249*635e5e73SDaire McNamara * trap handler 250*635e5e73SDaire McNamara * - CLK_MMUART0: reserved by the hss 251*635e5e73SDaire McNamara * - CLK_DDRC: provides clock to the ddr subsystem 252*635e5e73SDaire McNamara * - CLK_FICx: these provide clocks for sections of the fpga fabric, disabling them would 253*635e5e73SDaire McNamara * cause the fabric to go into reset 254*635e5e73SDaire McNamara */ 255*635e5e73SDaire McNamara 256*635e5e73SDaire McNamara static struct mpfs_periph_hw_clock mpfs_periph_clks[] = { 257*635e5e73SDaire McNamara CLK_PERIPH(CLK_ENVM, "clk_periph_envm", PARENT_CLK(AHB), 0, CLK_IS_CRITICAL), 258*635e5e73SDaire McNamara CLK_PERIPH(CLK_MAC0, "clk_periph_mac0", PARENT_CLK(AHB), 1, 0), 259*635e5e73SDaire McNamara CLK_PERIPH(CLK_MAC1, "clk_periph_mac1", PARENT_CLK(AHB), 2, 0), 260*635e5e73SDaire McNamara CLK_PERIPH(CLK_MMC, "clk_periph_mmc", PARENT_CLK(AHB), 3, 0), 261*635e5e73SDaire McNamara CLK_PERIPH(CLK_TIMER, "clk_periph_timer", PARENT_CLK(AHB), 4, 0), 262*635e5e73SDaire McNamara CLK_PERIPH(CLK_MMUART0, "clk_periph_mmuart0", PARENT_CLK(AHB), 5, CLK_IS_CRITICAL), 263*635e5e73SDaire McNamara CLK_PERIPH(CLK_MMUART1, "clk_periph_mmuart1", PARENT_CLK(AHB), 6, 0), 264*635e5e73SDaire McNamara CLK_PERIPH(CLK_MMUART2, "clk_periph_mmuart2", PARENT_CLK(AHB), 7, 0), 265*635e5e73SDaire McNamara CLK_PERIPH(CLK_MMUART3, "clk_periph_mmuart3", PARENT_CLK(AHB), 8, 0), 266*635e5e73SDaire McNamara CLK_PERIPH(CLK_MMUART4, "clk_periph_mmuart4", PARENT_CLK(AHB), 9, 0), 267*635e5e73SDaire McNamara CLK_PERIPH(CLK_SPI0, "clk_periph_spi0", PARENT_CLK(AHB), 10, 0), 268*635e5e73SDaire McNamara CLK_PERIPH(CLK_SPI1, "clk_periph_spi1", PARENT_CLK(AHB), 11, 0), 269*635e5e73SDaire McNamara CLK_PERIPH(CLK_I2C0, "clk_periph_i2c0", PARENT_CLK(AHB), 12, 0), 270*635e5e73SDaire McNamara CLK_PERIPH(CLK_I2C1, "clk_periph_i2c1", PARENT_CLK(AHB), 13, 0), 271*635e5e73SDaire McNamara CLK_PERIPH(CLK_CAN0, "clk_periph_can0", PARENT_CLK(AHB), 14, 0), 272*635e5e73SDaire McNamara CLK_PERIPH(CLK_CAN1, "clk_periph_can1", PARENT_CLK(AHB), 15, 0), 273*635e5e73SDaire McNamara CLK_PERIPH(CLK_USB, "clk_periph_usb", PARENT_CLK(AHB), 16, 0), 274*635e5e73SDaire McNamara CLK_PERIPH(CLK_RTC, "clk_periph_rtc", PARENT_CLK(AHB), 18, 0), 275*635e5e73SDaire McNamara CLK_PERIPH(CLK_QSPI, "clk_periph_qspi", PARENT_CLK(AHB), 19, 0), 276*635e5e73SDaire McNamara CLK_PERIPH(CLK_GPIO0, "clk_periph_gpio0", PARENT_CLK(AHB), 20, 0), 277*635e5e73SDaire McNamara CLK_PERIPH(CLK_GPIO1, "clk_periph_gpio1", PARENT_CLK(AHB), 21, 0), 278*635e5e73SDaire McNamara CLK_PERIPH(CLK_GPIO2, "clk_periph_gpio2", PARENT_CLK(AHB), 22, 0), 279*635e5e73SDaire McNamara CLK_PERIPH(CLK_DDRC, "clk_periph_ddrc", PARENT_CLK(AHB), 23, CLK_IS_CRITICAL), 280*635e5e73SDaire McNamara CLK_PERIPH(CLK_FIC0, "clk_periph_fic0", PARENT_CLK(AHB), 24, CLK_IS_CRITICAL), 281*635e5e73SDaire McNamara CLK_PERIPH(CLK_FIC1, "clk_periph_fic1", PARENT_CLK(AHB), 25, CLK_IS_CRITICAL), 282*635e5e73SDaire McNamara CLK_PERIPH(CLK_FIC2, "clk_periph_fic2", PARENT_CLK(AHB), 26, CLK_IS_CRITICAL), 283*635e5e73SDaire McNamara CLK_PERIPH(CLK_FIC3, "clk_periph_fic3", PARENT_CLK(AHB), 27, CLK_IS_CRITICAL), 284*635e5e73SDaire McNamara CLK_PERIPH(CLK_ATHENA, "clk_periph_athena", PARENT_CLK(AHB), 28, 0), 285*635e5e73SDaire McNamara CLK_PERIPH(CLK_CFM, "clk_periph_cfm", PARENT_CLK(AHB), 29, 0), 286*635e5e73SDaire McNamara }; 287*635e5e73SDaire McNamara 288*635e5e73SDaire McNamara static int mpfs_clk_register_periph(struct device *dev, struct mpfs_periph_hw_clock *periph_hw, 289*635e5e73SDaire McNamara void __iomem *sys_base) 290*635e5e73SDaire McNamara { 291*635e5e73SDaire McNamara periph_hw->sys_base = sys_base; 292*635e5e73SDaire McNamara 293*635e5e73SDaire McNamara return devm_clk_hw_register(dev, &periph_hw->hw); 294*635e5e73SDaire McNamara } 295*635e5e73SDaire McNamara 296*635e5e73SDaire McNamara static int mpfs_clk_register_periphs(struct device *dev, struct mpfs_periph_hw_clock *periph_hws, 297*635e5e73SDaire McNamara int num_clks, struct mpfs_clock_data *data) 298*635e5e73SDaire McNamara { 299*635e5e73SDaire McNamara void __iomem *sys_base = data->base; 300*635e5e73SDaire McNamara unsigned int i, id; 301*635e5e73SDaire McNamara int ret; 302*635e5e73SDaire McNamara 303*635e5e73SDaire McNamara for (i = 0; i < num_clks; i++) { 304*635e5e73SDaire McNamara struct mpfs_periph_hw_clock *periph_hw = &periph_hws[i]; 305*635e5e73SDaire McNamara 306*635e5e73SDaire McNamara ret = mpfs_clk_register_periph(dev, periph_hw, sys_base); 307*635e5e73SDaire McNamara if (ret) 308*635e5e73SDaire McNamara return dev_err_probe(dev, ret, "failed to register clock id: %d\n", 309*635e5e73SDaire McNamara periph_hw->periph.id); 310*635e5e73SDaire McNamara 311*635e5e73SDaire McNamara id = periph_hws[i].periph.id; 312*635e5e73SDaire McNamara data->hw_data.hws[id] = &periph_hw->hw; 313*635e5e73SDaire McNamara } 314*635e5e73SDaire McNamara 315*635e5e73SDaire McNamara return 0; 316*635e5e73SDaire McNamara } 317*635e5e73SDaire McNamara 318*635e5e73SDaire McNamara static int mpfs_clk_probe(struct platform_device *pdev) 319*635e5e73SDaire McNamara { 320*635e5e73SDaire McNamara struct device *dev = &pdev->dev; 321*635e5e73SDaire McNamara struct mpfs_clock_data *clk_data; 322*635e5e73SDaire McNamara unsigned int num_clks; 323*635e5e73SDaire McNamara int ret; 324*635e5e73SDaire McNamara 325*635e5e73SDaire McNamara /* CLK_RESERVED is not part of cfg_clks nor periph_clks, so add 1 */ 326*635e5e73SDaire McNamara num_clks = ARRAY_SIZE(mpfs_cfg_clks) + ARRAY_SIZE(mpfs_periph_clks) + 1; 327*635e5e73SDaire McNamara 328*635e5e73SDaire McNamara clk_data = devm_kzalloc(dev, struct_size(clk_data, hw_data.hws, num_clks), GFP_KERNEL); 329*635e5e73SDaire McNamara if (!clk_data) 330*635e5e73SDaire McNamara return -ENOMEM; 331*635e5e73SDaire McNamara 332*635e5e73SDaire McNamara clk_data->base = devm_platform_ioremap_resource(pdev, 0); 333*635e5e73SDaire McNamara if (IS_ERR(clk_data->base)) 334*635e5e73SDaire McNamara return PTR_ERR(clk_data->base); 335*635e5e73SDaire McNamara 336*635e5e73SDaire McNamara clk_data->hw_data.num = num_clks; 337*635e5e73SDaire McNamara 338*635e5e73SDaire McNamara ret = mpfs_clk_register_cfgs(dev, mpfs_cfg_clks, ARRAY_SIZE(mpfs_cfg_clks), clk_data); 339*635e5e73SDaire McNamara if (ret) 340*635e5e73SDaire McNamara return ret; 341*635e5e73SDaire McNamara 342*635e5e73SDaire McNamara ret = mpfs_clk_register_periphs(dev, mpfs_periph_clks, ARRAY_SIZE(mpfs_periph_clks), 343*635e5e73SDaire McNamara clk_data); 344*635e5e73SDaire McNamara if (ret) 345*635e5e73SDaire McNamara return ret; 346*635e5e73SDaire McNamara 347*635e5e73SDaire McNamara ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, &clk_data->hw_data); 348*635e5e73SDaire McNamara if (ret) 349*635e5e73SDaire McNamara return ret; 350*635e5e73SDaire McNamara 351*635e5e73SDaire McNamara return ret; 352*635e5e73SDaire McNamara } 353*635e5e73SDaire McNamara 354*635e5e73SDaire McNamara static const struct of_device_id mpfs_clk_of_match_table[] = { 355*635e5e73SDaire McNamara { .compatible = "microchip,mpfs-clkcfg", }, 356*635e5e73SDaire McNamara {} 357*635e5e73SDaire McNamara }; 358*635e5e73SDaire McNamara MODULE_DEVICE_TABLE(of, mpfs_clk_match_table); 359*635e5e73SDaire McNamara 360*635e5e73SDaire McNamara static struct platform_driver mpfs_clk_driver = { 361*635e5e73SDaire McNamara .probe = mpfs_clk_probe, 362*635e5e73SDaire McNamara .driver = { 363*635e5e73SDaire McNamara .name = "microchip-mpfs-clkcfg", 364*635e5e73SDaire McNamara .of_match_table = mpfs_clk_of_match_table, 365*635e5e73SDaire McNamara }, 366*635e5e73SDaire McNamara }; 367*635e5e73SDaire McNamara 368*635e5e73SDaire McNamara static int __init clk_mpfs_init(void) 369*635e5e73SDaire McNamara { 370*635e5e73SDaire McNamara return platform_driver_register(&mpfs_clk_driver); 371*635e5e73SDaire McNamara } 372*635e5e73SDaire McNamara core_initcall(clk_mpfs_init); 373*635e5e73SDaire McNamara 374*635e5e73SDaire McNamara static void __exit clk_mpfs_exit(void) 375*635e5e73SDaire McNamara { 376*635e5e73SDaire McNamara platform_driver_unregister(&mpfs_clk_driver); 377*635e5e73SDaire McNamara } 378*635e5e73SDaire McNamara module_exit(clk_mpfs_exit); 379*635e5e73SDaire McNamara 380*635e5e73SDaire McNamara MODULE_DESCRIPTION("Microchip PolarFire SoC Clock Driver"); 381*635e5e73SDaire McNamara MODULE_LICENSE("GPL v2"); 382