Quoting Mika Westerberg (2013-01-18 05:46:00) > 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@xxxxxxxxxxxxxxx> > Signed-off-by: Mika Westerberg <mika.westerberg@xxxxxxxxxxxxxxx> > Reviewed-by: Mark Brown <broonie@xxxxxxxxxxxxxxxxxxxxxxxxxxx> Nice to see another architecture using this framework. Acked-by: Mike Turquette <mturquette@xxxxxxxxxx> > --- > drivers/clk/Makefile | 1 + > drivers/clk/x86/Makefile | 2 + > drivers/clk/x86/clk-lpss.c | 99 ++++++++++++++++++++++++++++++++++++++++++++ > drivers/clk/x86/clk-lpss.h | 36 ++++++++++++++++ > drivers/clk/x86/clk-lpt.c | 86 ++++++++++++++++++++++++++++++++++++++ > 5 files changed, 224 insertions(+) > create mode 100644 drivers/clk/x86/Makefile > create mode 100644 drivers/clk/x86/clk-lpss.c > create mode 100644 drivers/clk/x86/clk-lpss.h > create mode 100644 drivers/clk/x86/clk-lpt.c > > diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile > index ee90e87..ee11460 100644 > --- a/drivers/clk/Makefile > +++ b/drivers/clk/Makefile > @@ -22,6 +22,7 @@ obj-$(CONFIG_ARCH_U8500) += ux500/ > obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o > obj-$(CONFIG_ARCH_SUNXI) += clk-sunxi.o > obj-$(CONFIG_ARCH_ZYNQ) += clk-zynq.o > +obj-$(CONFIG_X86) += x86/ > > # Chip specific > obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o > diff --git a/drivers/clk/x86/Makefile b/drivers/clk/x86/Makefile > new file mode 100644 > index 0000000..f9ba4fa > --- /dev/null > +++ b/drivers/clk/x86/Makefile > @@ -0,0 +1,2 @@ > +clk-x86-lpss-objs := clk-lpss.o clk-lpt.o > +obj-$(CONFIG_X86_INTEL_LPSS) += clk-x86-lpss.o > diff --git a/drivers/clk/x86/clk-lpss.c b/drivers/clk/x86/clk-lpss.c > new file mode 100644 > index 0000000..b5e229f > --- /dev/null > +++ b/drivers/clk/x86/clk-lpss.c > @@ -0,0 +1,99 @@ > +/* > + * Intel Low Power Subsystem clocks. > + * > + * Copyright (C) 2013, Intel Corporation > + * Authors: Mika Westerberg <mika.westerberg@xxxxxxxxxxxxxxx> > + * Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx> > + * > + * 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/clk-provider.h> > +#include <linux/err.h> > +#include <linux/io.h> > +#include <linux/module.h> > + > +static int clk_lpss_is_mmio_resource(struct acpi_resource *res, void *data) > +{ > + struct resource r; > + return !acpi_dev_resource_memory(res, &r); > +} > + > +static acpi_status clk_lpss_find_mmio(acpi_handle handle, u32 level, > + void *data, void **retval) > +{ > + struct resource_list_entry *rentry; > + struct list_head resource_list; > + struct acpi_device *adev; > + const char *uid = data; > + int ret; > + > + if (acpi_bus_get_device(handle, &adev)) > + return AE_OK; > + > + if (uid) { > + if (!adev->pnp.unique_id) > + return AE_OK; > + if (strcmp(uid, adev->pnp.unique_id)) > + return AE_OK; > + } > + > + INIT_LIST_HEAD(&resource_list); > + ret = acpi_dev_get_resources(adev, &resource_list, > + clk_lpss_is_mmio_resource, NULL); > + if (ret < 0) > + return AE_NO_MEMORY; > + > + list_for_each_entry(rentry, &resource_list, node) > + if (resource_type(&rentry->res) == IORESOURCE_MEM) { > + *(struct resource *)retval = rentry->res; > + break; > + } > + > + acpi_dev_free_resource_list(&resource_list); > + return AE_OK; > +} > + > +/** > + * clk_register_lpss_gate - register LPSS clock gate > + * @name: name of this clock gate > + * @parent_name: parent clock name > + * @hid: ACPI _HID of the device > + * @uid: ACPI _UID of the device (optional) > + * @offset: LPSS PRV_CLOCK_PARAMS offset > + * > + * Creates and registers LPSS clock gate. > + */ > +struct clk *clk_register_lpss_gate(const char *name, const char *parent_name, > + const char *hid, const char *uid, > + unsigned offset) > +{ > + struct resource res = { }; > + void __iomem *mmio_base; > + acpi_status status; > + struct clk *clk; > + > + /* > + * First try to look the device and its mmio resource from the > + * ACPI namespace. > + */ > + status = acpi_get_devices(hid, clk_lpss_find_mmio, (void *)uid, > + (void **)&res); > + if (ACPI_FAILURE(status) || !res.start) > + return ERR_PTR(-ENODEV); > + > + mmio_base = ioremap(res.start, resource_size(&res)); > + if (!mmio_base) > + return ERR_PTR(-ENOMEM); > + > + clk = clk_register_gate(NULL, name, parent_name, 0, mmio_base + offset, > + 0, 0, NULL); > + if (IS_ERR(clk)) > + iounmap(mmio_base); > + > + return clk; > +} > diff --git a/drivers/clk/x86/clk-lpss.h b/drivers/clk/x86/clk-lpss.h > new file mode 100644 > index 0000000..e9460f4 > --- /dev/null > +++ b/drivers/clk/x86/clk-lpss.h > @@ -0,0 +1,36 @@ > +/* > + * Intel Low Power Subsystem clock. > + * > + * Copyright (C) 2013, Intel Corporation > + * Authors: Mika Westerberg <mika.westerberg@xxxxxxxxxxxxxxx> > + * Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx> > + * > + * 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. > + */ > + > +#ifndef __CLK_LPSS_H > +#define __CLK_LPSS_H > + > +#include <linux/err.h> > +#include <linux/errno.h> > +#include <linux/clk.h> > + > +#ifdef CONFIG_ACPI > +extern struct clk *clk_register_lpss_gate(const char *name, > + const char *parent_name, > + const char *hid, const char *uid, > + unsigned offset); > +#else > +static inline struct clk *clk_register_lpss_gate(const char *name, > + const char *parent_name, > + const char *hid, > + const char *uid, > + unsigned offset) > +{ > + return ERR_PTR(-ENODEV); > +} > +#endif > + > +#endif /* __CLK_LPSS_H */ > 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@xxxxxxxxxxxxxxx> > + * Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx> > + * > + * 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); > -- > 1.7.10.4 -- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html