/*
* Copyright 2013 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* clock driver for Freescale QorIQ SoCs.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/fsl/guts.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/of.h>
#include <linux/slab.h>
#define PLL_DIV1 0
#define PLL_DIV2 1
#define PLL_DIV3 2
#define PLL_DIV4 3
#define PLATFORM_PLL 0
#define CGA_PLL1 1
#define CGA_PLL2 2
#define CGA_PLL3 3
#define CGA_PLL4 4 /* only on clockgen-1.0, which lacks CGB */
#define CGB_PLL1 4
#define CGB_PLL2 5
struct clockgen_pll_div {
struct clk *clk;
char name[32];
};
struct clockgen_pll {
struct clockgen_pll_div div[4];
};
#define CLKSEL_VALID 1
#define CLKSEL_80PCT 2 /* Only allowed if PLL <= 80% of max cpu freq */
struct clockgen_sourceinfo {
u32 flags; /* CLKSEL_xxx */
int pll; /* CGx_PLLn */
int div; /* PLL_DIVn */
};
#define NUM_MUX_PARENTS 16
struct clockgen_muxinfo {
struct clockgen_sourceinfo clksel[NUM_MUX_PARENTS];
};
#define NUM_HWACCEL 5
#define NUM_CMUX 8
struct clockgen;
/*
* cmux freq must be >= platform pll.
* If not set, cmux freq must be >= platform pll/2
*/
#define CG_CMUX_GE_PLAT 1
#define CG_PLL_8BIT 2 /* PLLCnGSR[CFG] is 8 bits, not 6 */
#define CG_VER3 4 /* version 3 cg: reg layout different */
#define CG_LITTLE_ENDIAN 8
struct clockgen_chipinfo {
const char *compat, *guts_compat;
const struct clockgen_muxinfo *cmux_groups[2];
const struct clockgen_muxinfo *hwaccel[NUM_HWACCEL];
void (*init_periph)(struct clockgen *cg);
int cmux_to_group[NUM_CMUX]; /* -1 terminates if fewer than NUM_CMUX */
u32 pll_mask; /* 1 << n bit set if PLL n is valid */
u32 flags; /* CG_xxx */
};
struct clockgen {
struct device_node *node;
void __iomem *regs;
struct clockgen_chipinfo info; /* mutable copy */
struct clk *sysclk;
struct clockgen_pll pll[6];
struct clk *cmux[NUM_CMUX];
struct clk *hwaccel[NUM_HWACCEL];
struct clk *fman[2];
struct ccsr_guts __iomem *guts;
};
static struct clockgen clockgen;
static void cg_out(struct clockgen *cg, u32 val, u32 __iomem *reg)
{
if (cg->info.flags & CG_LITTLE_ENDIAN)
iowrite32(val, reg);
else
iowrite32be(val, reg);
}
static u32 cg_in(struct clockgen *cg, u32 __iomem *reg)
{
u32 val;
if (cg->info.flags & CG_LITTLE_ENDIAN)
val = ioread32(