From: "Chang, Rebecca Swee Fun" <rebecca.swee.fun.ch...@intel.com>
clk/x86: Add clock framework support for Baytrail ACPI mode LPIO devices. The ACPI mode LPIO devices inclusive of SPI, HSUART, I2C and DMA. Signed-off-by: Chang, Rebecca Swee Fun <rebecca.swee.fun.ch...@intel.com> --- ...-clock-framework-support-for-Intel-Baytra.patch | 465 ++++++++++++++++++++ 1 file changed, 465 insertions(+) create mode 100644 meta/cfg/kernel-cache/features/valleyisland-io/0012-clk-x86-Add-clock-framework-support-for-Intel-Baytra.patch diff --git a/meta/cfg/kernel-cache/features/valleyisland-io/0012-clk-x86-Add-clock-framework-support-for-Intel-Baytra.patch b/meta/cfg/kernel-cache/features/valleyisland-io/0012-clk-x86-Add-clock-framework-support-for-Intel-Baytra.patch new file mode 100644 index 0000000..c52ba78 --- /dev/null +++ b/meta/cfg/kernel-cache/features/valleyisland-io/0012-clk-x86-Add-clock-framework-support-for-Intel-Baytra.patch @@ -0,0 +1,465 @@ +clk/x86: Add clock framework support for Valley Island ACPI mode LPIO devices. + +The ACPI mode LPIO devices inclusive of SPI, HSUART, I2C and DMA. + +Signed-off-by: Chang, Rebecca Swee Fun <rebecca.swee.fun.ch...@intel.com> +--- + drivers/clk/Makefile | 3 + + drivers/clk/x86/Makefile | 2 + + drivers/clk/x86/clk-byt.c | 94 ++++++++++++++++++++++++ + drivers/clk/x86/clk-lpss.c | 170 ++++++++++++++++++++++++++++++++++++++++++++ + drivers/clk/x86/clk-lpss.h | 47 ++++++++++++ + drivers/clk/x86/clk-lpt.c | 86 ++++++++++++++++++++++ + 6 files changed, 402 insertions(+) + create mode 100644 drivers/clk/x86/Makefile + create mode 100644 drivers/clk/x86/clk-byt.c + 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..cb7e4ed 100644 +--- a/drivers/clk/Makefile ++++ b/drivers/clk/Makefile +@@ -22,6 +22,9 @@ 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 ++ifeq ($(CONFIG_ACPI),y) ++obj-$(CONFIG_X86) += x86/ ++endif + + # 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..4deed96 +--- /dev/null ++++ b/drivers/clk/x86/Makefile +@@ -0,0 +1,2 @@ ++clk-x86-lpss-objs := clk-lpss.o clk-lpt.o clk-byt.o ++obj-$(CONFIG_X86_INTEL_LPSS) += clk-x86-lpss.o +diff --git a/drivers/clk/x86/clk-byt.c b/drivers/clk/x86/clk-byt.c +new file mode 100644 +index 0000000..209c1cb +--- /dev/null ++++ b/drivers/clk/x86/clk-byt.c +@@ -0,0 +1,94 @@ ++/* ++ * Intel BayTrail LPSS clocks. ++ * ++ * Copyright (C) 2013, Intel Corporation ++ * Author: Mika Westerberg <mika.westerb...@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/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 <asm/processor.h> ++ ++#include "clk-lpss.h" ++ ++#define PRV_CLOCK_PARAMS_SPI 0x400 ++#define PRV_CLOCK_PARAMS 0x800 ++ ++static int byt_clk_probe(struct platform_device *pdev) ++{ ++ struct clk *clk; ++ ++ /* SCC / LPSS free running clock */ ++ clk = clk_register_fixed_rate(NULL, "lpss_clk", NULL, CLK_IS_ROOT, ++ 100000000); ++ if (IS_ERR(clk)) ++ return PTR_ERR(clk); ++ ++ /* Shared DMA controllers */ ++ clk_register_clkdev(clk, "hclk", "INTL9C60.0.auto"); ++ clk_register_clkdev(clk, "hclk", "INTL9C60.1.auto"); ++ ++ /* SPI clock */ ++ clk = clk_register_fixed_rate(NULL, "spi_clk", "lpss_clk", 0, 50000000); ++ if (IS_ERR(clk)) ++ return PTR_ERR(clk); ++ ++ clk = clk_register_lpss_gate("spi0_clk", "spi_clk", "80860F0E", NULL, ++ PRV_CLOCK_PARAMS_SPI); ++ if (!IS_ERR(clk)) ++ clk_register_clkdev(clk, NULL, "80860F0E:00"); ++ ++ /* UART clock */ ++ clk = clk_register_fixed_rate(NULL, "uart_clk", "lpss_clk", 0, 44236800); ++ if (IS_ERR(clk)) ++ return PTR_ERR(clk); ++ ++ clk = clk_register_lpss_gate("uart0_clk", "uart_clk", "80860F0A", "1", ++ PRV_CLOCK_PARAMS); ++ if (!IS_ERR(clk)) ++ clk_register_clkdev(clk, NULL, "80860F0A:00"); ++ ++ clk = clk_register_lpss_gate("uart1_clk", "uart_clk", "80860F0A", "2", ++ PRV_CLOCK_PARAMS); ++ if (!IS_ERR(clk)) ++ clk_register_clkdev(clk, NULL, "80860F0A:01"); ++ ++ /* I2C clocks */ ++ clk = clk_register_fixed_rate(NULL, "i2c_100_clk", "lpss_clk", 0, ++ 100000000); ++ if (IS_ERR(clk)) ++ return PTR_ERR(clk); ++ ++ clk_register_clkdev(clk, NULL, "80860F41:00"); ++ clk_register_clkdev(clk, NULL, "80860F41:01"); ++ clk_register_clkdev(clk, NULL, "80860F41:02"); ++ clk_register_clkdev(clk, NULL, "80860F41:03"); ++ clk_register_clkdev(clk, NULL, "80860F41:04"); ++ clk_register_clkdev(clk, NULL, "80860F41:05"); ++ clk_register_clkdev(clk, NULL, "80860F41:06"); ++ ++ return 0; ++} ++ ++static struct platform_driver byt_clk_driver = { ++ .driver = { ++ .name = "clk-byt", ++ .owner = THIS_MODULE, ++ }, ++ .probe = byt_clk_probe, ++}; ++ ++static int __init byt_clk_init(void) ++{ ++ return platform_driver_register(&byt_clk_driver); ++} ++arch_initcall(byt_clk_init); +diff --git a/drivers/clk/x86/clk-lpss.c b/drivers/clk/x86/clk-lpss.c +new file mode 100644 +index 0000000..9a8a939 +--- /dev/null ++++ b/drivers/clk/x86/clk-lpss.c +@@ -0,0 +1,170 @@ ++/* ++ * Intel Low Power Subsystem clocks. ++ * ++ * Copyright (C) 2013, Intel Corporation ++ * Authors: Mika Westerberg <mika.westerb...@linux.intel.com> ++ * Heikki Krogerus <heikki.kroge...@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/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; ++} ++ ++static u8 clk_lpss_mux_get_parent(struct clk_hw *hw) ++{ ++ struct clk_mux *mux = container_of(hw, struct clk_mux, hw); ++ return readl(mux->reg) & BIT(0); ++} ++ ++static const struct clk_ops clk_lpss_mux_ops = { ++ .get_parent = clk_lpss_mux_get_parent, ++}; ++ ++/** ++ * clk_register_lpss_mux - register LPSS mux clock ++ * @name: name of this mux ++ * @parent_names: array of parent names for this clock ++ * @num_parents: number of parents in the array (max 2) ++ * @hid: ACPI _HID of the device ++ * @offset: LPSS PRV_CLOCK_PARAMS offset ++ * ++ * Creates a binary clock mux that selects between two parents. Most useful ++ * with the I2C clock. You cannot change the parent, only read it. ++ */ ++struct clk *clk_register_lpss_mux(const char *name, const char **parent_names, ++ u8 num_parents, const char *hid, ++ unsigned offset) ++{ ++ struct clk_init_data init = { }; ++ struct resource res = { }; ++ void __iomem *mmio_base; ++ struct clk_mux *mux; ++ acpi_status status; ++ struct clk *clk; ++ ++ if (num_parents > 2) ++ return ERR_PTR(-EINVAL); ++ ++ status = acpi_get_devices(hid, clk_lpss_find_mmio, NULL, (void **)&res); ++ if (ACPI_FAILURE(status) || !res.start) ++ return ERR_PTR(-ENODEV); ++ ++ mux = kzalloc(sizeof(*mux), GFP_KERNEL); ++ if (!mux) ++ return ERR_PTR(-ENOMEM); ++ ++ init.name = name; ++ init.ops = &clk_lpss_mux_ops; ++ init.parent_names = parent_names; ++ init.num_parents = num_parents; ++ ++ mmio_base = ioremap(res.start, resource_size(&res)); ++ if (!mmio_base) { ++ clk = ERR_PTR(-ENOMEM); ++ goto fail_free; ++ } ++ ++ mux->reg = mmio_base + offset; ++ mux->hw.init = &init; ++ ++ clk = clk_register(NULL, &mux->hw); ++ if (IS_ERR(clk)) ++ goto fail_unmap; ++ ++ return clk; ++ ++fail_unmap: ++ iounmap(mmio_base); ++fail_free: ++ kfree(mux); ++ ++ return clk; ++} +diff --git a/drivers/clk/x86/clk-lpss.h b/drivers/clk/x86/clk-lpss.h +new file mode 100644 +index 0000000..bdddeb5f +--- /dev/null ++++ b/drivers/clk/x86/clk-lpss.h +@@ -0,0 +1,47 @@ ++/* ++ * Intel Low Power Subsystem clock. ++ * ++ * Copyright (C) 2013, Intel Corporation ++ * Authors: Mika Westerberg <mika.westerb...@linux.intel.com> ++ * Heikki Krogerus <heikki.kroge...@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. ++ */ ++ ++#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); ++extern struct clk *clk_register_lpss_mux(const char *name, ++ const char **parent_names, ++ u8 num_parents, const char *hid, ++ 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); ++} ++static inline struct clk *clk_register_lpss_mux(const char *name, ++ const char **parent_names, ++ u8 num_parents, const char *hid, ++ 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.westerb...@linux.intel.com> ++ * Heikki Krogerus <heikki.kroge...@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); +-- +1.7.10.4 + -- 1.7.10.4 _______________________________________________ linux-yocto mailing list linux-yocto@yoctoproject.org https://lists.yoctoproject.org/listinfo/linux-yocto