All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/10] MIPS: Alchemy: common clk framework support
@ 2014-07-23 14:36 Manuel Lauss
  2014-07-23 14:36 ` [PATCH 01/10] MIPS: Alchemy: clock framework integration of onchip clocks Manuel Lauss
                   ` (9 more replies)
  0 siblings, 10 replies; 11+ messages in thread
From: Manuel Lauss @ 2014-07-23 14:36 UTC (permalink / raw)
  To: Linux-MIPS; +Cc: Manuel Lauss

This set of patches introduces common clk framework support for
on-chip peripherals.

patch #1  adds the core clk support for SoC-internal configurable
	  clk sources,
patches #2-#9 add clk fwk support to various drivers
patch #10 removes the old basic clk support.

Tested on DB1300, DB1200 and DB1500.

Applies on top of the Alchemy cleanup series I sent to the
MIPS list earlier.

Manuel Lauss (10):
  MIPS: Alchemy: clock framework integration of onchip clocks
  MIPS: Alchemy: platform: use clk framework for uarts
  MIPS: Alchemy: usb: use clk framework
  MIPS: Alchemy: pci: use clk framework to enable PCI clock
  MIPS: Alchemy: db1x00: use clk framework
  MIPS: Alchemy: irda: use clk framework
  MIPS: Alchemy: au1100fb: use clk framework
  MIPS: Alchemy: au1200fb: use clk framework
  MIPS: Alchemy: au1xmmc: use clk framework
  MIPS: Alchemy: remove old clock support

 arch/mips/Kconfig                          |    1 +
 arch/mips/alchemy/common/Makefile          |    4 +-
 arch/mips/alchemy/common/clock.c           | 1094 ++++++++++++++++++++++++++++
 arch/mips/alchemy/common/clocks.c          |  105 ---
 arch/mips/alchemy/common/platform.c        |   13 +-
 arch/mips/alchemy/common/setup.c           |   15 -
 arch/mips/alchemy/common/usb.c             |   47 +-
 arch/mips/alchemy/devboards/db1000.c       |   14 +
 arch/mips/alchemy/devboards/db1200.c       |   50 +-
 arch/mips/alchemy/devboards/db1300.c       |    7 +
 arch/mips/alchemy/devboards/db1550.c       |   13 +
 arch/mips/include/asm/mach-au1x00/au1000.h |   87 +--
 arch/mips/pci/pci-alchemy.c                |   24 +-
 drivers/mmc/host/au1xmmc.c                 |   31 +-
 drivers/net/irda/au1k_ir.c                 |   48 +-
 drivers/video/fbdev/au1100fb.c             |   36 +-
 drivers/video/fbdev/au1100fb.h             |    1 +
 drivers/video/fbdev/au1200fb.c             |   50 +-
 18 files changed, 1360 insertions(+), 280 deletions(-)
 create mode 100644 arch/mips/alchemy/common/clock.c
 delete mode 100644 arch/mips/alchemy/common/clocks.c

-- 
2.0.1

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 01/10] MIPS: Alchemy: clock framework integration of onchip clocks
  2014-07-23 14:36 [PATCH 00/10] MIPS: Alchemy: common clk framework support Manuel Lauss
@ 2014-07-23 14:36 ` Manuel Lauss
  2014-07-23 14:36 ` [PATCH 02/10] MIPS: Alchemy: platform: use clk framework for uarts Manuel Lauss
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Manuel Lauss @ 2014-07-23 14:36 UTC (permalink / raw)
  To: Linux-MIPS; +Cc: Manuel Lauss, Mike Turquette

This patch introduces common clock framework integration for all
configurable on-chip clocks on Alchemy chips:

- 2 or 3 PLLs which generate integer multiples of the root rate 12MHz,
- 6 dividers which take one of the 3 PLLs as input and divide their
  rate by either multiples of 2 or 1 (Au1300).
- another bank of up to 6 muxes which take either one of the 6
  above dividers or one of the PLLs directly and divide their rate
  further by 1, 2, 3 or 4.
- a few other sources which are used by onchip peripherals and are
  informational.

This implementation will take the clock tree as it was set up
by boot firmware: all in-kernel boards should continue to work
without having to set up the clock tree in board code.

CLK_IGNORE_DISABLED will be removed once all drivers have been
converted.

Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
Cc: Mike Turquette <mturquette@linaro.org>
---
 arch/mips/Kconfig                          |    1 +
 arch/mips/alchemy/common/Makefile          |    4 +-
 arch/mips/alchemy/common/clock.c           | 1096 ++++++++++++++++++++++++++++
 arch/mips/include/asm/mach-au1x00/au1000.h |   16 +
 4 files changed, 1115 insertions(+), 2 deletions(-)
 create mode 100644 arch/mips/alchemy/common/clock.c

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 458608d..86e79de 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -72,6 +72,7 @@ config MIPS_ALCHEMY
 	select SYS_SUPPORTS_APM_EMULATION
 	select ARCH_REQUIRE_GPIOLIB
 	select SYS_SUPPORTS_ZBOOT
+	select COMMON_CLK
 
 config AR7
 	bool "Texas Instruments AR7"
diff --git a/arch/mips/alchemy/common/Makefile b/arch/mips/alchemy/common/Makefile
index cb83d8d..c8dedcb 100644
--- a/arch/mips/alchemy/common/Makefile
+++ b/arch/mips/alchemy/common/Makefile
@@ -5,8 +5,8 @@
 # Makefile for the Alchemy Au1xx0 CPUs, generic files.
 #
 
-obj-y += prom.o time.o clocks.o platform.o power.o setup.o \
-	sleeper.o dma.o dbdma.o vss.o irq.o usb.o
+obj-y += prom.o time.o clock.o clocks.o platform.o power.o \
+	 setup.o sleeper.o dma.o dbdma.o vss.o irq.o usb.o
 
 # optional gpiolib support
 ifeq ($(CONFIG_ALCHEMY_GPIO_INDIRECT),)
diff --git a/arch/mips/alchemy/common/clock.c b/arch/mips/alchemy/common/clock.c
new file mode 100644
index 0000000..3cd4118
--- /dev/null
+++ b/arch/mips/alchemy/common/clock.c
@@ -0,0 +1,1096 @@
+/*
+ * Alchemy clocks.
+ *
+ * Exposes all configurable internal clock sources to the clk framework.
+ *
+ * We have:
+ *  - Root source, usually 12MHz supplied by an external crystal
+ *  - 3 PLLs which generate multiples of root rate [AUX, CPU, AUX2]
+ *
+ * Dividers:
+ *  - 6 clock dividers with:
+ *   * selectable source [one of the PLLs],
+ *   * output divided between [2 .. 512 in steps of 2] (!Au1300)
+ *     or [1 .. 256 in steps of 1] (Au1300),
+ *   * can be enabled individually.
+ *
+ * - up to 6 "internal" (fixed) consumers which:
+ *   * take either AUXPLL or one of the above 6 dividers as input,
+ *   * divide this input by 1, 2, or 4 (and 3 on Au1300).
+ *   * can be disabled separately.
+ *
+ * Misc clocks:
+ * - sysbus clock: CPU core clock (CPUPLL) divided by 2, 3 or 4.
+ *    depends on board design and should be set by bootloader, read-only.
+ * - peripheral clock: half the rate of sysbus clock, source for a lot
+ *    of peripheral blocks, read-only.
+ * - memory clock: clk rate to main memory chips, depends on board
+ *    design and is read-only,
+ * - lrclk: the static bus clock signal for synchronous operation.
+ *    depends on board design, must be set by bootloader,
+ *    but may be required to correctly configure devices attached to
+ *    the static bus. The Au1000/1500/1100 manuals call it LCLK, on
+ *    later models it's called RCLK.
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/clk-private.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <asm/mach-au1x00/au1000.h>
+
+/* Base clock: 12MHz is the default in all databooks, and I haven't
+ * found any board yet which uses a different rate.
+ */
+#define ALCHEMY_ROOTCLK_RATE	12000000
+
+/*
+ * the internal sources which can be driven by the PLLs and dividers.
+ * Names taken from the databooks, refer to them for more information,
+ * especially which ones are share a clock line.
+ */
+static const char * const alchemy_au1300_intclknames[] = {
+	"lcd_intclk", "gpemgp_clk", "maempe_clk", "maebsa_clk",
+	"EXTCLK0", "EXTCLK1"
+};
+
+static const char * const alchemy_au1200_intclknames[] = {
+	"lcd_intclk", NULL, NULL, NULL, "EXTCLK0", "EXTCLK1"
+};
+
+static const char * const alchemy_au1550_intclknames[] = {
+	"usb_clk", "psc0_intclk", "psc1_intclk", "pci_clko",
+	"EXTCLK0", "EXTCLK1"
+};
+
+static const char * const alchemy_au1100_intclknames[] = {
+	"usb_clk", "lcd_intclk", NULL, "i2s_clk", "EXTCLK0", "EXTCLK1"
+};
+
+static const char * const alchemy_au1500_intclknames[] = {
+	NULL, "usbd_clk", "usbh_clk", "pci_clko", "EXTCLK0", "EXTCLK1"
+};
+
+static const char * const alchemy_au1000_intclknames[] = {
+	"irda_clk", "usbd_clk", "usbh_clk", "i2s_clk", "EXTCLK0",
+	"EXTCLK1"
+};
+
+/* aliases for a few on-chip sources which are either shared
+ * or have gone through name changes.
+ */
+static struct clk_aliastable {
+	char *alias;
+	char *base;
+	int cputype;
+} alchemy_clk_aliases[] __initdata = {
+	{ "usbh_clk", "usb_clk",    ALCHEMY_CPU_AU1100 },
+	{ "usbd_clk", "usb_clk",    ALCHEMY_CPU_AU1100 },
+	{ "irda_clk", "usb_clk",    ALCHEMY_CPU_AU1100 },
+	{ "usbh_clk", "usb_clk",    ALCHEMY_CPU_AU1550 },
+	{ "usbd_clk", "usb_clk",    ALCHEMY_CPU_AU1550 },
+	{ "psc2_intclk", "usb_clk", ALCHEMY_CPU_AU1550 },
+	{ "psc3_intclk", "EXTCLK0", ALCHEMY_CPU_AU1550 },
+	{ "psc0_intclk", "EXTCLK0", ALCHEMY_CPU_AU1200 },
+	{ "psc1_intclk", "EXTCLK1", ALCHEMY_CPU_AU1200 },
+	{ "psc0_intclk", "EXTCLK0", ALCHEMY_CPU_AU1300 },
+	{ "psc2_intclk", "EXTCLK0", ALCHEMY_CPU_AU1300 },
+	{ "psc1_intclk", "EXTCLK1", ALCHEMY_CPU_AU1300 },
+	{ "psc3_intclk", "EXTCLK1", ALCHEMY_CPU_AU1300 },
+
+	{ NULL, NULL, 0 },
+};
+
+#define IOMEM(x)	((void __iomem *)(KSEG1ADDR(CPHYSADDR(x))))
+
+/* access locks to SYS_FREQCTRL0/1 and SYS_CLKSRC registers */
+static spinlock_t alchemy_clk_fg0_lock;
+static spinlock_t alchemy_clk_fg1_lock;
+static spinlock_t alchemy_clk_csrc_lock;
+
+/* CPU Core clock *****************************************************/
+
+static unsigned long alchemy_clk_cpu_recalc(struct clk_hw *hw,
+					    unsigned long parent_rate)
+{
+	unsigned long t;
+
+	/*
+	 * On early Au1000, sys_cpupll was write-only. Since these
+	 * silicon versions of Au1000 are not sold, we don't bend
+	 * over backwards trying to determine the frequency.
+	 */
+	if (unlikely(au1xxx_cpu_has_pll_wo()))
+		t = 396000000;
+	else {
+		t = alchemy_rdsys(AU1000_SYS_CPUPLL) & 0x7f;
+		t *= parent_rate;
+	}
+
+	return t;
+}
+
+static struct clk_ops alchemy_clkops_cpu = {
+	.recalc_rate	= alchemy_clk_cpu_recalc,
+};
+
+static struct clk __init *alchemy_clk_setup_cpu(const char *parent_name,
+						int ctype)
+{
+	struct clk_init_data id;
+	struct clk_hw *h;
+
+	h = kzalloc(sizeof(*h), GFP_KERNEL);
+	if (!h)
+		return ERR_PTR(-ENOMEM);
+
+	id.name = ALCHEMY_CPU_CLK;
+	id.parent_names = &parent_name;
+	id.num_parents = 1;
+	id.flags = CLK_IS_BASIC | CLK_IGNORE_UNUSED;
+	id.ops = &alchemy_clkops_cpu;
+	h->init = &id;
+
+	return clk_register(NULL, h);
+}
+
+/* AUXPLLs ************************************************************/
+
+struct alchemy_auxpll_clk {
+	struct clk_hw hw;
+	unsigned long reg;	/* au1300 has also AUXPLL2 */
+	int maxmult;		/* max multiplier */
+};
+#define to_auxpll_clk(x) container_of(x, struct alchemy_auxpll_clk, hw)
+
+static unsigned long alchemy_clk_aux_recalc(struct clk_hw *hw,
+					    unsigned long parent_rate)
+{
+	struct alchemy_auxpll_clk *a = to_auxpll_clk(hw);
+
+	return (alchemy_rdsys(a->reg) & 0xff) * parent_rate;
+}
+
+static int alchemy_clk_aux_setr(struct clk_hw *hw,
+				unsigned long rate,
+				unsigned long parent_rate)
+{
+	struct alchemy_auxpll_clk *a = to_auxpll_clk(hw);
+	unsigned long d = rate;
+
+	if (rate)
+		d /= parent_rate;
+	else
+		d = 0;
+
+	/* minimum is 84MHz, max is 756-1032 depending on variant */
+	if (((d < 7) && (d != 0)) || (d > a->maxmult))
+		return -EINVAL;
+
+	alchemy_wrsys(d, a->reg);
+	return 0;
+}
+
+static long alchemy_clk_aux_roundr(struct clk_hw *hw,
+					    unsigned long rate,
+					    unsigned long *parent_rate)
+{
+	struct alchemy_auxpll_clk *a = to_auxpll_clk(hw);
+	unsigned long mult;
+
+	if (!rate || !*parent_rate)
+		return 0;
+
+	mult = rate / (*parent_rate);
+
+	if (mult && (mult < 7))
+		mult = 7;
+	if (mult > a->maxmult)
+		mult = a->maxmult;
+
+	return (*parent_rate) * mult;
+}
+
+static struct clk_ops alchemy_clkops_aux = {
+	.recalc_rate	= alchemy_clk_aux_recalc,
+	.set_rate	= alchemy_clk_aux_setr,
+	.round_rate	= alchemy_clk_aux_roundr,
+};
+
+static struct clk __init *alchemy_clk_setup_aux(const char *parent_name,
+						char *name, int maxmult,
+						unsigned long reg)
+{
+	struct clk_init_data id;
+	struct clk *c;
+	struct alchemy_auxpll_clk *a;
+
+	a = kzalloc(sizeof(*a), GFP_KERNEL);
+	if (!a)
+		return ERR_PTR(-ENOMEM);
+
+	id.name = name;
+	id.parent_names = &parent_name;
+	id.num_parents = 1;
+	id.flags = CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED;
+	id.ops = &alchemy_clkops_aux;
+
+	a->reg = reg;
+	a->maxmult = maxmult;
+	a->hw.init = &id;
+
+	c = clk_register(NULL, &a->hw);
+	if (!IS_ERR(c))
+		clk_register_clkdev(c, name, NULL);
+	else
+		kfree(a);
+
+	return c;
+}
+
+/* sysbus_clk *********************************************************/
+
+static struct clk __init  *alchemy_clk_setup_sysbus(const char *pn)
+{
+	unsigned long v = (alchemy_rdsys(AU1000_SYS_POWERCTRL) & 3) + 2;
+	struct clk *c;
+
+	c = clk_register_fixed_factor(NULL, ALCHEMY_SYSBUS_CLK,
+				      pn, 0, 1, v);
+	if (!IS_ERR(c))
+		clk_register_clkdev(c, ALCHEMY_SYSBUS_CLK, NULL);
+	return c;
+}
+
+/* Peripheral Clock ***************************************************/
+
+static struct clk __init *alchemy_clk_setup_periph(const char *pn)
+{
+	/* Peripheral clock runs at half the rate of sysbus clk */
+	struct clk *c;
+
+	c = clk_register_fixed_factor(NULL, ALCHEMY_PERIPH_CLK,
+				      pn, 0, 1, 2);
+	if (!IS_ERR(c))
+		clk_register_clkdev(c, ALCHEMY_PERIPH_CLK, NULL);
+	return c;
+}
+
+/* mem clock **********************************************************/
+
+static struct clk __init *alchemy_clk_setup_mem(const char *pn, int ct)
+{
+	void __iomem *addr = IOMEM(AU1000_MEM_PHYS_ADDR);
+	unsigned long v;
+	struct clk *c;
+	int div;
+
+	switch (ct) {
+	case ALCHEMY_CPU_AU1550:
+	case ALCHEMY_CPU_AU1200:
+		v = __raw_readl(addr + AU1550_MEM_SDCONFIGB);
+		div = (v & (1 << 15)) ? 1 : 2;
+		break;
+	case ALCHEMY_CPU_AU1300:
+		v = __raw_readl(addr + AU1550_MEM_SDCONFIGB);
+		div = (v & (1 << 31)) ? 1 : 2;
+		break;
+	case ALCHEMY_CPU_AU1000:
+	case ALCHEMY_CPU_AU1500:
+	case ALCHEMY_CPU_AU1100:
+	default:
+		div = 2;
+		break;
+	}
+
+	c = clk_register_fixed_factor(NULL, ALCHEMY_MEM_CLK, pn,
+				      0, 1, div);
+	if (!IS_ERR(c))
+		clk_register_clkdev(c, ALCHEMY_MEM_CLK, NULL);
+	return c;
+}
+
+/* lrclk: external synchronous static bus clock ***********************/
+
+static struct clk __init *alchemy_clk_setup_lrclk(const char *pn)
+{
+	/* MEM_STCFG0[15:13] = divisor.
+	 * L/RCLK = periph_clk / (divisor + 1)
+	 * On Au1000, Au1500, Au1100 it's called LCLK,
+	 * on later models it's called RCLK, but it's the same thing.
+	 */
+	struct clk *c;
+	unsigned long v = alchemy_rdsmem(AU1000_MEM_STCFG0) >> 13;
+
+	v = (v & 7) + 1;
+	c = clk_register_fixed_factor(NULL, ALCHEMY_LR_CLK,
+				      pn, 0, 1, v);
+	if (!IS_ERR(c))
+		clk_register_clkdev(c, ALCHEMY_LR_CLK, NULL);
+	return c;
+}
+
+/* Clock dividers and muxes *******************************************/
+
+/* data for fgen and csrc mux-dividers */
+struct alchemy_fgcs_clk {
+	struct clk_hw hw;
+	spinlock_t *reglock;	/* register lock		  */
+	unsigned long reg;	/* SYS_FREQCTRL0/1		  */
+	int shift;		/* offset in register		  */
+	int parent;		/* parent before disable [Au1300] */
+	int isen;		/* is it enabled?		  */
+	int *dt;		/* dividertable for csrc	  */
+};
+#define to_fgcs_clk(x) container_of(x, struct alchemy_fgcs_clk, hw)
+
+static long alchemy_calc_div(unsigned long rate, unsigned long prate,
+			       int scale, int maxdiv, unsigned long *rv)
+{
+	long div1, div2;
+
+	div1 = prate / rate;
+	if ((prate / div1) > rate)
+		div1++;
+
+	if (scale == 2) {	/* only div-by-multiple-of-2 possible */
+		if (div1 & 1)
+			div1++;	/* stay <=prate */
+	}
+
+	div2 = (div1 / scale) - 1;	/* value to write to register */
+
+	if (div2 > maxdiv)
+		div2 = maxdiv;
+	if (rv)
+		*rv = div2;
+
+	div1 = ((div2 + 1) * scale);
+	return div1;
+}
+
+static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate,
+					unsigned long *best_parent_rate,
+					struct clk **best_parent_clk,
+					int scale, int maxdiv)
+{
+	struct clk *pc, *bpc, *free;
+	long tdv, tpr, pr, nr, br, bpr, diff, lastdiff;
+	int j;
+
+	lastdiff = INT_MAX;
+	bpr = 0;
+	bpc = NULL;
+	br = -EINVAL;
+	free = NULL;
+
+	/* look at the rates each enabled parent supplies and select
+	 * the one that gets closest to but not over the requested rate.
+	 */
+	for (j = 0; j < 7; j++) {
+		pc = clk_get_parent_by_index(hw->clk, j);
+		if (!pc)
+			break;
+
+		/* if this parent is currently unused, remember it.
+		 * XXX: I know it's a layering violation, but it works
+		 * so well.. (if (!clk_has_active_children(pc)) )
+		 */
+		if (pc->prepare_count == 0) {
+			if (!free)
+				free = pc;
+		}
+
+		pr = clk_get_rate(pc);
+		if (pr < rate)
+			continue;
+
+		/* what can hardware actually provide */
+		tdv = alchemy_calc_div(rate, pr, scale, maxdiv, NULL);
+		nr = pr / tdv;
+		diff = rate - nr;
+		if (nr > rate)
+			continue;
+
+		if (diff < lastdiff) {
+			lastdiff = diff;
+			bpr = pr;
+			bpc = pc;
+			br = nr;
+		}
+		if (diff == 0)
+			break;
+	}
+
+	/* if we couldn't get the exact rate we wanted from the enabled
+	 * parents, maybe we can tell an available disabled/inactive one
+	 * to give us a rate we can divide down to the requested rate.
+	 */
+	if (lastdiff && free) {
+		for (j = (maxdiv == 4) ? 1 : scale; j <= maxdiv; j += scale) {
+			tpr = rate * j;
+			if (tpr < 0)
+				break;
+			pr = clk_round_rate(free, tpr);
+
+			tdv = alchemy_calc_div(rate, pr, scale, maxdiv, NULL);
+			nr = pr / tdv;
+			diff = rate - nr;
+			if (nr > rate)
+				continue;
+			if (diff < lastdiff) {
+				lastdiff = diff;
+				bpr = pr;
+				bpc = free;
+				br = nr;
+			}
+			if (diff == 0)
+				break;
+		}
+	}
+
+	*best_parent_rate = bpr;
+	*best_parent_clk = bpc;
+	return br;
+}
+
+static int alchemy_clk_fgv1_en(struct clk_hw *hw)
+{
+	struct alchemy_fgcs_clk *c = to_fgcs_clk(hw);
+	unsigned long v, flags;
+
+	spin_lock_irqsave(c->reglock, flags);
+	v = alchemy_rdsys(c->reg);
+	v |= (1 << 1) << c->shift;
+	alchemy_wrsys(v, c->reg);
+	spin_unlock_irqrestore(c->reglock, flags);
+
+	return 0;
+}
+
+static int alchemy_clk_fgv1_isen(struct clk_hw *hw)
+{
+	struct alchemy_fgcs_clk *c = to_fgcs_clk(hw);
+	unsigned long v = alchemy_rdsys(c->reg) >> (c->shift + 1);
+
+	return v & 1;
+}
+
+static void alchemy_clk_fgv1_dis(struct clk_hw *hw)
+{
+	struct alchemy_fgcs_clk *c = to_fgcs_clk(hw);
+	unsigned long v, flags;
+
+	spin_lock_irqsave(c->reglock, flags);
+	v = alchemy_rdsys(c->reg);
+	v &= ~((1 << 1) << c->shift);
+	alchemy_wrsys(v, c->reg);
+	spin_unlock_irqrestore(c->reglock, flags);
+}
+
+static int alchemy_clk_fgv1_setp(struct clk_hw *hw, u8 index)
+{
+	struct alchemy_fgcs_clk *c = to_fgcs_clk(hw);
+	unsigned long v, flags;
+
+	spin_lock_irqsave(c->reglock, flags);
+	v = alchemy_rdsys(c->reg);
+	if (index)
+		v |= (1 << c->shift);
+	else
+		v &= ~(1 << c->shift);
+	alchemy_wrsys(v, c->reg);
+	spin_unlock_irqrestore(c->reglock, flags);
+
+	return 0;
+}
+
+static u8 alchemy_clk_fgv1_getp(struct clk_hw *hw)
+{
+	struct alchemy_fgcs_clk *c = to_fgcs_clk(hw);
+
+	return (alchemy_rdsys(c->reg) >> c->shift) & 1;
+}
+
+static int alchemy_clk_fgv1_setr(struct clk_hw *hw, unsigned long rate,
+				 unsigned long parent_rate)
+{
+	struct alchemy_fgcs_clk *c = to_fgcs_clk(hw);
+	unsigned long div, v, flags, ret;
+	int sh = c->shift + 2;
+
+	if (!rate || !parent_rate || rate > (parent_rate / 2))
+		return -EINVAL;
+	ret = alchemy_calc_div(rate, parent_rate, 2, 512, &div);
+	spin_lock_irqsave(c->reglock, flags);
+	v = alchemy_rdsys(c->reg);
+	v &= ~(0xff << sh);
+	v |= div << sh;
+	alchemy_wrsys(v, c->reg);
+	spin_unlock_irqrestore(c->reglock, flags);
+
+	return 0;
+}
+
+static unsigned long alchemy_clk_fgv1_recalc(struct clk_hw *hw,
+					     unsigned long parent_rate)
+{
+	struct alchemy_fgcs_clk *c = to_fgcs_clk(hw);
+	unsigned long v = alchemy_rdsys(c->reg) >> (c->shift + 2);
+
+	v = ((v & 0xff) + 1) * 2;
+	return parent_rate / v;
+}
+
+static long alchemy_clk_fgv1_detr(struct clk_hw *hw, unsigned long rate,
+					unsigned long *best_parent_rate,
+					struct clk **best_parent_clk)
+{
+	return alchemy_clk_fgcs_detr(hw, rate, best_parent_rate,
+				     best_parent_clk, 2, 512);
+}
+
+/* Au1000, Au1100, Au15x0, Au12x0 */
+static struct clk_ops alchemy_clkops_fgenv1 = {
+	.recalc_rate	= alchemy_clk_fgv1_recalc,
+	.determine_rate	= alchemy_clk_fgv1_detr,
+	.set_rate	= alchemy_clk_fgv1_setr,
+	.set_parent	= alchemy_clk_fgv1_setp,
+	.get_parent	= alchemy_clk_fgv1_getp,
+	.enable		= alchemy_clk_fgv1_en,
+	.disable	= alchemy_clk_fgv1_dis,
+	.is_enabled	= alchemy_clk_fgv1_isen,
+};
+
+static void __alchemy_clk_fgv2_en(struct alchemy_fgcs_clk *c)
+{
+	unsigned long v = alchemy_rdsys(c->reg);
+
+	v &= ~(3 << c->shift);
+	v |= (c->parent & 3) << c->shift;
+	alchemy_wrsys(v, c->reg);
+	c->isen = 1;
+}
+
+static int alchemy_clk_fgv2_en(struct clk_hw *hw)
+{
+	struct alchemy_fgcs_clk *c = to_fgcs_clk(hw);
+	unsigned long flags;
+
+	/* enable by setting the previous parent clock */
+	spin_lock_irqsave(c->reglock, flags);
+	__alchemy_clk_fgv2_en(c);
+	spin_unlock_irqrestore(c->reglock, flags);
+
+	return 0;
+}
+
+static int alchemy_clk_fgv2_isen(struct clk_hw *hw)
+{
+	struct alchemy_fgcs_clk *c = to_fgcs_clk(hw);
+
+	return ((alchemy_rdsys(c->reg) >> c->shift) & 3) != 0;
+}
+
+static void alchemy_clk_fgv2_dis(struct clk_hw *hw)
+{
+	struct alchemy_fgcs_clk *c = to_fgcs_clk(hw);
+	unsigned long v, flags;
+
+	spin_lock_irqsave(c->reglock, flags);
+	v = alchemy_rdsys(c->reg);
+	v &= ~(3 << c->shift);	/* set input mux to "disabled" state */
+	alchemy_wrsys(v, c->reg);
+	c->isen = 0;
+	spin_unlock_irqrestore(c->reglock, flags);
+}
+
+static int alchemy_clk_fgv2_setp(struct clk_hw *hw, u8 index)
+{
+	struct alchemy_fgcs_clk *c = to_fgcs_clk(hw);
+	unsigned long flags;
+
+	spin_lock_irqsave(c->reglock, flags);
+	c->parent = index + 1;	/* value to write to register */
+	if (c->isen)
+		__alchemy_clk_fgv2_en(c);
+	spin_unlock_irqrestore(c->reglock, flags);
+
+	return 0;
+}
+
+static u8 alchemy_clk_fgv2_getp(struct clk_hw *hw)
+{
+	struct alchemy_fgcs_clk *c = to_fgcs_clk(hw);
+	unsigned long flags, v;
+
+	spin_lock_irqsave(c->reglock, flags);
+	v = c->parent - 1;
+	spin_unlock_irqrestore(c->reglock, flags);
+	return v;
+}
+
+/* fg0-2 and fg4-6 share a "scale"-bit. With this bit cleared, the
+ * dividers behave exactly as on previous models (dividers are multiples
+ * of 2); with the bit set, dividers are multiples of 1, halving their
+ * range, but making them also much more flexible.
+ */
+static int alchemy_clk_fgv2_setr(struct clk_hw *hw, unsigned long rate,
+				 unsigned long parent_rate)
+{
+	struct alchemy_fgcs_clk *c = to_fgcs_clk(hw);
+	int sh = c->shift + 2;
+	unsigned long div, v, flags, ret;
+
+	if (!rate || !parent_rate || rate > parent_rate)
+		return -EINVAL;
+
+	v = alchemy_rdsys(c->reg) & (1 << 30); /* test "scale" bit */
+	ret = alchemy_calc_div(rate, parent_rate, v ? 1 : 2,
+			       v ? 256 : 512, &div);
+
+	spin_lock_irqsave(c->reglock, flags);
+	v = alchemy_rdsys(c->reg);
+	v &= ~(0xff << sh);
+	v |= (div & 0xff) << sh;
+	alchemy_wrsys(v, c->reg);
+	spin_unlock_irqrestore(c->reglock, flags);
+
+	return 0;
+}
+
+static unsigned long alchemy_clk_fgv2_recalc(struct clk_hw *hw,
+					     unsigned long parent_rate)
+{
+	struct alchemy_fgcs_clk *c = to_fgcs_clk(hw);
+	int sh = c->shift + 2;
+	unsigned long v, t;
+
+	v = alchemy_rdsys(c->reg);
+	t = parent_rate / (((v >> sh) & 0xff) + 1);
+	if ((v & (1 << 30)) == 0)		/* test scale bit */
+		t /= 2;
+
+	return t;
+}
+
+static long alchemy_clk_fgv2_detr(struct clk_hw *hw, unsigned long rate,
+					unsigned long *best_parent_rate,
+					struct clk **best_parent_clk)
+{
+	struct alchemy_fgcs_clk *c = to_fgcs_clk(hw);
+	int scale, maxdiv;
+
+	if (alchemy_rdsys(c->reg) & (1 << 30)) {
+		scale = 1;
+		maxdiv = 256;
+	} else {
+		scale = 2;
+		maxdiv = 512;
+	}
+
+	return alchemy_clk_fgcs_detr(hw, rate, best_parent_rate,
+				     best_parent_clk, scale, maxdiv);
+}
+
+/* Au1300 larger input mux, no separate disable bit, flexible divider */
+static struct clk_ops alchemy_clkops_fgenv2 = {
+	.recalc_rate	= alchemy_clk_fgv2_recalc,
+	.determine_rate	= alchemy_clk_fgv2_detr,
+	.set_rate	= alchemy_clk_fgv2_setr,
+	.set_parent	= alchemy_clk_fgv2_setp,
+	.get_parent	= alchemy_clk_fgv2_getp,
+	.enable		= alchemy_clk_fgv2_en,
+	.disable	= alchemy_clk_fgv2_dis,
+	.is_enabled	= alchemy_clk_fgv2_isen,
+};
+
+static const char * const alchemy_clk_fgv1_parents[] = {
+	ALCHEMY_CPU_CLK, ALCHEMY_AUXPLL_CLK
+};
+
+static const char * const alchemy_clk_fgv2_parents[] = {
+	ALCHEMY_AUXPLL2_CLK, ALCHEMY_CPU_CLK, ALCHEMY_AUXPLL_CLK
+};
+
+static const char * const alchemy_clk_fgen_names[] = {
+	ALCHEMY_FG0_CLK, ALCHEMY_FG1_CLK, ALCHEMY_FG2_CLK,
+	ALCHEMY_FG3_CLK, ALCHEMY_FG4_CLK, ALCHEMY_FG5_CLK };
+
+static int __init alchemy_clk_init_fgens(int ctype)
+{
+	struct clk *c;
+	struct clk_init_data id;
+	struct alchemy_fgcs_clk *a;
+	unsigned long v;
+	int i, ret;
+
+	switch (ctype) {
+	case ALCHEMY_CPU_AU1000...ALCHEMY_CPU_AU1200:
+		id.ops = &alchemy_clkops_fgenv1;
+		id.parent_names = (const char **)alchemy_clk_fgv1_parents;
+		id.num_parents = 2;
+		break;
+	case ALCHEMY_CPU_AU1300:
+		id.ops = &alchemy_clkops_fgenv2;
+		id.parent_names = (const char **)alchemy_clk_fgv2_parents;
+		id.num_parents = 3;
+		break;
+	default:
+		return -ENODEV;
+	}
+	id.flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE |
+		   CLK_IGNORE_UNUSED;
+
+	a = kzalloc((sizeof(*a)) * 6, GFP_KERNEL);
+	if (!a)
+		return -ENOMEM;
+
+	spin_lock_init(&alchemy_clk_fg0_lock);
+	spin_lock_init(&alchemy_clk_fg1_lock);
+	ret = 0;
+	for (i = 0; i < 6; i++) {
+		id.name = alchemy_clk_fgen_names[i];
+		a->shift = 10 * (i < 3 ? i : i - 3);
+		if (i > 2) {
+			a->reg = AU1000_SYS_FREQCTRL1;
+			a->reglock = &alchemy_clk_fg1_lock;
+		} else {
+			a->reg = AU1000_SYS_FREQCTRL0;
+			a->reglock = &alchemy_clk_fg0_lock;
+		}
+
+		/* default to first parent if bootloader has set
+		 * the mux to disabled state.
+		 */
+		if (ctype == ALCHEMY_CPU_AU1300) {
+			v = alchemy_rdsys(a->reg);
+			a->parent = (v >> a->shift) & 3;
+			if (!a->parent) {
+				a->parent = 1;
+				a->isen = 0;
+			} else
+				a->isen = 1;
+		}
+
+		a->hw.init = &id;
+		c = clk_register(NULL, &a->hw);
+		if (IS_ERR(c))
+			ret++;
+		else
+			clk_register_clkdev(c, id.name, NULL);
+		a++;
+	}
+
+	return ret;
+}
+
+/* internal sources muxes *********************************************/
+
+static int alchemy_clk_csrc_isen(struct clk_hw *hw)
+{
+	struct alchemy_fgcs_clk *c = to_fgcs_clk(hw);
+	unsigned long v = alchemy_rdsys(c->reg);
+
+	return (((v >> c->shift) >> 2) & 7) != 0;
+}
+
+static void __alchemy_clk_csrc_en(struct alchemy_fgcs_clk *c)
+{
+	unsigned long v = alchemy_rdsys(c->reg);
+
+	v &= ~((7 << 2) << c->shift);
+	v |= ((c->parent & 7) << 2) << c->shift;
+	alchemy_wrsys(v, c->reg);
+	c->isen = 1;
+}
+
+static int alchemy_clk_csrc_en(struct clk_hw *hw)
+{
+	struct alchemy_fgcs_clk *c = to_fgcs_clk(hw);
+	unsigned long flags;
+
+	/* enable by setting the previous parent clock */
+	spin_lock_irqsave(c->reglock, flags);
+	__alchemy_clk_csrc_en(c);
+	spin_unlock_irqrestore(c->reglock, flags);
+
+	return 0;
+}
+
+static void alchemy_clk_csrc_dis(struct clk_hw *hw)
+{
+	struct alchemy_fgcs_clk *c = to_fgcs_clk(hw);
+	unsigned long v, flags;
+
+	spin_lock_irqsave(c->reglock, flags);
+	v = alchemy_rdsys(c->reg);
+	v &= ~((3 << 2) << c->shift);	/* mux to "disabled" state */
+	alchemy_wrsys(v, c->reg);
+	c->isen = 0;
+	spin_unlock_irqrestore(c->reglock, flags);
+}
+
+static int alchemy_clk_csrc_setp(struct clk_hw *hw, u8 index)
+{
+	struct alchemy_fgcs_clk *c = to_fgcs_clk(hw);
+	unsigned long flags;
+
+	spin_lock_irqsave(c->reglock, flags);
+	c->parent = index + 1;	/* value to write to register */
+	if (c->isen)
+		__alchemy_clk_csrc_en(c);
+	spin_unlock_irqrestore(c->reglock, flags);
+
+	return 0;
+}
+
+static u8 alchemy_clk_csrc_getp(struct clk_hw *hw)
+{
+	struct alchemy_fgcs_clk *c = to_fgcs_clk(hw);
+
+	return c->parent - 1;
+}
+
+static unsigned long alchemy_clk_csrc_recalc(struct clk_hw *hw,
+					     unsigned long parent_rate)
+{
+	struct alchemy_fgcs_clk *c = to_fgcs_clk(hw);
+	unsigned long v = (alchemy_rdsys(c->reg) >> c->shift) & 3;
+
+	return parent_rate / c->dt[v];
+}
+
+static int alchemy_clk_csrc_setr(struct clk_hw *hw, unsigned long rate,
+				 unsigned long parent_rate)
+{
+	struct alchemy_fgcs_clk *c = to_fgcs_clk(hw);
+	unsigned long d, v, flags;
+	int i;
+
+	if (!rate || !parent_rate || rate > parent_rate)
+		return -EINVAL;
+
+	d = (parent_rate + (rate / 2)) / rate;
+	if (d > 4)
+		return -EINVAL;
+	if ((d == 3) && (c->dt[2] != 3))
+		d = 4;
+
+	for (i = 0; i < 4; i++)
+		if (c->dt[i] == d)
+			break;
+
+	if (i >= 4)
+		return -EINVAL;	/* oops */
+
+	spin_lock_irqsave(c->reglock, flags);
+	v = alchemy_rdsys(c->reg);
+	v &= ~(3 << c->shift);
+	v |= (i & 3) << c->shift;
+	alchemy_wrsys(v, c->reg);
+	spin_unlock_irqrestore(c->reglock, flags);
+
+	return 0;
+}
+
+static long alchemy_clk_csrc_detr(struct clk_hw *hw, unsigned long rate,
+					unsigned long *best_parent_rate,
+					struct clk **best_parent_clk)
+{
+	struct alchemy_fgcs_clk *c = to_fgcs_clk(hw);
+	int scale = c->dt[2] == 3 ? 1 : 2; /* au1300 check */
+
+	return alchemy_clk_fgcs_detr(hw, rate, best_parent_rate,
+				     best_parent_clk, scale, 4);
+}
+
+static struct clk_ops alchemy_clkops_csrc = {
+	.recalc_rate	= alchemy_clk_csrc_recalc,
+	.determine_rate	= alchemy_clk_csrc_detr,
+	.set_rate	= alchemy_clk_csrc_setr,
+	.set_parent	= alchemy_clk_csrc_setp,
+	.get_parent	= alchemy_clk_csrc_getp,
+	.enable		= alchemy_clk_csrc_en,
+	.disable	= alchemy_clk_csrc_dis,
+	.is_enabled	= alchemy_clk_csrc_isen,
+};
+
+static const char * const alchemy_clk_csrc_parents[] = {
+	/* disabled at index 0 */ ALCHEMY_AUXPLL_CLK,
+	ALCHEMY_FG0_CLK, ALCHEMY_FG1_CLK, ALCHEMY_FG2_CLK,
+	ALCHEMY_FG3_CLK, ALCHEMY_FG4_CLK, ALCHEMY_FG5_CLK
+};
+
+/* divider tables */
+static int alchemy_csrc_dt1[] = { 1, 4, 1, 2 };	/* rest */
+static int alchemy_csrc_dt2[] = { 1, 4, 3, 2 };	/* Au1300 */
+
+static int __init alchemy_clk_setup_imux(int ctype)
+{
+	struct alchemy_fgcs_clk *a;
+	const char * const *names;
+	struct clk_init_data id;
+	unsigned long v;
+	int i, ret, *dt;
+	struct clk *c;
+
+	id.ops = &alchemy_clkops_csrc;
+	id.parent_names = (const char **)alchemy_clk_csrc_parents;
+	id.num_parents = 7;
+	id.flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE |
+		   CLK_IGNORE_UNUSED;
+
+	dt = alchemy_csrc_dt1;
+	switch (ctype) {
+	case ALCHEMY_CPU_AU1000:
+		names = alchemy_au1000_intclknames;
+		break;
+	case ALCHEMY_CPU_AU1500:
+		names = alchemy_au1500_intclknames;
+		break;
+	case ALCHEMY_CPU_AU1100:
+		names = alchemy_au1100_intclknames;
+		break;
+	case ALCHEMY_CPU_AU1550:
+		names = alchemy_au1550_intclknames;
+		break;
+	case ALCHEMY_CPU_AU1200:
+		names = alchemy_au1200_intclknames;
+		break;
+	case ALCHEMY_CPU_AU1300:
+		dt = alchemy_csrc_dt2;
+		names = alchemy_au1300_intclknames;
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	a = kzalloc((sizeof(*a)) * 6, GFP_KERNEL);
+	if (!a)
+		return -ENOMEM;
+
+	spin_lock_init(&alchemy_clk_csrc_lock);
+	ret = 0;
+
+	for (i = 0; i < 6; i++) {
+		id.name = names[i];
+		if (!id.name)
+			goto next;
+
+		a->shift = i * 5;
+		a->reg = AU1000_SYS_CLKSRC;
+		a->reglock = &alchemy_clk_csrc_lock;
+		a->dt = dt;
+
+		/* default to first parent clock if mux is initially
+		 * set to disabled state.
+		 */
+		v = alchemy_rdsys(a->reg);
+		a->parent = ((v >> a->shift) >> 2) & 7;
+		if (!a->parent) {
+			a->parent = 1;
+			a->isen = 0;
+		} else
+			a->isen = 1;
+
+		a->hw.init = &id;
+		c = clk_register(NULL, &a->hw);
+		if (IS_ERR(c))
+			ret++;
+		else
+			clk_register_clkdev(c, id.name, NULL);
+next:
+		a++;
+	}
+
+	return ret;
+}
+
+
+/**********************************************************************/
+
+
+#define ERRCK(x)						\
+	if (IS_ERR(x)) {					\
+		ret = PTR_ERR(x);				\
+		goto out;					\
+	}
+
+static int __init alchemy_clk_init(void)
+{
+	int ctype = alchemy_get_cputype(), ret, i;
+	struct clk_aliastable *t = alchemy_clk_aliases;
+	struct clk *c;
+
+	/* Root of the Alchemy clock tree: external 12MHz crystal osc */
+	c = clk_register_fixed_rate(NULL, ALCHEMY_ROOT_CLK, NULL,
+					   CLK_IS_ROOT,
+					   ALCHEMY_ROOTCLK_RATE);
+	ERRCK(c)
+
+	/* CPU core clock */
+	c = alchemy_clk_setup_cpu(ALCHEMY_ROOT_CLK, ctype);
+	ERRCK(c)
+
+	/* AUXPLLs: max 1GHz on Au1300, 748MHz on older models */
+	i = (ctype == ALCHEMY_CPU_AU1300) ? 84 : 63;
+	c = alchemy_clk_setup_aux(ALCHEMY_ROOT_CLK, ALCHEMY_AUXPLL_CLK,
+				  i, AU1000_SYS_AUXPLL);
+	ERRCK(c)
+
+	if (ctype == ALCHEMY_CPU_AU1300) {
+		c = alchemy_clk_setup_aux(ALCHEMY_ROOT_CLK,
+					  ALCHEMY_AUXPLL2_CLK, i,
+					  AU1300_SYS_AUXPLL2);
+		ERRCK(c)
+	}
+
+	/* sysbus clock: cpu core clock divided by 2, 3 or 4 */
+	c = alchemy_clk_setup_sysbus(ALCHEMY_CPU_CLK);
+	ERRCK(c)
+
+	/* peripheral clock: runs at half rate of sysbus clk */
+	c = alchemy_clk_setup_periph(ALCHEMY_SYSBUS_CLK);
+	ERRCK(c)
+
+	/* SDR/DDR memory clock */
+	c = alchemy_clk_setup_mem(ALCHEMY_SYSBUS_CLK, ctype);
+	ERRCK(c)
+
+	/* L/RCLK: external static bus clock for synchronous mode */
+	c = alchemy_clk_setup_lrclk(ALCHEMY_PERIPH_CLK);
+	ERRCK(c)
+
+	/* Frequency dividers 0-5 */
+	ret = alchemy_clk_init_fgens(ctype);
+	if (ret) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	/* diving muxes for internal sources */
+	ret = alchemy_clk_setup_imux(ctype);
+	if (ret) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	/* set up aliases drivers might look for */
+	while (t->base) {
+		if (t->cputype == ctype)
+			clk_add_alias(t->alias, NULL, t->base, NULL);
+		t++;
+	}
+
+	pr_info("Alchemy clocktree installed\n");
+	return 0;
+
+out:
+	return ret;
+}
+postcore_initcall(alchemy_clk_init);
diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h
index 7542070..1f40c0a 100644
--- a/arch/mips/include/asm/mach-au1x00/au1000.h
+++ b/arch/mips/include/asm/mach-au1x00/au1000.h
@@ -47,6 +47,21 @@
 #define ALCHEMY_GPIC_INT_NUM	128
 #define ALCHEMY_GPIC_INT_LAST	(ALCHEMY_GPIC_INT_BASE + ALCHEMY_GPIC_INT_NUM - 1)
 
+/* common clock names, shared among all variants. AUXPLL2 is Au1300 */
+#define ALCHEMY_ROOT_CLK		"root_clk"
+#define ALCHEMY_CPU_CLK			"cpu_clk"
+#define ALCHEMY_AUXPLL_CLK		"auxpll_clk"
+#define ALCHEMY_AUXPLL2_CLK		"auxpll2_clk"
+#define ALCHEMY_SYSBUS_CLK		"sysbus_clk"
+#define ALCHEMY_PERIPH_CLK		"periph_clk"
+#define ALCHEMY_MEM_CLK			"mem_clk"
+#define ALCHEMY_LR_CLK			"lr_clk"
+#define ALCHEMY_FG0_CLK			"fg0_clk"
+#define ALCHEMY_FG1_CLK			"fg1_clk"
+#define ALCHEMY_FG2_CLK			"fg2_clk"
+#define ALCHEMY_FG3_CLK			"fg3_clk"
+#define ALCHEMY_FG4_CLK			"fg4_clk"
+#define ALCHEMY_FG5_CLK			"fg5_clk"
 
 /* Au1300 peripheral interrupt numbers */
 #define AU1300_FIRST_INT	(ALCHEMY_GPIC_INT_BASE)
@@ -523,6 +538,7 @@
 
 #define AU1000_SYS_CPUPLL	0x60
 #define AU1000_SYS_AUXPLL	0x64
+#define AU1300_SYS_AUXPLL2	0x68
 
 
 /**********************************************************************/
-- 
2.0.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 02/10] MIPS: Alchemy: platform: use clk framework for uarts
  2014-07-23 14:36 [PATCH 00/10] MIPS: Alchemy: common clk framework support Manuel Lauss
  2014-07-23 14:36 ` [PATCH 01/10] MIPS: Alchemy: clock framework integration of onchip clocks Manuel Lauss
@ 2014-07-23 14:36 ` Manuel Lauss
  2014-07-23 14:36 ` [PATCH 03/10] MIPS: Alchemy: usb: use clk framework Manuel Lauss
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Manuel Lauss @ 2014-07-23 14:36 UTC (permalink / raw)
  To: Linux-MIPS; +Cc: Manuel Lauss

Use the clock framework to get the rate of the peripheral clock.
Remove the now obsolete get_uart_baud_base function.

Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
---
 arch/mips/alchemy/common/clocks.c          | 19 -------------------
 arch/mips/alchemy/common/platform.c        | 13 ++++++++++++-
 arch/mips/include/asm/mach-au1x00/au1000.h |  2 --
 3 files changed, 12 insertions(+), 22 deletions(-)

diff --git a/arch/mips/alchemy/common/clocks.c b/arch/mips/alchemy/common/clocks.c
index 0e41416..a4c7cd7 100644
--- a/arch/mips/alchemy/common/clocks.c
+++ b/arch/mips/alchemy/common/clocks.c
@@ -38,7 +38,6 @@
 #define AU1000_SRC_CLK	12000000
 
 static unsigned int au1x00_clock; /*  Hz */
-static unsigned long uart_baud_base;
 
 /*
  * Set the au1000_clock
@@ -55,21 +54,6 @@ unsigned int get_au1x00_speed(void)
 EXPORT_SYMBOL(get_au1x00_speed);
 
 /*
- * The UART baud base is not known at compile time ... if
- * we want to be able to use the same code on different
- * speed CPUs.
- */
-unsigned long get_au1x00_uart_baud_base(void)
-{
-	return uart_baud_base;
-}
-
-void set_au1x00_uart_baud_base(unsigned long new_baud_base)
-{
-	uart_baud_base = new_baud_base;
-}
-
-/*
  * We read the real processor speed from the PLL.  This is important
  * because it is more accurate than computing it from the 32 KHz
  * counter, if it exists.  If we don't have an accurate processor
@@ -95,9 +79,6 @@ unsigned long au1xxx_calc_clock(void)
 
 	/* On Alchemy CPU:counter ratio is 1:1 */
 	mips_hpt_frequency = cpu_speed;
-	/* Equation: Baudrate = CPU / (SD * 2 * CLKDIV * 16) */
-	set_au1x00_uart_baud_base(cpu_speed / (2 *
-		((alchemy_rdsys(AU1000_SYS_POWERCTRL) & 0x03) + 2) * 16));
 
 	set_au1x00_speed(cpu_speed);
 
diff --git a/arch/mips/alchemy/common/platform.c b/arch/mips/alchemy/common/platform.c
index fb89d21..d77a64f 100644
--- a/arch/mips/alchemy/common/platform.c
+++ b/arch/mips/alchemy/common/platform.c
@@ -11,6 +11,7 @@
  * warranty of any kind, whether express or implied.
  */
 
+#include <linux/clk.h>
 #include <linux/dma-mapping.h>
 #include <linux/etherdevice.h>
 #include <linux/init.h>
@@ -99,10 +100,20 @@ static struct platform_device au1xx0_uart_device = {
 
 static void __init alchemy_setup_uarts(int ctype)
 {
-	unsigned int uartclk = get_au1x00_uart_baud_base() * 16;
+	long uartclk;
 	int s = sizeof(struct plat_serial8250_port);
 	int c = alchemy_get_uarts(ctype);
 	struct plat_serial8250_port *ports;
+	struct clk *clk = clk_get(NULL, ALCHEMY_PERIPH_CLK);
+
+	if (IS_ERR(clk))
+		return;
+	if (clk_prepare_enable(clk)) {
+		clk_put(clk);
+		return;
+	}
+	uartclk = clk_get_rate(clk);
+	clk_put(clk);
 
 	ports = kzalloc(s * (c + 1), GFP_KERNEL);
 	if (!ports) {
diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h
index 1f40c0a..e77b920 100644
--- a/arch/mips/include/asm/mach-au1x00/au1000.h
+++ b/arch/mips/include/asm/mach-au1x00/au1000.h
@@ -844,8 +844,6 @@ static inline int alchemy_get_macs(int type)
 /* arch/mips/au1000/common/clocks.c */
 extern void set_au1x00_speed(unsigned int new_freq);
 extern unsigned int get_au1x00_speed(void);
-extern void set_au1x00_uart_baud_base(unsigned long new_baud_base);
-extern unsigned long get_au1x00_uart_baud_base(void);
 extern unsigned long au1xxx_calc_clock(void);
 
 /* PM: arch/mips/alchemy/common/sleeper.S, power.c, irq.c */
-- 
2.0.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 03/10] MIPS: Alchemy: usb: use clk framework
  2014-07-23 14:36 [PATCH 00/10] MIPS: Alchemy: common clk framework support Manuel Lauss
  2014-07-23 14:36 ` [PATCH 01/10] MIPS: Alchemy: clock framework integration of onchip clocks Manuel Lauss
  2014-07-23 14:36 ` [PATCH 02/10] MIPS: Alchemy: platform: use clk framework for uarts Manuel Lauss
@ 2014-07-23 14:36 ` Manuel Lauss
  2014-07-23 14:36 ` [PATCH 04/10] MIPS: Alchemy: pci: use clk framework to enable PCI clock Manuel Lauss
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Manuel Lauss @ 2014-07-23 14:36 UTC (permalink / raw)
  To: Linux-MIPS; +Cc: Manuel Lauss

Add use of the common clock framework to set and enable the 48MHz
clock source for the onchip OHCI and UDC blocks.

Tested on a DB1500.  (Au1200 and Au1300 use an external 48MHz crystal).

Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
---
 arch/mips/alchemy/common/usb.c | 47 +++++++++++++++++++++++++++++++++++-------
 1 file changed, 40 insertions(+), 7 deletions(-)

diff --git a/arch/mips/alchemy/common/usb.c b/arch/mips/alchemy/common/usb.c
index d193dbe..297805a 100644
--- a/arch/mips/alchemy/common/usb.c
+++ b/arch/mips/alchemy/common/usb.c
@@ -9,6 +9,7 @@
  *
  */
 
+#include <linux/clk.h>
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/module.h>
@@ -387,10 +388,25 @@ static inline void au1200_usb_init(void)
 	udelay(1000);
 }
 
-static inline void au1000_usb_init(unsigned long rb, int reg)
+static inline int au1000_usb_init(unsigned long rb, int reg)
 {
 	void __iomem *base = (void __iomem *)KSEG1ADDR(rb + reg);
 	unsigned long r = __raw_readl(base);
+	struct clk *c;
+
+	/* 48MHz check. Don't init if no one can provide it */
+	c = clk_get(NULL, "usbh_clk");
+	if (IS_ERR(c))
+		return -ENODEV;
+	if (clk_round_rate(c, 48000000) != 48000000) {
+		clk_put(c);
+		return -ENODEV;
+	}
+	if (clk_set_rate(c, 48000000)) {
+		clk_put(c);
+		return -ENODEV;
+	}
+	clk_put(c);
 
 #if defined(__BIG_ENDIAN)
 	r |= USBHEN_BE;
@@ -400,6 +416,8 @@ static inline void au1000_usb_init(unsigned long rb, int reg)
 	__raw_writel(r, base);
 	wmb();
 	udelay(1000);
+
+	return 0;
 }
 
 
@@ -407,8 +425,15 @@ static inline void __au1xx0_ohci_control(int enable, unsigned long rb, int creg)
 {
 	void __iomem *base = (void __iomem *)KSEG1ADDR(rb);
 	unsigned long r = __raw_readl(base + creg);
+	struct clk *c = clk_get(NULL, "usbh_clk");
+
+	if (IS_ERR(c))
+		return;
 
 	if (enable) {
+		if (clk_prepare_enable(c))
+			goto out;
+
 		__raw_writel(r | USBHEN_CE, base + creg);
 		wmb();
 		udelay(1000);
@@ -423,7 +448,10 @@ static inline void __au1xx0_ohci_control(int enable, unsigned long rb, int creg)
 	} else {
 		__raw_writel(r & ~(USBHEN_CE | USBHEN_E), base + creg);
 		wmb();
+		clk_disable_unprepare(c);
 	}
+out:
+	clk_put(c);
 }
 
 static inline int au1000_usb_control(int block, int enable, unsigned long rb,
@@ -457,11 +485,11 @@ int alchemy_usb_control(int block, int enable)
 	case ALCHEMY_CPU_AU1500:
 	case ALCHEMY_CPU_AU1100:
 		ret = au1000_usb_control(block, enable,
-				AU1000_USB_OHCI_PHYS_ADDR, AU1000_OHCICFG);
+			AU1000_USB_OHCI_PHYS_ADDR, AU1000_OHCICFG);
 		break;
 	case ALCHEMY_CPU_AU1550:
 		ret = au1000_usb_control(block, enable,
-				AU1550_USB_OHCI_PHYS_ADDR, AU1550_OHCICFG);
+			AU1550_USB_OHCI_PHYS_ADDR, AU1550_OHCICFG);
 		break;
 	case ALCHEMY_CPU_AU1200:
 		ret = au1200_usb_control(block, enable);
@@ -569,14 +597,18 @@ static struct syscore_ops alchemy_usb_pm_ops = {
 
 static int __init alchemy_usb_init(void)
 {
+	int ret = 0;
+
 	switch (alchemy_get_cputype()) {
 	case ALCHEMY_CPU_AU1000:
 	case ALCHEMY_CPU_AU1500:
 	case ALCHEMY_CPU_AU1100:
-		au1000_usb_init(AU1000_USB_OHCI_PHYS_ADDR, AU1000_OHCICFG);
+		ret = au1000_usb_init(AU1000_USB_OHCI_PHYS_ADDR,
+				      AU1000_OHCICFG);
 		break;
 	case ALCHEMY_CPU_AU1550:
-		au1000_usb_init(AU1550_USB_OHCI_PHYS_ADDR, AU1550_OHCICFG);
+		ret = au1000_usb_init(AU1550_USB_OHCI_PHYS_ADDR,
+				      AU1550_OHCICFG);
 		break;
 	case ALCHEMY_CPU_AU1200:
 		au1200_usb_init();
@@ -586,8 +618,9 @@ static int __init alchemy_usb_init(void)
 		break;
 	}
 
-	register_syscore_ops(&alchemy_usb_pm_ops);
+	if (!ret)
+		register_syscore_ops(&alchemy_usb_pm_ops);
 
-	return 0;
+	return ret;
 }
 arch_initcall(alchemy_usb_init);
-- 
2.0.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 04/10] MIPS: Alchemy: pci: use clk framework to enable PCI clock
  2014-07-23 14:36 [PATCH 00/10] MIPS: Alchemy: common clk framework support Manuel Lauss
                   ` (2 preceding siblings ...)
  2014-07-23 14:36 ` [PATCH 03/10] MIPS: Alchemy: usb: use clk framework Manuel Lauss
@ 2014-07-23 14:36 ` Manuel Lauss
  2014-07-23 14:36 ` [PATCH 05/10] MIPS: Alchemy: db1x00: use clk framework Manuel Lauss
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Manuel Lauss @ 2014-07-23 14:36 UTC (permalink / raw)
  To: Linux-MIPS; +Cc: Manuel Lauss

Use the clock framework to get at the PCI clock source and enable
it on driver initialization.

Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
---
 arch/mips/pci/pci-alchemy.c | 24 +++++++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)

diff --git a/arch/mips/pci/pci-alchemy.c b/arch/mips/pci/pci-alchemy.c
index 563d1f6..c19600a 100644
--- a/arch/mips/pci/pci-alchemy.c
+++ b/arch/mips/pci/pci-alchemy.c
@@ -7,6 +7,7 @@
  * Support for all devices (greater than 16) added by David Gathright.
  */
 
+#include <linux/clk.h>
 #include <linux/export.h>
 #include <linux/types.h>
 #include <linux/pci.h>
@@ -364,6 +365,7 @@ static int alchemy_pci_probe(struct platform_device *pdev)
 	void __iomem *virt_io;
 	unsigned long val;
 	struct resource *r;
+	struct clk *c;
 	int ret;
 
 	/* need at least PCI IRQ mapping table */
@@ -393,11 +395,24 @@ static int alchemy_pci_probe(struct platform_device *pdev)
 		goto out1;
 	}
 
+	c = clk_get(&pdev->dev, "pci_clko");
+	if (IS_ERR(c)) {
+		dev_err(&pdev->dev, "unable to find PCI clock\n");
+		ret = PTR_ERR(c);
+		goto out2;
+	}
+
+	ret = clk_prepare_enable(c);
+	if (ret) {
+		dev_err(&pdev->dev, "cannot enable PCI clock\n");
+		goto out6;
+	}
+
 	ctx->regs = ioremap_nocache(r->start, resource_size(r));
 	if (!ctx->regs) {
 		dev_err(&pdev->dev, "cannot map pci regs\n");
 		ret = -ENODEV;
-		goto out2;
+		goto out5;
 	}
 
 	/* map parts of the PCI IO area */
@@ -465,12 +480,19 @@ static int alchemy_pci_probe(struct platform_device *pdev)
 	register_syscore_ops(&alchemy_pci_pmops);
 	register_pci_controller(&ctx->alchemy_pci_ctrl);
 
+	dev_info(&pdev->dev, "PCI controller at %ld MHz\n",
+		 clk_get_rate(c) / 1000000);
+
 	return 0;
 
 out4:
 	iounmap(virt_io);
 out3:
 	iounmap(ctx->regs);
+out5:
+	clk_disable_unprepare(c);
+out6:
+	clk_put(c);
 out2:
 	release_mem_region(r->start, resource_size(r));
 out1:
-- 
2.0.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 05/10] MIPS: Alchemy: db1x00: use clk framework
  2014-07-23 14:36 [PATCH 00/10] MIPS: Alchemy: common clk framework support Manuel Lauss
                   ` (3 preceding siblings ...)
  2014-07-23 14:36 ` [PATCH 04/10] MIPS: Alchemy: pci: use clk framework to enable PCI clock Manuel Lauss
@ 2014-07-23 14:36 ` Manuel Lauss
  2014-07-23 14:36 ` [PATCH 06/10] MIPS: Alchemy: irda: " Manuel Lauss
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Manuel Lauss @ 2014-07-23 14:36 UTC (permalink / raw)
  To: Linux-MIPS; +Cc: Manuel Lauss

Make use of the clk framework to set up and enable all PSC clocks.

Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
---
 arch/mips/alchemy/devboards/db1200.c | 50 ++++++++++++++++++------------------
 arch/mips/alchemy/devboards/db1300.c |  7 +++++
 arch/mips/alchemy/devboards/db1550.c | 13 ++++++++++
 3 files changed, 45 insertions(+), 25 deletions(-)

diff --git a/arch/mips/alchemy/devboards/db1200.c b/arch/mips/alchemy/devboards/db1200.c
index 5ccfd83..7761889 100644
--- a/arch/mips/alchemy/devboards/db1200.c
+++ b/arch/mips/alchemy/devboards/db1200.c
@@ -18,6 +18,7 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
+#include <linux/clk.h>
 #include <linux/dma-mapping.h>
 #include <linux/gpio.h>
 #include <linux/i2c.h>
@@ -129,7 +130,6 @@ static int __init db1200_detect_board(void)
 
 int __init db1200_board_setup(void)
 {
-	unsigned long freq0, clksrc, div, pfc;
 	unsigned short whoami;
 
 	if (db1200_detect_board())
@@ -149,30 +149,6 @@ int __init db1200_board_setup(void)
 		"  Board-ID %d	Daughtercard ID %d\n", get_system_type(),
 		(whoami >> 4) & 0xf, (whoami >> 8) & 0xf, whoami & 0xf);
 
-	/* SMBus/SPI on PSC0, Audio on PSC1 */
-	pfc = alchemy_rdsys(AU1000_SYS_PINFUNC);
-	pfc &= ~(SYS_PINFUNC_P0A | SYS_PINFUNC_P0B);
-	pfc &= ~(SYS_PINFUNC_P1A | SYS_PINFUNC_P1B | SYS_PINFUNC_FS3);
-	pfc |= SYS_PINFUNC_P1C; /* SPI is configured later */
-	alchemy_wrsys(pfc, AU1000_SYS_PINFUNC);
-
-	/* Clock configurations: PSC0: ~50MHz via Clkgen0, derived from
-	 * CPU clock; all other clock generators off/unused.
-	 */
-	div = (get_au1x00_speed() + 25000000) / 50000000;
-	if (div & 1)
-		div++;
-	div = ((div >> 1) - 1) & 0xff;
-
-	freq0 = div << SYS_FC_FRDIV0_BIT;
-	alchemy_wrsys(freq0, AU1000_SYS_FREQCTRL0);
-	freq0 |= SYS_FC_FE0;	/* enable F0 */
-	alchemy_wrsys(freq0, AU1000_SYS_FREQCTRL0);
-
-	/* psc0_intclk comes 1:1 from F0 */
-	clksrc = SYS_CS_MUX_FQ0 << SYS_CS_ME0_BIT;
-	alchemy_wrsys(clksrc, AU1000_SYS_CLKSRC);
-
 	return 0;
 }
 
@@ -843,6 +819,7 @@ int __init db1200_dev_setup(void)
 	unsigned long pfc;
 	unsigned short sw;
 	int swapped, bid;
+	struct clk *c;
 
 	bid = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI));
 	if ((bid == BCSR_WHOAMI_PB1200_DDR1) ||
@@ -855,6 +832,24 @@ int __init db1200_dev_setup(void)
 	irq_set_irq_type(AU1200_GPIO7_INT, IRQ_TYPE_LEVEL_LOW);
 	bcsr_init_irq(DB1200_INT_BEGIN, DB1200_INT_END, AU1200_GPIO7_INT);
 
+	/* SMBus/SPI on PSC0, Audio on PSC1 */
+	pfc = alchemy_rdsys(AU1000_SYS_PINFUNC);
+	pfc &= ~(SYS_PINFUNC_P0A | SYS_PINFUNC_P0B);
+	pfc &= ~(SYS_PINFUNC_P1A | SYS_PINFUNC_P1B | SYS_PINFUNC_FS3);
+	pfc |= SYS_PINFUNC_P1C; /* SPI is configured later */
+	alchemy_wrsys(pfc, AU1000_SYS_PINFUNC);
+
+	/* get 50MHz for I2C driver on PSC0 */
+	c = clk_get(NULL, "psc0_intclk");
+	if (!IS_ERR(c)) {
+		pfc = clk_round_rate(c, 50000000);
+		if ((pfc < 1) || (abs(50000000 - pfc) > 2500000))
+			pr_warn("DB1200: cant get I2C close to 50MHz\n");
+		else
+			clk_set_rate(c, pfc);
+		clk_put(c);
+	}
+
 	/* insert/eject pairs: one of both is always screaming.	 To avoid
 	 * issues they must not be automatically enabled when initially
 	 * requested.
@@ -927,6 +922,11 @@ int __init db1200_dev_setup(void)
 	}
 
 	/* Audio PSC clock is supplied externally. (FIXME: platdata!!) */
+	c = clk_get(NULL, "psc1_intclk");
+	if (!IS_ERR(c)) {
+		clk_prepare_enable(c);
+		clk_put(c);
+	}
 	__raw_writel(PSC_SEL_CLK_SERCLK,
 	    (void __iomem *)KSEG1ADDR(AU1550_PSC1_PHYS_ADDR) + PSC_SEL_OFFSET);
 	wmb();
diff --git a/arch/mips/alchemy/devboards/db1300.c b/arch/mips/alchemy/devboards/db1300.c
index e0ed9b9..00ce895 100644
--- a/arch/mips/alchemy/devboards/db1300.c
+++ b/arch/mips/alchemy/devboards/db1300.c
@@ -4,6 +4,7 @@
  * (c) 2009 Manuel Lauss <manuel.lauss@googlemail.com>
  */
 
+#include <linux/clk.h>
 #include <linux/dma-mapping.h>
 #include <linux/gpio.h>
 #include <linux/gpio_keys.h>
@@ -771,6 +772,7 @@ static struct platform_device *db1300_dev[] __initdata = {
 int __init db1300_dev_setup(void)
 {
 	int swapped, cpldirq;
+	struct clk *c;
 
 	/* setup CPLD IRQ muxer */
 	cpldirq = au1300_gpio_to_irq(AU1300_PIN_EXTCLK1);
@@ -804,6 +806,11 @@ int __init db1300_dev_setup(void)
 	    (void __iomem *)KSEG1ADDR(AU1300_PSC2_PHYS_ADDR) + PSC_SEL_OFFSET);
 	wmb();
 	/* I2C uses internal 48MHz EXTCLK1 */
+	c = clk_get(NULL, "psc3_intclk");
+	if (!IS_ERR(c)) {
+		clk_prepare_enable(c);
+		clk_put(c);
+	}
 	__raw_writel(PSC_SEL_CLK_INTCLK,
 	    (void __iomem *)KSEG1ADDR(AU1300_PSC3_PHYS_ADDR) + PSC_SEL_OFFSET);
 	wmb();
diff --git a/arch/mips/alchemy/devboards/db1550.c b/arch/mips/alchemy/devboards/db1550.c
index d132066..7e89936 100644
--- a/arch/mips/alchemy/devboards/db1550.c
+++ b/arch/mips/alchemy/devboards/db1550.c
@@ -4,6 +4,7 @@
  * (c) 2011 Manuel Lauss <manuel.lauss@googlemail.com>
  */
 
+#include <linux/clk.h>
 #include <linux/dma-mapping.h>
 #include <linux/gpio.h>
 #include <linux/i2c.h>
@@ -574,6 +575,7 @@ static void __init pb1550_devices(void)
 int __init db1550_dev_setup(void)
 {
 	int swapped, id;
+	struct clk *c;
 
 	id = (BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI)) != BCSR_WHOAMI_DB1550);
 
@@ -582,6 +584,17 @@ int __init db1550_dev_setup(void)
 	spi_register_board_info(db1550_spi_devs,
 				ARRAY_SIZE(db1550_i2c_devs));
 
+	c = clk_get(NULL, "psc0_intclk");
+	if (!IS_ERR(c)) {
+		clk_prepare_enable(c);
+		clk_put(c);
+	}
+	c = clk_get(NULL, "psc2_intclk");
+	if (!IS_ERR(c)) {
+		clk_prepare_enable(c);
+		clk_put(c);
+	}
+
 	/* Audio PSC clock is supplied by codecs (PSC1, 3) FIXME: platdata!! */
 	__raw_writel(PSC_SEL_CLK_SERCLK,
 	    (void __iomem *)KSEG1ADDR(AU1550_PSC1_PHYS_ADDR) + PSC_SEL_OFFSET);
-- 
2.0.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 06/10] MIPS: Alchemy: irda: use clk framework
  2014-07-23 14:36 [PATCH 00/10] MIPS: Alchemy: common clk framework support Manuel Lauss
                   ` (4 preceding siblings ...)
  2014-07-23 14:36 ` [PATCH 05/10] MIPS: Alchemy: db1x00: use clk framework Manuel Lauss
@ 2014-07-23 14:36 ` Manuel Lauss
  2014-07-23 14:36 ` [PATCH 07/10] MIPS: Alchemy: au1100fb: " Manuel Lauss
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Manuel Lauss @ 2014-07-23 14:36 UTC (permalink / raw)
  To: Linux-MIPS; +Cc: Manuel Lauss

Test the existence of the irda_clk clock object, use it to en/dis-
able it when date is being transferred.

Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
---
 drivers/net/irda/au1k_ir.c | 48 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 46 insertions(+), 2 deletions(-)

diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c
index 5f91e3e..aab2cf7 100644
--- a/drivers/net/irda/au1k_ir.c
+++ b/drivers/net/irda/au1k_ir.c
@@ -18,6 +18,7 @@
  *  with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/clk.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
 #include <linux/interrupt.h>
@@ -175,6 +176,7 @@ struct au1k_private {
 
 	struct resource *ioarea;
 	struct au1k_irda_platform_data *platdata;
+	struct clk *irda_clk;
 };
 
 static int qos_mtt_bits = 0x07;  /* 1 ms or more */
@@ -514,9 +516,39 @@ static irqreturn_t au1k_irda_interrupt(int dummy, void *dev_id)
 static int au1k_init(struct net_device *dev)
 {
 	struct au1k_private *aup = netdev_priv(dev);
-	u32 enable, ring_address;
+	u32 enable, ring_address, phyck;
+	struct clk *c;
 	int i;
 
+	c = clk_get(NULL, "irda_clk");
+	if (IS_ERR(c))
+		return PTR_ERR(c);
+	i = clk_prepare_enable(c);
+	if (i) {
+		clk_put(c);
+		return i;
+	}
+
+	switch (clk_get_rate(c)) {
+	case 40000000:
+		phyck = IR_PHYCLK_40MHZ;
+		break;
+	case 48000000:
+		phyck = IR_PHYCLK_48MHZ;
+		break;
+	case 56000000:
+		phyck = IR_PHYCLK_56MHZ;
+		break;
+	case 64000000:
+		phyck = IR_PHYCLK_64MHZ;
+		break;
+	default:
+		clk_disable_unprepare(c);
+		clk_put(c);
+		return -EINVAL;
+	}
+	aup->irda_clk = c;
+
 	enable = IR_HC | IR_CE | IR_C;
 #ifndef CONFIG_CPU_LITTLE_ENDIAN
 	enable |= IR_BE;
@@ -545,7 +577,7 @@ static int au1k_init(struct net_device *dev)
 	irda_write(aup, IR_RING_SIZE,
 				(RING_SIZE_64 << 8) | (RING_SIZE_64 << 12));
 
-	irda_write(aup, IR_CONFIG_2, IR_PHYCLK_48MHZ | IR_ONE_PIN);
+	irda_write(aup, IR_CONFIG_2, phyck | IR_ONE_PIN);
 	irda_write(aup, IR_RING_ADDR_CMPR, 0);
 
 	au1k_irda_set_speed(dev, 9600);
@@ -619,6 +651,9 @@ static int au1k_irda_stop(struct net_device *dev)
 	free_irq(aup->irq_tx, dev);
 	free_irq(aup->irq_rx, dev);
 
+	clk_disable_unprepare(aup->irda_clk);
+	clk_put(aup->irda_clk);
+
 	return 0;
 }
 
@@ -853,6 +888,7 @@ static int au1k_irda_probe(struct platform_device *pdev)
 	struct au1k_private *aup;
 	struct net_device *dev;
 	struct resource *r;
+	struct clk *c;
 	int err;
 
 	dev = alloc_irdadev(sizeof(struct au1k_private));
@@ -886,6 +922,14 @@ static int au1k_irda_probe(struct platform_device *pdev)
 	if (!aup->ioarea)
 		goto out;
 
+	/* bail out early if clock doesn't exist */
+	c = clk_get(NULL, "irda_clk");
+	if (IS_ERR(c)) {
+		err = PTR_ERR(c);
+		goto out;
+	}
+	clk_put(c);
+
 	aup->iobase = ioremap_nocache(r->start, resource_size(r));
 	if (!aup->iobase)
 		goto out2;
-- 
2.0.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 07/10] MIPS: Alchemy: au1100fb: use clk framework
  2014-07-23 14:36 [PATCH 00/10] MIPS: Alchemy: common clk framework support Manuel Lauss
                   ` (5 preceding siblings ...)
  2014-07-23 14:36 ` [PATCH 06/10] MIPS: Alchemy: irda: " Manuel Lauss
@ 2014-07-23 14:36 ` Manuel Lauss
  2014-07-23 14:36 ` [PATCH 08/10] MIPS: Alchemy: au1200fb: " Manuel Lauss
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 11+ messages in thread
From: Manuel Lauss @ 2014-07-23 14:36 UTC (permalink / raw)
  To: Linux-MIPS; +Cc: Manuel Lauss

Use the clock framework to en/disable the clock to the au1100
framebuffer device.

Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
---
 arch/mips/alchemy/devboards/db1000.c | 14 ++++++++++++++
 drivers/video/fbdev/au1100fb.c       | 36 ++++++++++++++++++++++--------------
 drivers/video/fbdev/au1100fb.h       |  1 +
 3 files changed, 37 insertions(+), 14 deletions(-)

diff --git a/arch/mips/alchemy/devboards/db1000.c b/arch/mips/alchemy/devboards/db1000.c
index 8201f00..001102e 100644
--- a/arch/mips/alchemy/devboards/db1000.c
+++ b/arch/mips/alchemy/devboards/db1000.c
@@ -19,6 +19,7 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
+#include <linux/clk.h>
 #include <linux/dma-mapping.h>
 #include <linux/gpio.h>
 #include <linux/init.h>
@@ -496,6 +497,7 @@ int __init db1000_dev_setup(void)
 	int board = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI));
 	int c0, c1, d0, d1, s0, s1, flashsize = 32,  twosocks = 1;
 	unsigned long pfc;
+	struct clk *c, *p;
 
 	if (board == BCSR_WHOAMI_DB1500) {
 		c0 = AU1500_GPIO2_INT;
@@ -525,6 +527,18 @@ int __init db1000_dev_setup(void)
 		spi_register_board_info(db1100_spi_info,
 					ARRAY_SIZE(db1100_spi_info));
 
+		/* link LCD clock to AUXPLL */
+		p = clk_get(NULL, "auxpll_clk");
+		c = clk_get(NULL, "lcd_intclk");
+		if (!IS_ERR(c) && !IS_ERR(p)) {
+			clk_set_parent(c, p);
+			clk_set_rate(c, clk_get_rate(p));
+		}
+		if (!IS_ERR(c))
+			clk_put(c);
+		if (!IS_ERR(p))
+			clk_put(p);
+
 		platform_add_devices(db1100_devs, ARRAY_SIZE(db1100_devs));
 		platform_device_register(&db1100_spi_dev);
 	} else if (board == BCSR_WHOAMI_DB1000) {
diff --git a/drivers/video/fbdev/au1100fb.c b/drivers/video/fbdev/au1100fb.c
index c163424..0676746e 100644
--- a/drivers/video/fbdev/au1100fb.c
+++ b/drivers/video/fbdev/au1100fb.c
@@ -41,6 +41,7 @@
  *  with this program; if not, write  to the Free Software Foundation, Inc.,
  *  675 Mass Ave, Cambridge, MA 02139, USA.
  */
+#include <linux/clk.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -434,7 +435,7 @@ static int au1100fb_drv_probe(struct platform_device *dev)
 	struct au1100fb_device *fbdev = NULL;
 	struct resource *regs_res;
 	unsigned long page;
-	u32 sys_clksrc;
+	struct clk *c;
 
 	/* Allocate new device private */
 	fbdev = devm_kzalloc(&dev->dev, sizeof(struct au1100fb_device),
@@ -473,6 +474,13 @@ static int au1100fb_drv_probe(struct platform_device *dev)
 	print_dbg("Register memory map at %p", fbdev->regs);
 	print_dbg("phys=0x%08x, size=%d", fbdev->regs_phys, fbdev->regs_len);
 
+	c = clk_get(NULL, "lcd_intclk");
+	if (!IS_ERR(c)) {
+		fbdev->lcdclk = c;
+		clk_set_rate(c, 48000000);
+		clk_prepare_enable(c);
+	}
+
 	/* Allocate the framebuffer to the maximum screen size * nbr of video buffers */
 	fbdev->fb_len = fbdev->panel->xres * fbdev->panel->yres *
 		  	(fbdev->panel->bpp >> 3) * AU1100FB_NBR_VIDEO_BUFFERS;
@@ -506,11 +514,6 @@ static int au1100fb_drv_probe(struct platform_device *dev)
 	print_dbg("Framebuffer memory map at %p", fbdev->fb_mem);
 	print_dbg("phys=0x%08x, size=%dK", fbdev->fb_phys, fbdev->fb_len / 1024);
 
-	/* Setup LCD clock to AUX (48 MHz) */
-	sys_clksrc = alchemy_rdsys(AU1000_SYS_CLKSRC);
-	sys_clksrc &= ~(SYS_CS_ML_MASK | SYS_CS_DL | SYS_CS_CL);
-	alchemy_wrsys((sys_clksrc | (1 << SYS_CS_ML_BIT)), AU1000_SYS_CLKSRC);
-
 	/* load the panel info into the var struct */
 	au1100fb_var.bits_per_pixel = fbdev->panel->bpp;
 	au1100fb_var.xres = fbdev->panel->xres;
@@ -547,6 +550,10 @@ static int au1100fb_drv_probe(struct platform_device *dev)
 	return 0;
 
 failed:
+	if (fbdev->lcdclk) {
+		clk_disable_unprepare(fbdev->lcdclk);
+		clk_put(fbdev->lcdclk);
+	}
 	if (fbdev->fb_mem) {
 		dma_free_noncoherent(&dev->dev, fbdev->fb_len, fbdev->fb_mem,
 				     fbdev->fb_phys);
@@ -577,11 +584,15 @@ int au1100fb_drv_remove(struct platform_device *dev)
 
 	fb_dealloc_cmap(&fbdev->info.cmap);
 
+	if (fbdev->lcdclk) {
+		clk_disable_unprepare(fbdev->lcdclk);
+		clk_put(fbdev->lcdclk);
+	}
+
 	return 0;
 }
 
 #ifdef CONFIG_PM
-static u32 sys_clksrc;
 static struct au1100fb_regs fbregs;
 
 int au1100fb_drv_suspend(struct platform_device *dev, pm_message_t state)
@@ -591,14 +602,11 @@ int au1100fb_drv_suspend(struct platform_device *dev, pm_message_t state)
 	if (!fbdev)
 		return 0;
 
-	/* Save the clock source state */
-	sys_clksrc = alchemy_rdsys(AU1000_SYS_CLKSRC);
-
 	/* Blank the LCD */
 	au1100fb_fb_blank(VESA_POWERDOWN, &fbdev->info);
 
-	/* Stop LCD clocking */
-	alchemy_wrsys(sys_clksrc & ~SYS_CS_ML_MASK, AU1000_SYS_CLKSRC);
+	if (fbdev->lcdclk)
+		clk_disable(fbdev->lcdclk);
 
 	memcpy(&fbregs, fbdev->regs, sizeof(struct au1100fb_regs));
 
@@ -614,8 +622,8 @@ int au1100fb_drv_resume(struct platform_device *dev)
 
 	memcpy(fbdev->regs, &fbregs, sizeof(struct au1100fb_regs));
 
-	/* Restart LCD clocking */
-	alchemy_wrsys(sys_clksrc, AU1000_SYS_CLKSRC);
+	if (fbdev->lcdclk)
+		clk_enable(fbdev->lcdclk);
 
 	/* Unblank the LCD */
 	au1100fb_fb_blank(VESA_NO_BLANKING, &fbdev->info);
diff --git a/drivers/video/fbdev/au1100fb.h b/drivers/video/fbdev/au1100fb.h
index 12d9642..9af1993 100644
--- a/drivers/video/fbdev/au1100fb.h
+++ b/drivers/video/fbdev/au1100fb.h
@@ -109,6 +109,7 @@ struct au1100fb_device {
 	size_t	      		fb_len;
 	dma_addr_t    		fb_phys;
 	int			panel_idx;
+	struct clk		*lcdclk;
 };
 
 /********************************************************************/
-- 
2.0.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 08/10] MIPS: Alchemy: au1200fb: use clk framework
  2014-07-23 14:36 [PATCH 00/10] MIPS: Alchemy: common clk framework support Manuel Lauss
                   ` (6 preceding siblings ...)
  2014-07-23 14:36 ` [PATCH 07/10] MIPS: Alchemy: au1100fb: " Manuel Lauss
@ 2014-07-23 14:36 ` Manuel Lauss
  2014-07-23 14:36 ` [PATCH 09/10] MIPS: Alchemy: au1xmmc: " Manuel Lauss
  2014-07-23 14:36 ` [PATCH 10/10] MIPS: Alchemy: remove old clock support Manuel Lauss
  9 siblings, 0 replies; 11+ messages in thread
From: Manuel Lauss @ 2014-07-23 14:36 UTC (permalink / raw)
  To: Linux-MIPS; +Cc: Manuel Lauss

minimal patch to replace direct clock register hackery with clock
framework calls.

Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
---
 drivers/video/fbdev/au1200fb.c | 50 +++++++++++++++++++-----------------------
 1 file changed, 23 insertions(+), 27 deletions(-)

diff --git a/drivers/video/fbdev/au1200fb.c b/drivers/video/fbdev/au1200fb.c
index 1c8e106..40494db 100644
--- a/drivers/video/fbdev/au1200fb.c
+++ b/drivers/video/fbdev/au1200fb.c
@@ -30,6 +30,7 @@
  *  675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include <linux/clk.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/kernel.h>
@@ -330,9 +331,8 @@ struct panel_settings
 	uint32 mode_pwmhi;
 	uint32 mode_outmask;
 	uint32 mode_fifoctrl;
-	uint32 mode_toyclksrc;
 	uint32 mode_backlight;
-	uint32 mode_auxpll;
+	uint32 lcdclk;
 #define Xres min_xres
 #define Yres min_yres
 	u32	min_xres;		/* Minimum horizontal resolution */
@@ -379,9 +379,8 @@ static struct panel_settings known_lcd_panels[] =
 		.mode_pwmhi		= 0x00000000,
 		.mode_outmask	= 0x00FFFFFF,
 		.mode_fifoctrl	= 0x2f2f2f2f,
-		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
 		.mode_backlight	= 0x00000000,
-		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.lcdclk		= 96,
 		320, 320,
 		240, 240,
 	},
@@ -407,9 +406,8 @@ static struct panel_settings known_lcd_panels[] =
 		.mode_pwmhi		= 0x00000000,
 		.mode_outmask	= 0x00FFFFFF,
 		.mode_fifoctrl	= 0x2f2f2f2f,
-		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
 		.mode_backlight	= 0x00000000,
-		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.lcdclk		= 96,
 		640, 480,
 		640, 480,
 	},
@@ -435,9 +433,8 @@ static struct panel_settings known_lcd_panels[] =
 		.mode_pwmhi		= 0x00000000,
 		.mode_outmask	= 0x00FFFFFF,
 		.mode_fifoctrl	= 0x2f2f2f2f,
-		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
 		.mode_backlight	= 0x00000000,
-		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.lcdclk		= 96,
 		800, 800,
 		600, 600,
 	},
@@ -463,9 +460,8 @@ static struct panel_settings known_lcd_panels[] =
 		.mode_pwmhi		= 0x00000000,
 		.mode_outmask	= 0x00FFFFFF,
 		.mode_fifoctrl	= 0x2f2f2f2f,
-		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
 		.mode_backlight	= 0x00000000,
-		.mode_auxpll		= 6, /* 72MHz AUXPLL */
+		.lcdclk		= 72,
 		1024, 1024,
 		768, 768,
 	},
@@ -491,9 +487,8 @@ static struct panel_settings known_lcd_panels[] =
 		.mode_pwmhi		= 0x00000000,
 		.mode_outmask	= 0x00FFFFFF,
 		.mode_fifoctrl	= 0x2f2f2f2f,
-		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
 		.mode_backlight	= 0x00000000,
-		.mode_auxpll		= 10, /* 120MHz AUXPLL */
+		.lcdclk		= 120,
 		1280, 1280,
 		1024, 1024,
 	},
@@ -519,9 +514,8 @@ static struct panel_settings known_lcd_panels[] =
 		.mode_pwmhi		= 0x03400000, /* SCB 0x0 */
 		.mode_outmask	= 0x00FFFFFF,
 		.mode_fifoctrl	= 0x2f2f2f2f,
-		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
 		.mode_backlight	= 0x00000000,
-		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.lcdclk		= 96,
 		1024, 1024,
 		768, 768,
 	},
@@ -550,9 +544,8 @@ static struct panel_settings known_lcd_panels[] =
 		.mode_pwmhi		= 0x03400000,
 		.mode_outmask	= 0x00fcfcfc,
 		.mode_fifoctrl	= 0x2f2f2f2f,
-		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
 		.mode_backlight	= 0x00000000,
-		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.lcdclk		= 96,
 		640, 480,
 		640, 480,
 	},
@@ -581,9 +574,8 @@ static struct panel_settings known_lcd_panels[] =
 		.mode_pwmhi		= 0x03400000,
 		.mode_outmask	= 0x00fcfcfc,
 		.mode_fifoctrl	= 0x2f2f2f2f,
-		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
 		.mode_backlight	= 0x00000000,
-		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.lcdclk		= 96, /* 96MHz AUXPLL */
 		320, 320,
 		240, 240,
 	},
@@ -612,9 +604,8 @@ static struct panel_settings known_lcd_panels[] =
 		.mode_pwmhi		= 0x03400000,
 		.mode_outmask	= 0x00fcfcfc,
 		.mode_fifoctrl	= 0x2f2f2f2f,
-		.mode_toyclksrc	= 0x00000004, /* AUXPLL directly */
 		.mode_backlight	= 0x00000000,
-		.mode_auxpll		= 8, /* 96MHz AUXPLL */
+		.lcdclk		= 96,
 		856, 856,
 		480, 480,
 	},
@@ -646,9 +637,8 @@ static struct panel_settings known_lcd_panels[] =
 		.mode_pwmhi		= 0x00000000,
 		.mode_outmask		= 0x00FFFFFF,
 		.mode_fifoctrl		= 0x2f2f2f2f,
-		.mode_toyclksrc		= 0x00000004, /* AUXPLL directly */
 		.mode_backlight		= 0x00000000,
-		.mode_auxpll		= (48/12) * 2,
+		.lcdclk			= 96,
 		800, 800,
 		480, 480,
 	},
@@ -828,11 +818,17 @@ static void au1200_setpanel(struct panel_settings *newpanel,
 	 */
 	if (!(panel->mode_clkcontrol & LCD_CLKCONTROL_EXT))
 	{
-		uint32 sys_clksrc;
-		alchemy_wrsys(panel->mode_auxpll, AU1000_SYS_AUXPLL);
-		sys_clksrc = alchemy_rdsys(AU1000_SYS_CLKSRC) & ~0x0000001f;
-		sys_clksrc |= panel->mode_toyclksrc;
-		alchemy_wrsys(sys_clksrc, AU1000_SYS_CLKSRC);
+		struct clk *c = clk_get(NULL, "lcd_intclk");
+		long r, pc = panel->lcdclk * 1000000;
+
+		if (!IS_ERR(c)) {
+			r = clk_round_rate(c, pc);
+			if ((pc - r) < (pc / 10)) {	/* 10% slack */
+				clk_set_rate(c, r);
+				clk_prepare_enable(c);
+			}
+			clk_put(c);
+		}
 	}
 
 	/*
-- 
2.0.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 09/10] MIPS: Alchemy: au1xmmc: use clk framework
  2014-07-23 14:36 [PATCH 00/10] MIPS: Alchemy: common clk framework support Manuel Lauss
                   ` (7 preceding siblings ...)
  2014-07-23 14:36 ` [PATCH 08/10] MIPS: Alchemy: au1200fb: " Manuel Lauss
@ 2014-07-23 14:36 ` Manuel Lauss
  2014-07-23 14:36 ` [PATCH 10/10] MIPS: Alchemy: remove old clock support Manuel Lauss
  9 siblings, 0 replies; 11+ messages in thread
From: Manuel Lauss @ 2014-07-23 14:36 UTC (permalink / raw)
  To: Linux-MIPS; +Cc: Manuel Lauss

Use the clock framework to get the peripheral clock rate to
correctly set the MMC/SD bus clock divider.

Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
---
 drivers/mmc/host/au1xmmc.c | 31 +++++++++++++++++++++----------
 1 file changed, 21 insertions(+), 10 deletions(-)

diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c
index 2988e9d..9c9f6af 100644
--- a/drivers/mmc/host/au1xmmc.c
+++ b/drivers/mmc/host/au1xmmc.c
@@ -32,6 +32,7 @@
  * (the low to high transition will not occur).
  */
 
+#include <linux/clk.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
@@ -118,6 +119,7 @@ struct au1xmmc_host {
 	struct au1xmmc_platform_data *platdata;
 	struct platform_device *pdev;
 	struct resource *ioarea;
+	struct clk *clk;
 };
 
 /* Status flags used by the host structure */
@@ -597,17 +599,10 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status)
 
 static void au1xmmc_set_clock(struct au1xmmc_host *host, int rate)
 {
-	unsigned int pbus = get_au1x00_speed();
-	unsigned int divisor;
+	unsigned int pbus = clk_get_rate(host->clk);
+	unsigned int divisor = ((pbus / rate) / 2) - 1;
 	u32 config;
 
-	/* From databook:
-	 * divisor = ((((cpuclock / sbus_divisor) / 2) / mmcclock) / 2) - 1
-	 */
-	pbus /= ((alchemy_rdsys(AU1000_SYS_POWERCTRL) & 0x3) + 2);
-	pbus /= 2;
-	divisor = ((pbus / rate) / 2) - 1;
-
 	config = __raw_readl(HOST_CONFIG(host));
 
 	config &= ~(SD_CONFIG_DIV);
@@ -1030,6 +1025,16 @@ static int au1xmmc_probe(struct platform_device *pdev)
 		goto out3;
 	}
 
+	host->clk = clk_get(&pdev->dev, ALCHEMY_PERIPH_CLK);
+	if (IS_ERR(host->clk)) {
+		dev_err(&pdev->dev, "cannot find clock\n");
+		goto out_irq;
+	}
+	if (clk_prepare_enable(host->clk)) {
+		dev_err(&pdev->dev, "cannot enable clock\n");
+		goto out_clk;
+	}
+
 	host->status = HOST_S_IDLE;
 
 	/* board-specific carddetect setup, if any */
@@ -1106,7 +1111,10 @@ out5:
 	if (host->platdata && host->platdata->cd_setup &&
 	    !(mmc->caps & MMC_CAP_NEEDS_POLL))
 		host->platdata->cd_setup(mmc, 0);
-
+out_clk:
+	clk_disable_unprepare(host->clk);
+	clk_put(host->clk);
+out_irq:
 	free_irq(host->irq, host);
 out3:
 	iounmap((void *)host->iobase);
@@ -1148,6 +1156,9 @@ static int au1xmmc_remove(struct platform_device *pdev)
 
 		au1xmmc_set_power(host, 0);
 
+		clk_disable_unprepare(host->clk);
+		clk_put(host->clk);
+
 		free_irq(host->irq, host);
 		iounmap((void *)host->iobase);
 		release_resource(host->ioarea);
-- 
2.0.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 10/10] MIPS: Alchemy: remove old clock support
  2014-07-23 14:36 [PATCH 00/10] MIPS: Alchemy: common clk framework support Manuel Lauss
                   ` (8 preceding siblings ...)
  2014-07-23 14:36 ` [PATCH 09/10] MIPS: Alchemy: au1xmmc: " Manuel Lauss
@ 2014-07-23 14:36 ` Manuel Lauss
  9 siblings, 0 replies; 11+ messages in thread
From: Manuel Lauss @ 2014-07-23 14:36 UTC (permalink / raw)
  To: Linux-MIPS; +Cc: Manuel Lauss

With the clock framework in place, remove unused functions and bits,
and drop the CLK_IGNORE_UNUSED flag, which is now unneeded.

Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
---
 arch/mips/alchemy/common/Makefile          |  2 +-
 arch/mips/alchemy/common/clock.c           | 10 ++--
 arch/mips/alchemy/common/clocks.c          | 86 ------------------------------
 arch/mips/alchemy/common/setup.c           | 15 ------
 arch/mips/include/asm/mach-au1x00/au1000.h | 69 ------------------------
 5 files changed, 5 insertions(+), 177 deletions(-)
 delete mode 100644 arch/mips/alchemy/common/clocks.c

diff --git a/arch/mips/alchemy/common/Makefile b/arch/mips/alchemy/common/Makefile
index c8dedcb..f64744f 100644
--- a/arch/mips/alchemy/common/Makefile
+++ b/arch/mips/alchemy/common/Makefile
@@ -5,7 +5,7 @@
 # Makefile for the Alchemy Au1xx0 CPUs, generic files.
 #
 
-obj-y += prom.o time.o clock.o clocks.o platform.o power.o \
+obj-y += prom.o time.o clock.o platform.o power.o \
 	 setup.o sleeper.o dma.o dbdma.o vss.o irq.o usb.o
 
 # optional gpiolib support
diff --git a/arch/mips/alchemy/common/clock.c b/arch/mips/alchemy/common/clock.c
index 3cd4118..d7557cd 100644
--- a/arch/mips/alchemy/common/clock.c
+++ b/arch/mips/alchemy/common/clock.c
@@ -151,7 +151,7 @@ static struct clk __init *alchemy_clk_setup_cpu(const char *parent_name,
 	id.name = ALCHEMY_CPU_CLK;
 	id.parent_names = &parent_name;
 	id.num_parents = 1;
-	id.flags = CLK_IS_BASIC | CLK_IGNORE_UNUSED;
+	id.flags = CLK_IS_BASIC;
 	id.ops = &alchemy_clkops_cpu;
 	h->init = &id;
 
@@ -236,7 +236,7 @@ static struct clk __init *alchemy_clk_setup_aux(const char *parent_name,
 	id.name = name;
 	id.parent_names = &parent_name;
 	id.num_parents = 1;
-	id.flags = CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED;
+	id.flags = CLK_GET_RATE_NOCACHE;
 	id.ops = &alchemy_clkops_aux;
 
 	a->reg = reg;
@@ -743,8 +743,7 @@ static int __init alchemy_clk_init_fgens(int ctype)
 	default:
 		return -ENODEV;
 	}
-	id.flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE |
-		   CLK_IGNORE_UNUSED;
+	id.flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE;
 
 	a = kzalloc((sizeof(*a)) * 6, GFP_KERNEL);
 	if (!a)
@@ -942,8 +941,7 @@ static int __init alchemy_clk_setup_imux(int ctype)
 	id.ops = &alchemy_clkops_csrc;
 	id.parent_names = (const char **)alchemy_clk_csrc_parents;
 	id.num_parents = 7;
-	id.flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE |
-		   CLK_IGNORE_UNUSED;
+	id.flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE;
 
 	dt = alchemy_csrc_dt1;
 	switch (ctype) {
diff --git a/arch/mips/alchemy/common/clocks.c b/arch/mips/alchemy/common/clocks.c
deleted file mode 100644
index a4c7cd7..0000000
--- a/arch/mips/alchemy/common/clocks.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * BRIEF MODULE DESCRIPTION
- *	Simple Au1xx0 clocks routines.
- *
- * Copyright 2001, 2008 MontaVista Software Inc.
- * Author: MontaVista Software, Inc. <source@mvista.com>
- *
- *  This program is free software; you can redistribute	 it and/or modify it
- *  under  the terms of	 the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the	License, or (at your
- *  option) any later version.
- *
- *  THIS  SOFTWARE  IS PROVIDED	  ``AS	IS'' AND   ANY	EXPRESS OR IMPLIED
- *  WARRANTIES,	  INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- *  NO	EVENT  SHALL   THE AUTHOR  BE	 LIABLE FOR ANY	  DIRECT, INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *  NOT LIMITED	  TO, PROCUREMENT OF  SUBSTITUTE GOODS	OR SERVICES; LOSS OF
- *  USE, DATA,	OR PROFITS; OR	BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- *  ANY THEORY OF LIABILITY, WHETHER IN	 CONTRACT, STRICT LIABILITY, OR TORT
- *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  You should have received a copy of the  GNU General Public License along
- *  with this program; if not, write  to the Free Software Foundation, Inc.,
- *  675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <asm/time.h>
-#include <asm/mach-au1x00/au1000.h>
-
-/*
- * I haven't found anyone that doesn't use a 12 MHz source clock,
- * but just in case.....
- */
-#define AU1000_SRC_CLK	12000000
-
-static unsigned int au1x00_clock; /*  Hz */
-
-/*
- * Set the au1000_clock
- */
-void set_au1x00_speed(unsigned int new_freq)
-{
-	au1x00_clock = new_freq;
-}
-
-unsigned int get_au1x00_speed(void)
-{
-	return au1x00_clock;
-}
-EXPORT_SYMBOL(get_au1x00_speed);
-
-/*
- * We read the real processor speed from the PLL.  This is important
- * because it is more accurate than computing it from the 32 KHz
- * counter, if it exists.  If we don't have an accurate processor
- * speed, all of the peripherals that derive their clocks based on
- * this advertised speed will introduce error and sometimes not work
- * properly.  This function is further convoluted to still allow configurations
- * to do that in case they have really, really old silicon with a
- * write-only PLL register.			-- Dan
- */
-unsigned long au1xxx_calc_clock(void)
-{
-	unsigned long cpu_speed;
-
-	/*
-	 * On early Au1000, sys_cpupll was write-only. Since these
-	 * silicon versions of Au1000 are not sold by AMD, we don't bend
-	 * over backwards trying to determine the frequency.
-	 */
-	if (au1xxx_cpu_has_pll_wo())
-		cpu_speed = 396000000;
-	else
-		cpu_speed = (alchemy_rdsys(AU1000_SYS_CPUPLL) & 0x3f) * AU1000_SRC_CLK;
-
-	/* On Alchemy CPU:counter ratio is 1:1 */
-	mips_hpt_frequency = cpu_speed;
-
-	set_au1x00_speed(cpu_speed);
-
-	return cpu_speed;
-}
diff --git a/arch/mips/alchemy/common/setup.c b/arch/mips/alchemy/common/setup.c
index 8267e3c..ea8f418 100644
--- a/arch/mips/alchemy/common/setup.c
+++ b/arch/mips/alchemy/common/setup.c
@@ -27,12 +27,9 @@
 
 #include <linux/init.h>
 #include <linux/ioport.h>
-#include <linux/jiffies.h>
-#include <linux/module.h>
 
 #include <asm/dma-coherence.h>
 #include <asm/mipsregs.h>
-#include <asm/time.h>
 
 #include <au1000.h>
 
@@ -41,18 +38,6 @@ extern void set_cpuspec(void);
 
 void __init plat_mem_setup(void)
 {
-	unsigned long est_freq;
-
-	/* determine core clock */
-	est_freq = au1xxx_calc_clock();
-	est_freq += 5000;    /* round */
-	est_freq -= est_freq % 10000;
-	printk(KERN_INFO "(PRId %08x) @ %lu.%02lu MHz\n", read_c0_prid(),
-	       est_freq / 1000000, ((est_freq % 1000000) * 100) / 1000000);
-
-	/* this is faster than wasting cycles trying to approximate it */
-	preset_lpj = (est_freq >> 1) / HZ;
-
 	if (au1xxx_cpu_needs_config_od())
 		/* Various early Au1xx0 errata corrected by this */
 		set_c0_config(1 << 19); /* Set Config[OD] */
diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h
index e77b920..a7eec33 100644
--- a/arch/mips/include/asm/mach-au1x00/au1000.h
+++ b/arch/mips/include/asm/mach-au1x00/au1000.h
@@ -470,72 +470,8 @@
 
 /* Clock Controller */
 #define AU1000_SYS_FREQCTRL0	0x20
-#  define SYS_FC_FRDIV2_BIT	22
-#  define SYS_FC_FRDIV2_MASK	(0xff << SYS_FC_FRDIV2_BIT)
-#  define SYS_FC_FE2		(1 << 21)
-#  define SYS_FC_FS2		(1 << 20)
-#  define SYS_FC_FRDIV1_BIT	12
-#  define SYS_FC_FRDIV1_MASK	(0xff << SYS_FC_FRDIV1_BIT)
-#  define SYS_FC_FE1		(1 << 11)
-#  define SYS_FC_FS1		(1 << 10)
-#  define SYS_FC_FRDIV0_BIT	2
-#  define SYS_FC_FRDIV0_MASK	(0xff << SYS_FC_FRDIV0_BIT)
-#  define SYS_FC_FE0		(1 << 1)
-#  define SYS_FC_FS0		(1 << 0)
 #define AU1000_SYS_FREQCTRL1	0x24
-#  define SYS_FC_FRDIV5_BIT	22
-#  define SYS_FC_FRDIV5_MASK	(0xff << SYS_FC_FRDIV5_BIT)
-#  define SYS_FC_FE5		(1 << 21)
-#  define SYS_FC_FS5		(1 << 20)
-#  define SYS_FC_FRDIV4_BIT	12
-#  define SYS_FC_FRDIV4_MASK	(0xff << SYS_FC_FRDIV4_BIT)
-#  define SYS_FC_FE4		(1 << 11)
-#  define SYS_FC_FS4		(1 << 10)
-#  define SYS_FC_FRDIV3_BIT	2
-#  define SYS_FC_FRDIV3_MASK	(0xff << SYS_FC_FRDIV3_BIT)
-#  define SYS_FC_FE3		(1 << 1)
-#  define SYS_FC_FS3		(1 << 0)
 #define AU1000_SYS_CLKSRC	0x28
-#  define SYS_CS_ME1_BIT	27
-#  define SYS_CS_ME1_MASK	(0x7 << SYS_CS_ME1_BIT)
-#  define SYS_CS_DE1		(1 << 26)
-#  define SYS_CS_CE1		(1 << 25)
-#  define SYS_CS_ME0_BIT	22
-#  define SYS_CS_ME0_MASK	(0x7 << SYS_CS_ME0_BIT)
-#  define SYS_CS_DE0		(1 << 21)
-#  define SYS_CS_CE0		(1 << 20)
-#  define SYS_CS_MI2_BIT	17
-#  define SYS_CS_MI2_MASK	(0x7 << SYS_CS_MI2_BIT)
-#  define SYS_CS_DI2		(1 << 16)
-#  define SYS_CS_CI2		(1 << 15)
-
-#  define SYS_CS_ML_BIT		7
-#  define SYS_CS_ML_MASK	(0x7 << SYS_CS_ML_BIT)
-#  define SYS_CS_DL		(1 << 6)
-#  define SYS_CS_CL		(1 << 5)
-
-#  define SYS_CS_MUH_BIT	12
-#  define SYS_CS_MUH_MASK	(0x7 << SYS_CS_MUH_BIT)
-#  define SYS_CS_DUH		(1 << 11)
-#  define SYS_CS_CUH		(1 << 10)
-#  define SYS_CS_MUD_BIT	7
-#  define SYS_CS_MUD_MASK	(0x7 << SYS_CS_MUD_BIT)
-#  define SYS_CS_DUD		(1 << 6)
-#  define SYS_CS_CUD		(1 << 5)
-
-#  define SYS_CS_MIR_BIT	2
-#  define SYS_CS_MIR_MASK	(0x7 << SYS_CS_MIR_BIT)
-#  define SYS_CS_DIR		(1 << 1)
-#  define SYS_CS_CIR		(1 << 0)
-
-#  define SYS_CS_MUX_AUX	0x1
-#  define SYS_CS_MUX_FQ0	0x2
-#  define SYS_CS_MUX_FQ1	0x3
-#  define SYS_CS_MUX_FQ2	0x4
-#  define SYS_CS_MUX_FQ3	0x5
-#  define SYS_CS_MUX_FQ4	0x6
-#  define SYS_CS_MUX_FQ5	0x7
-
 #define AU1000_SYS_CPUPLL	0x60
 #define AU1000_SYS_AUXPLL	0x64
 #define AU1300_SYS_AUXPLL2	0x68
@@ -841,11 +777,6 @@ static inline int alchemy_get_macs(int type)
 	return 0;
 }
 
-/* arch/mips/au1000/common/clocks.c */
-extern void set_au1x00_speed(unsigned int new_freq);
-extern unsigned int get_au1x00_speed(void);
-extern unsigned long au1xxx_calc_clock(void);
-
 /* PM: arch/mips/alchemy/common/sleeper.S, power.c, irq.c */
 void alchemy_sleep_au1000(void);
 void alchemy_sleep_au1550(void);
-- 
2.0.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2014-07-23 14:48 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-07-23 14:36 [PATCH 00/10] MIPS: Alchemy: common clk framework support Manuel Lauss
2014-07-23 14:36 ` [PATCH 01/10] MIPS: Alchemy: clock framework integration of onchip clocks Manuel Lauss
2014-07-23 14:36 ` [PATCH 02/10] MIPS: Alchemy: platform: use clk framework for uarts Manuel Lauss
2014-07-23 14:36 ` [PATCH 03/10] MIPS: Alchemy: usb: use clk framework Manuel Lauss
2014-07-23 14:36 ` [PATCH 04/10] MIPS: Alchemy: pci: use clk framework to enable PCI clock Manuel Lauss
2014-07-23 14:36 ` [PATCH 05/10] MIPS: Alchemy: db1x00: use clk framework Manuel Lauss
2014-07-23 14:36 ` [PATCH 06/10] MIPS: Alchemy: irda: " Manuel Lauss
2014-07-23 14:36 ` [PATCH 07/10] MIPS: Alchemy: au1100fb: " Manuel Lauss
2014-07-23 14:36 ` [PATCH 08/10] MIPS: Alchemy: au1200fb: " Manuel Lauss
2014-07-23 14:36 ` [PATCH 09/10] MIPS: Alchemy: au1xmmc: " Manuel Lauss
2014-07-23 14:36 ` [PATCH 10/10] MIPS: Alchemy: remove old clock support Manuel Lauss

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.