clk: x86: add support for Lynxpoint LPSS clocks

Intel Lynxpoint Low Power Subsystem hosts peripherals like UART, I2C and
SPI controllers. For most of these there is a configuration register that
allows software to enable and disable the functional clock. Disabling the
clock while the peripheral is not used saves power.

In order to take advantage of this we add a new clock gate of type
lpss_gate that just re-uses the ordinary clk_gate but in addition is able
to enumerate the base address register of the device using ACPI.

We then create a clock tree that models the Lynxpoint LPSS clocks using
these gates and fixed clocks so that we can pass clock rate to the drivers
as well.

Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Acked-by: Mike Turquette <mturquette@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
diff --git a/drivers/clk/x86/clk-lpt.c b/drivers/clk/x86/clk-lpt.c
new file mode 100644
index 0000000..81298ae
--- /dev/null
+++ b/drivers/clk/x86/clk-lpt.c
@@ -0,0 +1,86 @@
+/*
+ * Intel Lynxpoint LPSS clocks.
+ *
+ * Copyright (C) 2013, Intel Corporation
+ * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
+ *	    Heikki Krogerus <heikki.krogerus@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/acpi.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "clk-lpss.h"
+
+#define PRV_CLOCK_PARAMS 0x800
+
+static int lpt_clk_probe(struct platform_device *pdev)
+{
+	struct clk *clk;
+
+	/* LPSS free running clock */
+	clk = clk_register_fixed_rate(&pdev->dev, "lpss_clk", NULL, CLK_IS_ROOT,
+				      100000000);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	/* Shared DMA clock */
+	clk_register_clkdev(clk, "hclk", "INTL9C60.0.auto");
+
+	/* SPI clocks */
+	clk = clk_register_lpss_gate("spi0_clk", "lpss_clk", "INT33C0", NULL,
+				     PRV_CLOCK_PARAMS);
+	if (!IS_ERR(clk))
+		clk_register_clkdev(clk, NULL, "INT33C0:00");
+
+	clk = clk_register_lpss_gate("spi1_clk", "lpss_clk", "INT33C1", NULL,
+				     PRV_CLOCK_PARAMS);
+	if (!IS_ERR(clk))
+		clk_register_clkdev(clk, NULL, "INT33C1:00");
+
+	/* I2C clocks */
+	clk = clk_register_lpss_gate("i2c0_clk", "lpss_clk", "INT33C2", NULL,
+				     PRV_CLOCK_PARAMS);
+	if (!IS_ERR(clk))
+		clk_register_clkdev(clk, NULL, "INT33C2:00");
+
+	clk = clk_register_lpss_gate("i2c1_clk", "lpss_clk", "INT33C3", NULL,
+				     PRV_CLOCK_PARAMS);
+	if (!IS_ERR(clk))
+		clk_register_clkdev(clk, NULL, "INT33C3:00");
+
+	/* UART clocks */
+	clk = clk_register_lpss_gate("uart0_clk", "lpss_clk", "INT33C4", NULL,
+				     PRV_CLOCK_PARAMS);
+	if (!IS_ERR(clk))
+		clk_register_clkdev(clk, NULL, "INT33C4:00");
+
+	clk = clk_register_lpss_gate("uart1_clk", "lpss_clk", "INT33C5", NULL,
+				     PRV_CLOCK_PARAMS);
+	if (!IS_ERR(clk))
+		clk_register_clkdev(clk, NULL, "INT33C5:00");
+
+	return 0;
+}
+
+static struct platform_driver lpt_clk_driver = {
+	.driver = {
+		.name = "clk-lpt",
+		.owner = THIS_MODULE,
+	},
+	.probe = lpt_clk_probe,
+};
+
+static int __init lpt_clk_init(void)
+{
+	return platform_driver_register(&lpt_clk_driver);
+}
+arch_initcall(lpt_clk_init);