Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b90884c8 authored by Guennadi Liakhovetski's avatar Guennadi Liakhovetski Committed by Paul Mundt
Browse files

ARM: mach-shmobile: extend clock definitions on sh7372



Add definitions for DV_CLKI and HDMI clocks, extend support for PLLC2 and some
other clocks.

Signed-off-by: default avatarGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Acked-by: default avatarMagnus Damm <damm@opensource.se>
Signed-off-by: default avatarPaul Mundt <lethal@linux-sh.org>
parent b3dd51a8
Loading
Loading
Loading
Loading
+166 −5
Original line number Original line Diff line number Diff line
@@ -50,6 +50,10 @@
#define SMSTPCR3	0xe615013c
#define SMSTPCR3	0xe615013c
#define SMSTPCR4	0xe6150140
#define SMSTPCR4	0xe6150140


/* Platforms must set frequency on their DV_CLKI pin */
struct clk dv_clki_clk = {
};

/* Fixed 32 KHz root clock from EXTALR pin */
/* Fixed 32 KHz root clock from EXTALR pin */
static struct clk r_clk = {
static struct clk r_clk = {
	.rate           = 32768,
	.rate           = 32768,
@@ -81,6 +85,12 @@ static struct clk_ops div2_clk_ops = {
	.recalc		= div2_recalc,
	.recalc		= div2_recalc,
};
};


/* Divide dv_clki by two */
struct clk dv_clki_div2_clk = {
	.ops		= &div2_clk_ops,
	.parent		= &dv_clki_clk,
};

/* Divide extal1 by two */
/* Divide extal1 by two */
static struct clk extal1_div2_clk = {
static struct clk extal1_div2_clk = {
	.ops		= &div2_clk_ops,
	.ops		= &div2_clk_ops,
@@ -135,30 +145,160 @@ static struct clk pllc1_div2_clk = {
};
};


/* PLLC2 */
/* PLLC2 */

/* Indices are important - they are the actual src selecting values */
static struct clk *pllc2_parent[] = {
	[0] = &extal1_div2_clk,
	[1] = &extal2_div2_clk,
	[2] = &dv_clki_div2_clk,
};

/* Only multipliers 20 * 2 to 46 * 2 are valid, last entry for CPUFREQ_TABLE_END */
static struct cpufreq_frequency_table pllc2_freq_table[29];

static void pllc2_table_rebuild(struct clk *clk)
{
	int i;

	/* Initialise PLLC2 frequency table */
	for (i = 0; i < ARRAY_SIZE(pllc2_freq_table) - 2; i++) {
		pllc2_freq_table[i].frequency = clk->parent->rate * (i + 20) * 2;
		pllc2_freq_table[i].index = i;
	}

	/* This is a special entry - switching PLL off makes it a repeater */
	pllc2_freq_table[i].frequency = clk->parent->rate;
	pllc2_freq_table[i].index = i;

	pllc2_freq_table[++i].frequency = CPUFREQ_TABLE_END;
	pllc2_freq_table[i].index = i;
}

static unsigned long pllc2_recalc(struct clk *clk)
static unsigned long pllc2_recalc(struct clk *clk)
{
{
	unsigned long mult = 1;
	unsigned long mult = 1;


	pllc2_table_rebuild(clk);

	/*
	 * If the PLL is off, mult == 1, clk->rate will be updated in
	 * pllc2_enable().
	 */
	if (__raw_readl(PLLC2CR) & (1 << 31))
	if (__raw_readl(PLLC2CR) & (1 << 31))
		mult = (((__raw_readl(PLLC2CR) >> 24) & 0x3f) + 1) * 2;
		mult = (((__raw_readl(PLLC2CR) >> 24) & 0x3f) + 1) * 2;


	return clk->parent->rate * mult;
	return clk->parent->rate * mult;
}
}


static long pllc2_round_rate(struct clk *clk, unsigned long rate)
{
	return clk_rate_table_round(clk, clk->freq_table, rate);
}

static int pllc2_enable(struct clk *clk)
{
	int i;

	__raw_writel(__raw_readl(PLLC2CR) | 0x80000000, PLLC2CR);

	for (i = 0; i < 100; i++)
		if (__raw_readl(PLLC2CR) & 0x80000000) {
			clk->rate = pllc2_recalc(clk);
			return 0;
		}

	pr_err("%s(): timeout!\n", __func__);

	return -ETIMEDOUT;
}

static void pllc2_disable(struct clk *clk)
{
	__raw_writel(__raw_readl(PLLC2CR) & ~0x80000000, PLLC2CR);
}

static int pllc2_set_rate(struct clk *clk,
			  unsigned long rate, int algo_id)
{
	unsigned long value;
	int idx;

	idx = clk_rate_table_find(clk, clk->freq_table, rate);
	if (idx < 0)
		return idx;

	if (rate == clk->parent->rate) {
		pllc2_disable(clk);
		return 0;
	}

	value = __raw_readl(PLLC2CR) & ~(0x3f << 24);

	if (value & 0x80000000)
		pllc2_disable(clk);

	__raw_writel((value & ~0x80000000) | ((idx + 19) << 24), PLLC2CR);

	if (value & 0x80000000)
		return pllc2_enable(clk);

	return 0;
}

static int pllc2_set_parent(struct clk *clk, struct clk *parent)
{
	u32 value;
	int ret, i;

	if (!clk->parent_table || !clk->parent_num)
		return -EINVAL;

	/* Search the parent */
	for (i = 0; i < clk->parent_num; i++)
		if (clk->parent_table[i] == parent)
			break;

	if (i == clk->parent_num)
		return -ENODEV;

	ret = clk_reparent(clk, parent);
	if (ret < 0)
		return ret;

	value = __raw_readl(PLLC2CR) & ~(3 << 6);

	__raw_writel(value | (i << 6), PLLC2CR);

	/* Rebiuld the frequency table */
	pllc2_table_rebuild(clk);

	return 0;
}

static struct clk_ops pllc2_clk_ops = {
static struct clk_ops pllc2_clk_ops = {
	.recalc		= pllc2_recalc,
	.recalc		= pllc2_recalc,
	.round_rate	= pllc2_round_rate,
	.set_rate	= pllc2_set_rate,
	.enable		= pllc2_enable,
	.disable	= pllc2_disable,
	.set_parent	= pllc2_set_parent,
};
};


static struct clk pllc2_clk = {
struct clk pllc2_clk = {
	.ops		= &pllc2_clk_ops,
	.ops		= &pllc2_clk_ops,
	.flags		= CLK_ENABLE_ON_INIT,
	.flags		= CLK_ENABLE_ON_INIT,
	.parent		= &extal1_div2_clk,
	.parent		= &extal1_div2_clk,
	.freq_table	= pllc2_freq_table,
	.parent_table	= pllc2_parent,
	.parent_num	= ARRAY_SIZE(pllc2_parent),
};
};


static struct clk *main_clks[] = {
static struct clk *main_clks[] = {
	&dv_clki_clk,
	&r_clk,
	&r_clk,
	&sh7372_extal1_clk,
	&sh7372_extal1_clk,
	&sh7372_extal2_clk,
	&sh7372_extal2_clk,
	&dv_clki_div2_clk,
	&extal1_div2_clk,
	&extal1_div2_clk,
	&extal2_div2_clk,
	&extal2_div2_clk,
	&extal2_div4_clk,
	&extal2_div4_clk,
@@ -219,7 +359,7 @@ static struct clk div4_clks[DIV4_NR] = {


enum { DIV6_VCK1, DIV6_VCK2, DIV6_VCK3, DIV6_FMSI, DIV6_FMSO,
enum { DIV6_VCK1, DIV6_VCK2, DIV6_VCK3, DIV6_FMSI, DIV6_FMSO,
       DIV6_FSIA, DIV6_FSIB, DIV6_SUB, DIV6_SPU,
       DIV6_FSIA, DIV6_FSIB, DIV6_SUB, DIV6_SPU,
       DIV6_VOU, DIV6_HDMI, DIV6_DSIT, DIV6_DSI0P, DIV6_DSI1P,
       DIV6_VOU, DIV6_DSIT, DIV6_DSI0P, DIV6_DSI1P,
       DIV6_NR };
       DIV6_NR };


static struct clk div6_clks[DIV6_NR] = {
static struct clk div6_clks[DIV6_NR] = {
@@ -233,12 +373,26 @@ static struct clk div6_clks[DIV6_NR] = {
	[DIV6_SUB] = SH_CLK_DIV6(&sh7372_extal2_clk, SUBCKCR, 0),
	[DIV6_SUB] = SH_CLK_DIV6(&sh7372_extal2_clk, SUBCKCR, 0),
	[DIV6_SPU] = SH_CLK_DIV6(&pllc1_div2_clk, SPUCKCR, 0),
	[DIV6_SPU] = SH_CLK_DIV6(&pllc1_div2_clk, SPUCKCR, 0),
	[DIV6_VOU] = SH_CLK_DIV6(&pllc1_div2_clk, VOUCKCR, 0),
	[DIV6_VOU] = SH_CLK_DIV6(&pllc1_div2_clk, VOUCKCR, 0),
	[DIV6_HDMI] = SH_CLK_DIV6(&pllc1_div2_clk, HDMICKCR, 0),
	[DIV6_DSIT] = SH_CLK_DIV6(&pllc1_div2_clk, DSITCKCR, 0),
	[DIV6_DSIT] = SH_CLK_DIV6(&pllc1_div2_clk, DSITCKCR, 0),
	[DIV6_DSI0P] = SH_CLK_DIV6(&pllc1_div2_clk, DSI0PCKCR, 0),
	[DIV6_DSI0P] = SH_CLK_DIV6(&pllc1_div2_clk, DSI0PCKCR, 0),
	[DIV6_DSI1P] = SH_CLK_DIV6(&pllc1_div2_clk, DSI1PCKCR, 0),
	[DIV6_DSI1P] = SH_CLK_DIV6(&pllc1_div2_clk, DSI1PCKCR, 0),
};
};


enum { DIV6_HDMI, DIV6_REPARENT_NR };

/* Indices are important - they are the actual src selecting values */
static struct clk *hdmi_parent[] = {
	[0] = &pllc1_div2_clk,
	[1] = &pllc2_clk,
	[2] = &dv_clki_clk,
	[3] = NULL,	/* pllc2_div4 not implemented yet */
};

static struct clk div6_reparent_clks[DIV6_REPARENT_NR] = {
	[DIV6_HDMI] = SH_CLK_DIV6_EXT(&pllc1_div2_clk, HDMICKCR, 0,
				      hdmi_parent, ARRAY_SIZE(hdmi_parent), 6, 2),
};

enum { MSTP001,
enum { MSTP001,
       MSTP131, MSTP130,
       MSTP131, MSTP130,
       MSTP129, MSTP128,
       MSTP129, MSTP128,
@@ -247,7 +401,7 @@ enum { MSTP001,
       MSTP223,
       MSTP223,
       MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
       MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
       MSTP329, MSTP328, MSTP323, MSTP322, MSTP314, MSTP313, MSTP312,
       MSTP329, MSTP328, MSTP323, MSTP322, MSTP314, MSTP313, MSTP312,
       MSTP415, MSTP410, MSTP411, MSTP406, MSTP403,
       MSTP415, MSTP413, MSTP411, MSTP410, MSTP406, MSTP403,
       MSTP_NR };
       MSTP_NR };


#define MSTP(_parent, _reg, _bit, _flags) \
#define MSTP(_parent, _reg, _bit, _flags) \
@@ -281,6 +435,7 @@ static struct clk mstp_clks[MSTP_NR] = {
	[MSTP313] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 13, 0), /* SDHI1 */
	[MSTP313] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 13, 0), /* SDHI1 */
	[MSTP312] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 12, 0), /* MMC */
	[MSTP312] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 12, 0), /* MMC */
	[MSTP415] = MSTP(&div4_clks[DIV4_HP], SMSTPCR4, 15, 0), /* SDHI2 */
	[MSTP415] = MSTP(&div4_clks[DIV4_HP], SMSTPCR4, 15, 0), /* SDHI2 */
	[MSTP413] = MSTP(&pllc1_div2_clk, SMSTPCR4, 13, 0), /* HDMI */
	[MSTP411] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 11, 0), /* IIC3 */
	[MSTP411] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 11, 0), /* IIC3 */
	[MSTP410] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 10, 0), /* IIC4 */
	[MSTP410] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 10, 0), /* IIC4 */
	[MSTP406] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 6, 0), /* USB1 */
	[MSTP406] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 6, 0), /* USB1 */
@@ -292,6 +447,7 @@ static struct clk mstp_clks[MSTP_NR] = {


static struct clk_lookup lookups[] = {
static struct clk_lookup lookups[] = {
	/* main clocks */
	/* main clocks */
	CLKDEV_CON_ID("dv_clki_div2_clk", &dv_clki_div2_clk),
	CLKDEV_CON_ID("r_clk", &r_clk),
	CLKDEV_CON_ID("r_clk", &r_clk),
	CLKDEV_CON_ID("extal1", &sh7372_extal1_clk),
	CLKDEV_CON_ID("extal1", &sh7372_extal1_clk),
	CLKDEV_CON_ID("extal2", &sh7372_extal2_clk),
	CLKDEV_CON_ID("extal2", &sh7372_extal2_clk),
@@ -331,7 +487,7 @@ static struct clk_lookup lookups[] = {
	CLKDEV_CON_ID("sub_clk", &div6_clks[DIV6_SUB]),
	CLKDEV_CON_ID("sub_clk", &div6_clks[DIV6_SUB]),
	CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_SPU]),
	CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_SPU]),
	CLKDEV_CON_ID("vou_clk", &div6_clks[DIV6_VOU]),
	CLKDEV_CON_ID("vou_clk", &div6_clks[DIV6_VOU]),
	CLKDEV_CON_ID("hdmi_clk", &div6_clks[DIV6_HDMI]),
	CLKDEV_CON_ID("hdmi_clk", &div6_reparent_clks[DIV6_HDMI]),
	CLKDEV_CON_ID("dsit_clk", &div6_clks[DIV6_DSIT]),
	CLKDEV_CON_ID("dsit_clk", &div6_clks[DIV6_DSIT]),
	CLKDEV_CON_ID("dsi0p_clk", &div6_clks[DIV6_DSI0P]),
	CLKDEV_CON_ID("dsi0p_clk", &div6_clks[DIV6_DSI0P]),
	CLKDEV_CON_ID("dsi1p_clk", &div6_clks[DIV6_DSI1P]),
	CLKDEV_CON_ID("dsi1p_clk", &div6_clks[DIV6_DSI1P]),
@@ -366,11 +522,13 @@ static struct clk_lookup lookups[] = {
	CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */
	CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */
	CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP312]), /* MMC */
	CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP312]), /* MMC */
	CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP415]), /* SDHI2 */
	CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP415]), /* SDHI2 */
	CLKDEV_DEV_ID("sh-mobile-hdmi", &mstp_clks[MSTP413]), /* HDMI */
	CLKDEV_DEV_ID("i2c-sh_mobile.3", &mstp_clks[MSTP411]), /* IIC3 */
	CLKDEV_DEV_ID("i2c-sh_mobile.3", &mstp_clks[MSTP411]), /* IIC3 */
	CLKDEV_DEV_ID("i2c-sh_mobile.4", &mstp_clks[MSTP410]), /* IIC4 */
	CLKDEV_DEV_ID("i2c-sh_mobile.4", &mstp_clks[MSTP410]), /* IIC4 */
	CLKDEV_DEV_ID("r8a66597_hcd.1", &mstp_clks[MSTP406]), /* USB1 */
	CLKDEV_DEV_ID("r8a66597_hcd.1", &mstp_clks[MSTP406]), /* USB1 */
	CLKDEV_DEV_ID("r8a66597_udc.1", &mstp_clks[MSTP406]), /* USB1 */
	CLKDEV_DEV_ID("r8a66597_udc.1", &mstp_clks[MSTP406]), /* USB1 */
	CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */
	CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */
	{.con_id = "ick", .dev_id = "sh-mobile-hdmi", .clk = &div6_reparent_clks[DIV6_HDMI]},
};
};


void __init sh7372_clock_init(void)
void __init sh7372_clock_init(void)
@@ -386,6 +544,9 @@ void __init sh7372_clock_init(void)
	if (!ret)
	if (!ret)
		ret = sh_clk_div6_register(div6_clks, DIV6_NR);
		ret = sh_clk_div6_register(div6_clks, DIV6_NR);


	if (!ret)
		ret = sh_clk_div6_reparent_register(div6_reparent_clks, DIV6_NR);

	if (!ret)
	if (!ret)
		ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
		ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);


+6 −0
Original line number Original line Diff line number Diff line
@@ -11,6 +11,8 @@
#ifndef __ASM_SH7372_H__
#ifndef __ASM_SH7372_H__
#define __ASM_SH7372_H__
#define __ASM_SH7372_H__


#include <linux/sh_clk.h>

/*
/*
 * Pin Function Controller:
 * Pin Function Controller:
 *	GPIO_FN_xx - GPIO used to select pin function
 *	GPIO_FN_xx - GPIO used to select pin function
@@ -455,4 +457,8 @@ enum {
	SHDMA_SLAVE_SDHI2_TX,
	SHDMA_SLAVE_SDHI2_TX,
};
};


extern struct clk dv_clki_clk;
extern struct clk dv_clki_div2_clk;
extern struct clk pllc2_clk;

#endif /* __ASM_SH7372_H__ */
#endif /* __ASM_SH7372_H__ */