^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * Clk driver for NXP LPC18xx/LPC43xx Clock Control Unit (CCU)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * This file is licensed under the terms of the GNU General Public
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * License version 2. This program is licensed "as is" without any
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * warranty of any kind, whether express or implied.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/clk-provider.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <dt-bindings/clock/lpc18xx-ccu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) /* Bit defines for CCU branch configuration register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define LPC18XX_CCU_RUN BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define LPC18XX_CCU_AUTO BIT(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define LPC18XX_CCU_DIV BIT(5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define LPC18XX_CCU_DIVSTAT BIT(27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) /* CCU branch feature bits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define CCU_BRANCH_IS_BUS BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define CCU_BRANCH_HAVE_DIV2 BIT(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) struct lpc18xx_branch_clk_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) const char **name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) int num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) struct lpc18xx_clk_branch {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) const char *base_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) const char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) u16 offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) u16 flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) struct clk *clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) struct clk_gate gate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) static struct lpc18xx_clk_branch clk_branches[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) {"base_apb3_clk", "apb3_bus", CLK_APB3_BUS, CCU_BRANCH_IS_BUS},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) {"base_apb3_clk", "apb3_i2c1", CLK_APB3_I2C1, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) {"base_apb3_clk", "apb3_dac", CLK_APB3_DAC, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) {"base_apb3_clk", "apb3_adc0", CLK_APB3_ADC0, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) {"base_apb3_clk", "apb3_adc1", CLK_APB3_ADC1, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) {"base_apb3_clk", "apb3_can0", CLK_APB3_CAN0, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) {"base_apb1_clk", "apb1_bus", CLK_APB1_BUS, CCU_BRANCH_IS_BUS},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) {"base_apb1_clk", "apb1_mc_pwm", CLK_APB1_MOTOCON_PWM, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) {"base_apb1_clk", "apb1_i2c0", CLK_APB1_I2C0, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) {"base_apb1_clk", "apb1_i2s", CLK_APB1_I2S, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) {"base_apb1_clk", "apb1_can1", CLK_APB1_CAN1, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) {"base_spifi_clk", "spifi", CLK_SPIFI, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) {"base_cpu_clk", "cpu_bus", CLK_CPU_BUS, CCU_BRANCH_IS_BUS},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) {"base_cpu_clk", "cpu_spifi", CLK_CPU_SPIFI, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) {"base_cpu_clk", "cpu_gpio", CLK_CPU_GPIO, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) {"base_cpu_clk", "cpu_lcd", CLK_CPU_LCD, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) {"base_cpu_clk", "cpu_ethernet", CLK_CPU_ETHERNET, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) {"base_cpu_clk", "cpu_usb0", CLK_CPU_USB0, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) {"base_cpu_clk", "cpu_emc", CLK_CPU_EMC, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) {"base_cpu_clk", "cpu_sdio", CLK_CPU_SDIO, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) {"base_cpu_clk", "cpu_dma", CLK_CPU_DMA, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) {"base_cpu_clk", "cpu_core", CLK_CPU_CORE, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) {"base_cpu_clk", "cpu_sct", CLK_CPU_SCT, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) {"base_cpu_clk", "cpu_usb1", CLK_CPU_USB1, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) {"base_cpu_clk", "cpu_emcdiv", CLK_CPU_EMCDIV, CCU_BRANCH_HAVE_DIV2},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {"base_cpu_clk", "cpu_flasha", CLK_CPU_FLASHA, CCU_BRANCH_HAVE_DIV2},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) {"base_cpu_clk", "cpu_flashb", CLK_CPU_FLASHB, CCU_BRANCH_HAVE_DIV2},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) {"base_cpu_clk", "cpu_m0app", CLK_CPU_M0APP, CCU_BRANCH_HAVE_DIV2},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) {"base_cpu_clk", "cpu_adchs", CLK_CPU_ADCHS, CCU_BRANCH_HAVE_DIV2},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) {"base_cpu_clk", "cpu_eeprom", CLK_CPU_EEPROM, CCU_BRANCH_HAVE_DIV2},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) {"base_cpu_clk", "cpu_wwdt", CLK_CPU_WWDT, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) {"base_cpu_clk", "cpu_uart0", CLK_CPU_UART0, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) {"base_cpu_clk", "cpu_uart1", CLK_CPU_UART1, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) {"base_cpu_clk", "cpu_ssp0", CLK_CPU_SSP0, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) {"base_cpu_clk", "cpu_timer0", CLK_CPU_TIMER0, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) {"base_cpu_clk", "cpu_timer1", CLK_CPU_TIMER1, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) {"base_cpu_clk", "cpu_scu", CLK_CPU_SCU, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) {"base_cpu_clk", "cpu_creg", CLK_CPU_CREG, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) {"base_cpu_clk", "cpu_ritimer", CLK_CPU_RITIMER, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) {"base_cpu_clk", "cpu_uart2", CLK_CPU_UART2, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) {"base_cpu_clk", "cpu_uart3", CLK_CPU_UART3, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) {"base_cpu_clk", "cpu_timer2", CLK_CPU_TIMER2, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) {"base_cpu_clk", "cpu_timer3", CLK_CPU_TIMER3, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) {"base_cpu_clk", "cpu_ssp1", CLK_CPU_SSP1, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) {"base_cpu_clk", "cpu_qei", CLK_CPU_QEI, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) {"base_periph_clk", "periph_bus", CLK_PERIPH_BUS, CCU_BRANCH_IS_BUS},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) {"base_periph_clk", "periph_core", CLK_PERIPH_CORE, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) {"base_periph_clk", "periph_sgpio", CLK_PERIPH_SGPIO, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) {"base_usb0_clk", "usb0", CLK_USB0, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) {"base_usb1_clk", "usb1", CLK_USB1, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) {"base_spi_clk", "spi", CLK_SPI, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) {"base_adchs_clk", "adchs", CLK_ADCHS, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) {"base_audio_clk", "audio", CLK_AUDIO, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) {"base_uart3_clk", "apb2_uart3", CLK_APB2_UART3, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) {"base_uart2_clk", "apb2_uart2", CLK_APB2_UART2, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) {"base_uart1_clk", "apb0_uart1", CLK_APB0_UART1, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) {"base_uart0_clk", "apb0_uart0", CLK_APB0_UART0, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) {"base_ssp1_clk", "apb2_ssp1", CLK_APB2_SSP1, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) {"base_ssp0_clk", "apb0_ssp0", CLK_APB0_SSP0, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) {"base_sdio_clk", "sdio", CLK_SDIO, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) static struct clk *lpc18xx_ccu_branch_clk_get(struct of_phandle_args *clkspec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) struct lpc18xx_branch_clk_data *clk_data = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) unsigned int offset = clkspec->args[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) int i, j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) for (i = 0; i < ARRAY_SIZE(clk_branches); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) if (clk_branches[i].offset != offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) for (j = 0; j < clk_data->num; j++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) if (!strcmp(clk_branches[i].base_name, clk_data->name[j]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) return clk_branches[i].clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) pr_err("%s: invalid clock offset %d\n", __func__, offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) static int lpc18xx_ccu_gate_endisable(struct clk_hw *hw, bool enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) struct clk_gate *gate = to_clk_gate(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) * Divider field is write only, so divider stat field must
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) * be read so divider field can be set accordingly.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) val = readl(gate->reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) if (val & LPC18XX_CCU_DIVSTAT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) val |= LPC18XX_CCU_DIV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (enable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) val |= LPC18XX_CCU_RUN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) * To safely disable a branch clock a squence of two separate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) * writes must be used. First write should set the AUTO bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) * and the next write should clear the RUN bit.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) val |= LPC18XX_CCU_AUTO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) writel(val, gate->reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) val &= ~LPC18XX_CCU_RUN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) writel(val, gate->reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) static int lpc18xx_ccu_gate_enable(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) return lpc18xx_ccu_gate_endisable(hw, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) static void lpc18xx_ccu_gate_disable(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) lpc18xx_ccu_gate_endisable(hw, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) static int lpc18xx_ccu_gate_is_enabled(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) const struct clk_hw *parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) * The branch clock registers are only accessible
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) * if the base (parent) clock is enabled. Register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) * access with a disabled base clock will hang the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) * system.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) parent = clk_hw_get_parent(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) if (!parent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) if (!clk_hw_is_enabled(parent))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) return clk_gate_ops.is_enabled(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) static const struct clk_ops lpc18xx_ccu_gate_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) .enable = lpc18xx_ccu_gate_enable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) .disable = lpc18xx_ccu_gate_disable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) .is_enabled = lpc18xx_ccu_gate_is_enabled,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) static void lpc18xx_ccu_register_branch_gate_div(struct lpc18xx_clk_branch *branch,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) void __iomem *reg_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) const char *parent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) const struct clk_ops *div_ops = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) struct clk_divider *div = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) struct clk_hw *div_hw = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) if (branch->flags & CCU_BRANCH_HAVE_DIV2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) div = kzalloc(sizeof(*div), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) if (!div)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) div->reg = branch->offset + reg_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) div->flags = CLK_DIVIDER_READ_ONLY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) div->shift = 27;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) div->width = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) div_hw = &div->hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) div_ops = &clk_divider_ro_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) branch->gate.reg = branch->offset + reg_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) branch->gate.bit_idx = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) branch->clk = clk_register_composite(NULL, branch->name, &parent, 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) NULL, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) div_hw, div_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) &branch->gate.hw, &lpc18xx_ccu_gate_ops, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) if (IS_ERR(branch->clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) kfree(div);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) pr_warn("%s: failed to register %s\n", __func__, branch->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) /* Grab essential branch clocks for CPU and SDRAM */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) switch (branch->offset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) case CLK_CPU_EMC:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) case CLK_CPU_CORE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) case CLK_CPU_CREG:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) case CLK_CPU_EMCDIV:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) clk_prepare_enable(branch->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) static void lpc18xx_ccu_register_branch_clks(void __iomem *reg_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) const char *base_name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) const char *parent = base_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) for (i = 0; i < ARRAY_SIZE(clk_branches); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) if (strcmp(clk_branches[i].base_name, base_name))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) lpc18xx_ccu_register_branch_gate_div(&clk_branches[i], reg_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) if (clk_branches[i].flags & CCU_BRANCH_IS_BUS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) parent = clk_branches[i].name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) static void __init lpc18xx_ccu_init(struct device_node *np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) struct lpc18xx_branch_clk_data *clk_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) void __iomem *reg_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) int i, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) reg_base = of_iomap(np, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) if (!reg_base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) pr_warn("%s: failed to map address range\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) if (!clk_data) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) iounmap(reg_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) clk_data->num = of_property_count_strings(np, "clock-names");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) clk_data->name = kcalloc(clk_data->num, sizeof(char *), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) if (!clk_data->name) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) iounmap(reg_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) kfree(clk_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) for (i = 0; i < clk_data->num; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) ret = of_property_read_string_index(np, "clock-names", i,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) &clk_data->name[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) pr_warn("%s: failed to get clock name at idx %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) __func__, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) lpc18xx_ccu_register_branch_clks(reg_base, clk_data->name[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) of_clk_add_provider(np, lpc18xx_ccu_branch_clk_get, clk_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) CLK_OF_DECLARE(lpc18xx_ccu, "nxp,lpc1850-ccu", lpc18xx_ccu_init);