/*
* Copyright 2015 Vladimir Zapolskiy <vz@mleia.com>
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/of_address.h>
#include <linux/regmap.h>
#include <dt-bindings/clock/lpc32xx-clock.h>
#undef pr_fmt
#define pr_fmt(fmt) "%s: " fmt, __func__
/* Common bitfield definitions for x397 PLL (lock), USB PLL and HCLK PLL */
#define PLL_CTRL_ENABLE BIT(16)
#define PLL_CTRL_BYPASS BIT(15)
#define PLL_CTRL_DIRECT BIT(14)
#define PLL_CTRL_FEEDBACK BIT(13)
#define PLL_CTRL_POSTDIV (BIT(12)|BIT(11))
#define PLL_CTRL_PREDIV (BIT(10)|BIT(9))
#define PLL_CTRL_FEEDDIV (0xFF << 1)
#define PLL_CTRL_LOCK BIT(0)
/* Clock registers on System Control Block */
#define LPC32XX_CLKPWR_DEBUG_CTRL 0x00
#define LPC32XX_CLKPWR_USB_DIV 0x1C
#define LPC32XX_CLKPWR_HCLKDIV_CTRL 0x40
#define LPC32XX_CLKPWR_PWR_CTRL 0x44
#define LPC32XX_CLKPWR_PLL397_CTRL 0x48
#define LPC32XX_CLKPWR_OSC_CTRL 0x4C
#define LPC32XX_CLKPWR_SYSCLK_CTRL 0x50
#define LPC32XX_CLKPWR_LCDCLK_CTRL 0x54
#define LPC32XX_CLKPWR_HCLKPLL_CTRL 0x58
#define LPC32XX_CLKPWR_ADCCLK_CTRL1 0x60
#define LPC32XX_CLKPWR_USB_CTRL 0x64
#define LPC32XX_CLKPWR_SSP_CTRL 0x78
#define LPC32XX_CLKPWR_I2S_CTRL 0x7C
#define LPC32XX_CLKPWR_MS_CTRL 0x80
#define LPC32XX_CLKPWR_MACCLK_CTRL 0x90
#define LPC32XX_CLKPWR_TEST_CLK_CTRL 0xA4
#define LPC32XX_CLKPWR_I2CCLK_CTRL 0xAC
#define LPC32XX_CLKPWR_KEYCLK_CTRL 0xB0
#define LPC32XX_CLKPWR_ADCCLK_CTRL 0xB4
#define LPC32XX_CLKPWR_PWMCLK_CTRL 0xB8
#define LPC32XX_CLKPWR_TIMCLK_CTRL 0xBC
#define LPC32XX_CLKPWR_TIMCLK_CTRL1 0xC0
#define LPC32XX_CLKPWR_SPI_CTRL 0xC4
#define LPC32XX_CLKPWR_FLASHCLK_CTRL 0xC8
#define LPC32XX_CLKPWR_UART3_CLK_CTRL 0xD0
#define LPC32XX_CLKPWR_UART4_CLK_CTRL 0xD4
#define LPC32XX_CLKPWR_UART5_CLK_CTRL 0xD8
#define LPC32XX_CLKPWR_UART6_CLK_CTRL 0xDC
#define LPC32XX_CLKPWR_IRDA_CLK_CTRL 0xE0
#define LPC32XX_CLKPWR_UART_CLK_CTRL 0xE4
#define LPC32XX_CLKPWR_DMA_CLK_CTRL 0xE8
/* Clock registers on USB controller */
#define LPC32XX_USB_CLK_CTRL 0xF4
#define LPC32XX_USB_CLK_STS 0xF8
static struct regmap_config lpc32xx_scb_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.val_format_endian = REGMAP_ENDIAN_LITTLE,
.max_register = 0x114,
.fast_io = true,
};
static struct regmap *clk_regmap;
static void __iomem *usb_clk_vbase;
enum {
LPC32XX_USB_CLK_OTG = LPC32XX_USB_CLK_HOST + 1,
LPC32XX_USB_CLK_AHB,
LPC32XX_USB_CLK_MAX = LPC32XX_USB_CLK_AHB + 1,
};
enum {
/* Start from the last defined clock in dt bindings */
LPC32XX_CLK_ADC_DIV = LPC32XX_CLK_PERIPH + 1,
LPC32XX_CLK_ADC_RTC,
LPC32XX_CLK_TEST1,
LPC32XX_CLK_TEST2,
/* System clocks, PLL 397x and HCLK PLL clocks */
LPC32XX_CLK_OSC,
LPC32XX_CLK_SYS,
LPC32XX_CLK_PLL397X,
LPC32XX_CLK_HCLK_DIV_PERIPH,
LPC32XX_CLK_HCLK_DIV,
LPC32XX_CLK_HCLK,
LPC32XX_CLK_ARM,
LPC32XX_CLK_ARM_VFP,
/* USB clocks */
LPC32XX_CLK_USB_PLL,
LPC32XX_CLK_USB_DIV,
LPC32XX_CLK_USB,
/* Only one control PWR_CTRL[10] for both muxes */
LPC32XX_CLK_PERIPH_HCLK_MUX,
LPC32XX_CLK_PERIPH_ARM_MUX,
/* Only one control PWR_CTRL[2] for all three muxes */
LPC32XX_CLK_SYSCLK_PERIPH_MUX,
LPC32XX_CLK_SYSCLK_HCLK_MUX,
LPC32XX_CLK_SYSCLK_ARM_MUX,
/* Two clock sources external to the driver */
LPC32XX_CLK_XTAL_32K,
LPC32XX_CLK_XTAL,
/* Renumbered USB clocks, may have a parent from SCB table */
LPC32XX_CLK_USB_OFFSET,
LPC32XX_CLK_USB_I2C = LPC32XX_USB_CLK_I2C + LPC32XX_CLK_USB_OFFSET,
LPC32XX_CLK_USB_DEV = LPC32XX_USB_CLK_DEVICE + LPC32XX_CLK_USB_OFFSET,
LPC32XX_CLK_USB_HOST = LPC32XX_USB_CLK_HOST + LPC32XX_CLK_USB_OFFSET,
LPC32XX_CLK_USB_OTG = LPC32XX_USB_CLK_OTG + LPC32XX_CLK_USB_OFFSET,
LPC32XX_CLK_USB_AHB = LPC32XX_USB_CLK_AHB + LPC32XX_CLK_USB_OFFSET,
/* Stub for composite clocks */
LPC32XX_CLK__NULL,
/* Subclocks of composite clocks, clocks above are for CCF */
LPC32XX_CLK_PWM1_MUX,
LPC32XX_CLK_PWM1_DIV,
LPC32XX_CLK_PWM1_GATE,
LPC32XX_CLK_PWM2_MUX,
LPC32XX_CLK_PWM2_DIV,
LPC32XX_CLK_PWM2_GATE,
LPC32XX_CLK_UART3_MUX,
LPC32XX_CLK_UART3_DIV,
LPC32XX_CLK_UART3_GATE,
LPC32XX_CLK_UART4_MUX,
LPC32XX_CLK_UART4_DIV,
LPC32XX_CLK_UART4_GATE,
LPC32XX_CLK_UART5_MUX,
LPC32XX_CLK_UART5_DIV,
LPC32XX_CLK_UART5_GATE,
LPC32XX_CLK_UART6_MUX,
LPC32XX_CLK_UART6_DIV,
LPC32XX_CLK_UART6_GATE,
LPC32XX_CLK_TEST1_MUX,
LPC32XX_CLK_TEST1_GATE,
LPC32XX_CLK_TEST2_MUX,
LPC32XX_CLK_TEST2_GATE,
LPC32XX_CLK_USB_DIV_DIV,
LPC32XX_CLK_USB_DIV_GATE,
LPC32XX_CLK_SD_DIV,
LPC32XX_CLK_SD_GATE,
LPC32XX_CLK_LCD_DIV,
LPC32XX_CLK_LCD_GATE,
LPC32XX_CLK_HW_MAX,
LPC32XX_CLK_MAX = LPC32XX_CLK_SYSCLK_ARM_MUX + 1,
LPC32XX_CLK_CCF_MAX = LPC32XX_CLK_USB_AHB + 1,
};
static struct clk *clk[LPC32XX_CLK_MAX];
static struct clk_onecell_data clk_data = {
.clks = clk,
.clk_num = LPC32XX_CLK_MAX,
};
static struct clk *usb_clk[LPC32XX_USB_CLK_MAX];
static struct clk_onecell_data usb_clk_data = {
.clks = usb_clk,
.clk_num = LPC32XX_USB_CLK_MAX,
};
#define LPC32XX_CLK_PARENTS_MAX 5
struct clk_proto_t {
const char *name;
const u8 parents[LPC32XX_CLK_PARENTS_MAX];
u8 num_parents;
unsigned long flags;
};
#define CLK_PREFIX(LITERAL) LPC32XX_CLK_ ## LITERAL
#define NUMARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int))
#define LPC32XX_CLK_DEFINE(_idx, _name, _flags, ...) \
[CLK_PREFIX(_idx)] = { \
.name = _name, \
.flags = _flags, \
.parents = { __VA_ARGS__ }, \
.num_parents = NUMARGS(__VA_ARGS__), \
}
static const struct clk_proto_t clk_proto[LPC32XX_CLK_CCF_MAX] __initconst = {
LPC32XX_CLK_DEFINE(XTAL, "xtal", 0x0),
LPC32XX_CLK_DEFINE(XTAL_32K, "xtal_32k", 0x0),
LPC32XX_CLK_DEFINE(RTC, "rtc", 0x0, LPC32XX_CLK_XTAL_32K),
LPC32XX_CLK_DEFINE(OSC, "osc", CLK_IGNORE_UNUSED, LPC32XX_CLK_XTAL),
LPC32XX_CLK_DEFINE(SYS, "
|