Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Clk driver for NXP LPC18xx/LPC43xx Clock Control Unit (CCU)
0004  *
0005  * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
0006  */
0007 
0008 #include <linux/clk.h>
0009 #include <linux/clk-provider.h>
0010 #include <linux/io.h>
0011 #include <linux/kernel.h>
0012 #include <linux/of.h>
0013 #include <linux/of_address.h>
0014 #include <linux/slab.h>
0015 #include <linux/string.h>
0016 
0017 #include <dt-bindings/clock/lpc18xx-ccu.h>
0018 
0019 /* Bit defines for CCU branch configuration register */
0020 #define LPC18XX_CCU_RUN     BIT(0)
0021 #define LPC18XX_CCU_AUTO    BIT(1)
0022 #define LPC18XX_CCU_DIV     BIT(5)
0023 #define LPC18XX_CCU_DIVSTAT BIT(27)
0024 
0025 /* CCU branch feature bits */
0026 #define CCU_BRANCH_IS_BUS   BIT(0)
0027 #define CCU_BRANCH_HAVE_DIV2    BIT(1)
0028 
0029 struct lpc18xx_branch_clk_data {
0030     const char **name;
0031     int num;
0032 };
0033 
0034 struct lpc18xx_clk_branch {
0035     const char *base_name;
0036     const char *name;
0037     u16 offset;
0038     u16 flags;
0039     struct clk *clk;
0040     struct clk_gate gate;
0041 };
0042 
0043 static struct lpc18xx_clk_branch clk_branches[] = {
0044     {"base_apb3_clk", "apb3_bus",       CLK_APB3_BUS,       CCU_BRANCH_IS_BUS},
0045     {"base_apb3_clk", "apb3_i2c1",      CLK_APB3_I2C1,      0},
0046     {"base_apb3_clk", "apb3_dac",       CLK_APB3_DAC,       0},
0047     {"base_apb3_clk", "apb3_adc0",      CLK_APB3_ADC0,      0},
0048     {"base_apb3_clk", "apb3_adc1",      CLK_APB3_ADC1,      0},
0049     {"base_apb3_clk", "apb3_can0",      CLK_APB3_CAN0,      0},
0050 
0051     {"base_apb1_clk", "apb1_bus",       CLK_APB1_BUS,       CCU_BRANCH_IS_BUS},
0052     {"base_apb1_clk", "apb1_mc_pwm",    CLK_APB1_MOTOCON_PWM,   0},
0053     {"base_apb1_clk", "apb1_i2c0",      CLK_APB1_I2C0,      0},
0054     {"base_apb1_clk", "apb1_i2s",       CLK_APB1_I2S,       0},
0055     {"base_apb1_clk", "apb1_can1",      CLK_APB1_CAN1,      0},
0056 
0057     {"base_spifi_clk", "spifi",     CLK_SPIFI,      0},
0058 
0059     {"base_cpu_clk", "cpu_bus",     CLK_CPU_BUS,        CCU_BRANCH_IS_BUS},
0060     {"base_cpu_clk", "cpu_spifi",       CLK_CPU_SPIFI,      0},
0061     {"base_cpu_clk", "cpu_gpio",        CLK_CPU_GPIO,       0},
0062     {"base_cpu_clk", "cpu_lcd",     CLK_CPU_LCD,        0},
0063     {"base_cpu_clk", "cpu_ethernet",    CLK_CPU_ETHERNET,   0},
0064     {"base_cpu_clk", "cpu_usb0",        CLK_CPU_USB0,       0},
0065     {"base_cpu_clk", "cpu_emc",     CLK_CPU_EMC,        0},
0066     {"base_cpu_clk", "cpu_sdio",        CLK_CPU_SDIO,       0},
0067     {"base_cpu_clk", "cpu_dma",     CLK_CPU_DMA,        0},
0068     {"base_cpu_clk", "cpu_core",        CLK_CPU_CORE,       0},
0069     {"base_cpu_clk", "cpu_sct",     CLK_CPU_SCT,        0},
0070     {"base_cpu_clk", "cpu_usb1",        CLK_CPU_USB1,       0},
0071     {"base_cpu_clk", "cpu_emcdiv",      CLK_CPU_EMCDIV,     CCU_BRANCH_HAVE_DIV2},
0072     {"base_cpu_clk", "cpu_flasha",      CLK_CPU_FLASHA,     CCU_BRANCH_HAVE_DIV2},
0073     {"base_cpu_clk", "cpu_flashb",      CLK_CPU_FLASHB,     CCU_BRANCH_HAVE_DIV2},
0074     {"base_cpu_clk", "cpu_m0app",       CLK_CPU_M0APP,      CCU_BRANCH_HAVE_DIV2},
0075     {"base_cpu_clk", "cpu_adchs",       CLK_CPU_ADCHS,      CCU_BRANCH_HAVE_DIV2},
0076     {"base_cpu_clk", "cpu_eeprom",      CLK_CPU_EEPROM,     CCU_BRANCH_HAVE_DIV2},
0077     {"base_cpu_clk", "cpu_wwdt",        CLK_CPU_WWDT,       0},
0078     {"base_cpu_clk", "cpu_uart0",       CLK_CPU_UART0,      0},
0079     {"base_cpu_clk", "cpu_uart1",       CLK_CPU_UART1,      0},
0080     {"base_cpu_clk", "cpu_ssp0",        CLK_CPU_SSP0,       0},
0081     {"base_cpu_clk", "cpu_timer0",      CLK_CPU_TIMER0,     0},
0082     {"base_cpu_clk", "cpu_timer1",      CLK_CPU_TIMER1,     0},
0083     {"base_cpu_clk", "cpu_scu",     CLK_CPU_SCU,        0},
0084     {"base_cpu_clk", "cpu_creg",        CLK_CPU_CREG,       0},
0085     {"base_cpu_clk", "cpu_ritimer",     CLK_CPU_RITIMER,    0},
0086     {"base_cpu_clk", "cpu_uart2",       CLK_CPU_UART2,      0},
0087     {"base_cpu_clk", "cpu_uart3",       CLK_CPU_UART3,      0},
0088     {"base_cpu_clk", "cpu_timer2",      CLK_CPU_TIMER2,     0},
0089     {"base_cpu_clk", "cpu_timer3",      CLK_CPU_TIMER3,     0},
0090     {"base_cpu_clk", "cpu_ssp1",        CLK_CPU_SSP1,       0},
0091     {"base_cpu_clk", "cpu_qei",     CLK_CPU_QEI,        0},
0092 
0093     {"base_periph_clk", "periph_bus",   CLK_PERIPH_BUS,     CCU_BRANCH_IS_BUS},
0094     {"base_periph_clk", "periph_core",  CLK_PERIPH_CORE,    0},
0095     {"base_periph_clk", "periph_sgpio", CLK_PERIPH_SGPIO,   0},
0096 
0097     {"base_usb0_clk",  "usb0",      CLK_USB0,       0},
0098     {"base_usb1_clk",  "usb1",      CLK_USB1,       0},
0099     {"base_spi_clk",   "spi",       CLK_SPI,        0},
0100     {"base_adchs_clk", "adchs",     CLK_ADCHS,      0},
0101 
0102     {"base_audio_clk", "audio",     CLK_AUDIO,      0},
0103     {"base_uart3_clk", "apb2_uart3",    CLK_APB2_UART3,     0},
0104     {"base_uart2_clk", "apb2_uart2",    CLK_APB2_UART2,     0},
0105     {"base_uart1_clk", "apb0_uart1",    CLK_APB0_UART1,     0},
0106     {"base_uart0_clk", "apb0_uart0",    CLK_APB0_UART0,     0},
0107     {"base_ssp1_clk",  "apb2_ssp1",     CLK_APB2_SSP1,      0},
0108     {"base_ssp0_clk",  "apb0_ssp0",     CLK_APB0_SSP0,      0},
0109     {"base_sdio_clk",  "sdio",      CLK_SDIO,       0},
0110 };
0111 
0112 static struct clk *lpc18xx_ccu_branch_clk_get(struct of_phandle_args *clkspec,
0113                           void *data)
0114 {
0115     struct lpc18xx_branch_clk_data *clk_data = data;
0116     unsigned int offset = clkspec->args[0];
0117     int i, j;
0118 
0119     for (i = 0; i < ARRAY_SIZE(clk_branches); i++) {
0120         if (clk_branches[i].offset != offset)
0121             continue;
0122 
0123         for (j = 0; j < clk_data->num; j++) {
0124             if (!strcmp(clk_branches[i].base_name, clk_data->name[j]))
0125                 return clk_branches[i].clk;
0126         }
0127     }
0128 
0129     pr_err("%s: invalid clock offset %d\n", __func__, offset);
0130 
0131     return ERR_PTR(-EINVAL);
0132 }
0133 
0134 static int lpc18xx_ccu_gate_endisable(struct clk_hw *hw, bool enable)
0135 {
0136     struct clk_gate *gate = to_clk_gate(hw);
0137     u32 val;
0138 
0139     /*
0140      * Divider field is write only, so divider stat field must
0141      * be read so divider field can be set accordingly.
0142      */
0143     val = readl(gate->reg);
0144     if (val & LPC18XX_CCU_DIVSTAT)
0145         val |= LPC18XX_CCU_DIV;
0146 
0147     if (enable) {
0148         val |= LPC18XX_CCU_RUN;
0149     } else {
0150         /*
0151          * To safely disable a branch clock a squence of two separate
0152          * writes must be used. First write should set the AUTO bit
0153          * and the next write should clear the RUN bit.
0154          */
0155         val |= LPC18XX_CCU_AUTO;
0156         writel(val, gate->reg);
0157 
0158         val &= ~LPC18XX_CCU_RUN;
0159     }
0160 
0161     writel(val, gate->reg);
0162 
0163     return 0;
0164 }
0165 
0166 static int lpc18xx_ccu_gate_enable(struct clk_hw *hw)
0167 {
0168     return lpc18xx_ccu_gate_endisable(hw, true);
0169 }
0170 
0171 static void lpc18xx_ccu_gate_disable(struct clk_hw *hw)
0172 {
0173     lpc18xx_ccu_gate_endisable(hw, false);
0174 }
0175 
0176 static int lpc18xx_ccu_gate_is_enabled(struct clk_hw *hw)
0177 {
0178     const struct clk_hw *parent;
0179 
0180     /*
0181      * The branch clock registers are only accessible
0182      * if the base (parent) clock is enabled. Register
0183      * access with a disabled base clock will hang the
0184      * system.
0185      */
0186     parent = clk_hw_get_parent(hw);
0187     if (!parent)
0188         return 0;
0189 
0190     if (!clk_hw_is_enabled(parent))
0191         return 0;
0192 
0193     return clk_gate_ops.is_enabled(hw);
0194 }
0195 
0196 static const struct clk_ops lpc18xx_ccu_gate_ops = {
0197     .enable     = lpc18xx_ccu_gate_enable,
0198     .disable    = lpc18xx_ccu_gate_disable,
0199     .is_enabled = lpc18xx_ccu_gate_is_enabled,
0200 };
0201 
0202 static void lpc18xx_ccu_register_branch_gate_div(struct lpc18xx_clk_branch *branch,
0203                          void __iomem *reg_base,
0204                          const char *parent)
0205 {
0206     const struct clk_ops *div_ops = NULL;
0207     struct clk_divider *div = NULL;
0208     struct clk_hw *div_hw = NULL;
0209 
0210     if (branch->flags & CCU_BRANCH_HAVE_DIV2) {
0211         div = kzalloc(sizeof(*div), GFP_KERNEL);
0212         if (!div)
0213             return;
0214 
0215         div->reg = branch->offset + reg_base;
0216         div->flags = CLK_DIVIDER_READ_ONLY;
0217         div->shift = 27;
0218         div->width = 1;
0219 
0220         div_hw = &div->hw;
0221         div_ops = &clk_divider_ro_ops;
0222     }
0223 
0224     branch->gate.reg = branch->offset + reg_base;
0225     branch->gate.bit_idx = 0;
0226 
0227     branch->clk = clk_register_composite(NULL, branch->name, &parent, 1,
0228                          NULL, NULL,
0229                          div_hw, div_ops,
0230                          &branch->gate.hw, &lpc18xx_ccu_gate_ops, 0);
0231     if (IS_ERR(branch->clk)) {
0232         kfree(div);
0233         pr_warn("%s: failed to register %s\n", __func__, branch->name);
0234         return;
0235     }
0236 
0237     /* Grab essential branch clocks for CPU and SDRAM */
0238     switch (branch->offset) {
0239     case CLK_CPU_EMC:
0240     case CLK_CPU_CORE:
0241     case CLK_CPU_CREG:
0242     case CLK_CPU_EMCDIV:
0243         clk_prepare_enable(branch->clk);
0244     }
0245 }
0246 
0247 static void lpc18xx_ccu_register_branch_clks(void __iomem *reg_base,
0248                          const char *base_name)
0249 {
0250     const char *parent = base_name;
0251     int i;
0252 
0253     for (i = 0; i < ARRAY_SIZE(clk_branches); i++) {
0254         if (strcmp(clk_branches[i].base_name, base_name))
0255             continue;
0256 
0257         lpc18xx_ccu_register_branch_gate_div(&clk_branches[i], reg_base,
0258                              parent);
0259 
0260         if (clk_branches[i].flags & CCU_BRANCH_IS_BUS)
0261             parent = clk_branches[i].name;
0262     }
0263 }
0264 
0265 static void __init lpc18xx_ccu_init(struct device_node *np)
0266 {
0267     struct lpc18xx_branch_clk_data *clk_data;
0268     void __iomem *reg_base;
0269     int i, ret;
0270 
0271     reg_base = of_iomap(np, 0);
0272     if (!reg_base) {
0273         pr_warn("%s: failed to map address range\n", __func__);
0274         return;
0275     }
0276 
0277     clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
0278     if (!clk_data) {
0279         iounmap(reg_base);
0280         return;
0281     }
0282 
0283     clk_data->num = of_property_count_strings(np, "clock-names");
0284     clk_data->name = kcalloc(clk_data->num, sizeof(char *), GFP_KERNEL);
0285     if (!clk_data->name) {
0286         iounmap(reg_base);
0287         kfree(clk_data);
0288         return;
0289     }
0290 
0291     for (i = 0; i < clk_data->num; i++) {
0292         ret = of_property_read_string_index(np, "clock-names", i,
0293                             &clk_data->name[i]);
0294         if (ret) {
0295             pr_warn("%s: failed to get clock name at idx %d\n",
0296                 __func__, i);
0297             continue;
0298         }
0299 
0300         lpc18xx_ccu_register_branch_clks(reg_base, clk_data->name[i]);
0301     }
0302 
0303     of_clk_add_provider(np, lpc18xx_ccu_branch_clk_get, clk_data);
0304 }
0305 CLK_OF_DECLARE(lpc18xx_ccu, "nxp,lpc1850-ccu", lpc18xx_ccu_init);