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

Commit fcca3f0f authored by Kuninori Morimoto's avatar Kuninori Morimoto Committed by Rafael J. Wysocki
Browse files

ARM: mach-shmobile: clock-r8a7740: add USB clock



R8A7740 USB needs many clocks for workaround,
and it has confusing name "usb24s" and "usb24".
This "usb24s" will be used by other clocks.

Signed-off-by: default avatarKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Tested-by: default avatarSimon Horman <horms@verge.net.au>
Acked-by: default avatarMagnus Damm <damm@opensource.se>
Signed-off-by: default avatarRafael J. Wysocki <rjw@sisk.pl>
parent 7ee8948d
Loading
Loading
Loading
Loading
+116 −2
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@
#define PLLC01CR	0xe6150028

#define SUBCKCR		0xe6150080
#define USBCKCR		0xe615008c

#define MSTPSR0		0xe6150030
#define MSTPSR1		0xe6150038
@@ -181,6 +182,100 @@ static struct clk pllc1_div2_clk = {
	.parent		= &pllc1_clk,
};

/* USB clock */
static struct clk *usb24s_parents[] = {
	[0] = &system_clk,
	[1] = &extal2_clk
};

static unsigned long usb24s_recalc(struct clk *clk)
{
	return clk->parent->rate;
};

static int usb24s_enable(struct clk *clk)
{
	__raw_writel(__raw_readl(USBCKCR) & ~(1 << 8), USBCKCR);

	return 0;
}

static void usb24s_disable(struct clk *clk)
{
	__raw_writel(__raw_readl(USBCKCR) | (1 << 8), USBCKCR);
}

static int usb24s_set_parent(struct clk *clk, struct clk *parent)
{
	int i, ret;
	u32 val;

	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;

	val = __raw_readl(USBCKCR);
	val &= ~(1 << 7);
	val |= i << 7;
	__raw_writel(val, USBCKCR);

	return 0;
}

static struct sh_clk_ops usb24s_clk_ops = {
	.recalc		= usb24s_recalc,
	.enable		= usb24s_enable,
	.disable	= usb24s_disable,
	.set_parent	= usb24s_set_parent,
};

static struct clk usb24s_clk = {
	.ops		= &usb24s_clk_ops,
	.parent_table	= usb24s_parents,
	.parent_num	= ARRAY_SIZE(usb24s_parents),
	.parent		= &system_clk,
};

static unsigned long usb24_recalc(struct clk *clk)
{
	return clk->parent->rate /
		((__raw_readl(USBCKCR) & (1 << 6)) ? 1 : 2);
};

static int usb24_set_rate(struct clk *clk, unsigned long rate)
{
	u32 val;

	/* closer to which ? parent->rate or parent->rate/2 */
	val = __raw_readl(USBCKCR);
	val &= ~(1 << 6);
	val |= (rate > (clk->parent->rate / 4) * 3) << 6;
	__raw_writel(val, USBCKCR);

	return 0;
}

static struct sh_clk_ops usb24_clk_ops = {
	.recalc		= usb24_recalc,
	.set_rate	= usb24_set_rate,
};

static struct clk usb24_clk = {
	.ops		= &usb24_clk_ops,
	.parent		= &usb24s_clk,
};

struct clk *main_clks[] = {
	&extalr_clk,
	&extal1_clk,
@@ -196,6 +291,8 @@ struct clk *main_clks[] = {
	&pllc0_clk,
	&pllc1_clk,
	&pllc1_div2_clk,
	&usb24s_clk,
	&usb24_clk,
};

static void div4_kick(struct clk *clk)
@@ -223,7 +320,7 @@ static struct clk_div4_table div4_table = {

enum {
	DIV4_I, DIV4_ZG, DIV4_B, DIV4_M1, DIV4_HP,
	DIV4_HPP, DIV4_S, DIV4_ZB, DIV4_M3, DIV4_CP,
	DIV4_HPP, DIV4_USBP, DIV4_S, DIV4_ZB, DIV4_M3, DIV4_CP,
	DIV4_NR
};

@@ -234,6 +331,7 @@ struct clk div4_clks[DIV4_NR] = {
	[DIV4_M1]	= SH_CLK_DIV4(&pllc1_clk, FRQCRA,  4, 0x6fff, CLK_ENABLE_ON_INIT),
	[DIV4_HP]	= SH_CLK_DIV4(&pllc1_clk, FRQCRB,  4, 0x6fff, 0),
	[DIV4_HPP]	= SH_CLK_DIV4(&pllc1_clk, FRQCRC, 20, 0x6fff, 0),
	[DIV4_USBP]	= SH_CLK_DIV4(&pllc1_clk, FRQCRC, 16, 0x6fff, 0),
	[DIV4_S]	= SH_CLK_DIV4(&pllc1_clk, FRQCRC, 12, 0x6fff, 0),
	[DIV4_ZB]	= SH_CLK_DIV4(&pllc1_clk, FRQCRC,  8, 0x6fff, 0),
	[DIV4_M3]	= SH_CLK_DIV4(&pllc1_clk, FRQCRC,  4, 0x6fff, 0),
@@ -257,7 +355,9 @@ enum {
	MSTP222,
	MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,

	MSTP329, MSTP328, MSTP323,
	MSTP329, MSTP328, MSTP323, MSTP320,

	MSTP416, MSTP407, MSTP406,

	MSTP_NR
};
@@ -282,6 +382,11 @@ static struct clk mstp_clks[MSTP_NR] = {
	[MSTP329] = SH_CLK_MSTP32(&r_clk,		SMSTPCR3, 29, 0), /* CMT10 */
	[MSTP328] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],	SMSTPCR3, 28, 0), /* FSI */
	[MSTP323] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB],	SMSTPCR3, 23, 0), /* IIC1 */
	[MSTP320] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],	SMSTPCR3, 20, 0), /* USBF */

	[MSTP416] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],	SMSTPCR4, 16, 0), /* USBHOST */
	[MSTP407] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],	SMSTPCR4,  7, 0), /* USB-Func */
	[MSTP406] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],	SMSTPCR4,  6, 0), /* USB Phy */
};

static struct clk_lookup lookups[] = {
@@ -300,6 +405,7 @@ static struct clk_lookup lookups[] = {
	CLKDEV_CON_ID("pllc0_clk",		&pllc0_clk),
	CLKDEV_CON_ID("pllc1_clk",		&pllc1_clk),
	CLKDEV_CON_ID("pllc1_div2_clk",		&pllc1_div2_clk),
	CLKDEV_CON_ID("usb24s",			&usb24s_clk),

	/* DIV4 clocks */
	CLKDEV_CON_ID("i_clk",			&div4_clks[DIV4_I]),
@@ -337,6 +443,14 @@ static struct clk_lookup lookups[] = {
	CLKDEV_DEV_ID("sh_cmt.10",		&mstp_clks[MSTP329]),
	CLKDEV_DEV_ID("sh_fsi2",		&mstp_clks[MSTP328]),
	CLKDEV_DEV_ID("i2c-sh_mobile.1",	&mstp_clks[MSTP323]),
	CLKDEV_DEV_ID("renesas_usbhs",		&mstp_clks[MSTP320]),

	/* ICK */
	CLKDEV_ICK_ID("host",	"renesas_usbhs",	&mstp_clks[MSTP416]),
	CLKDEV_ICK_ID("func",	"renesas_usbhs",	&mstp_clks[MSTP407]),
	CLKDEV_ICK_ID("phy",	"renesas_usbhs",	&mstp_clks[MSTP406]),
	CLKDEV_ICK_ID("pci",	"renesas_usbhs",	&div4_clks[DIV4_USBP]),
	CLKDEV_ICK_ID("usb24",	"renesas_usbhs",	&usb24_clk),
};

void __init r8a7740_clock_init(u8 md_ck)