summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/samsung/Kconfig10
-rw-r--r--drivers/clk/samsung/Makefile2
-rw-r--r--drivers/clk/samsung/clk-exynos-clkout.c199
-rw-r--r--drivers/cpuidle/cpuidle-big_little.c3
-rw-r--r--drivers/soc/samsung/exynos-pmu.c11
-rw-r--r--drivers/soc/samsung/exynos5422-asv.c2
-rw-r--r--drivers/soc/samsung/s3c-pm-check.c2
7 files changed, 167 insertions, 62 deletions
diff --git a/drivers/clk/samsung/Kconfig b/drivers/clk/samsung/Kconfig
index 57d4b3f20417..7e9c186e57ef 100644
--- a/drivers/clk/samsung/Kconfig
+++ b/drivers/clk/samsung/Kconfig
@@ -19,6 +19,16 @@ config EXYNOS_AUDSS_CLK_CON
on some Exynos SoC variants. Choose M or Y here if you want to
use audio devices such as I2S, PCM, etc.
+config EXYNOS_CLKOUT
+ tristate "Samsung Exynos clock output driver"
+ depends on COMMON_CLK_SAMSUNG
+ default y if ARCH_EXYNOS
+ help
+ Support for the clock output (XCLKOUT) present on some of Exynos SoC
+ variants. Usually the XCLKOUT is used to monitor the status of the
+ certains clocks from SoC, but it could also be tied to other devices
+ as an input clock.
+
# For S3C24XX platforms, select following symbols:
config S3C2410_COMMON_CLK
bool "Samsung S3C2410 clock controller support" if COMPILE_TEST
diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile
index 1a4e6b787978..6891b087acff 100644
--- a/drivers/clk/samsung/Makefile
+++ b/drivers/clk/samsung/Makefile
@@ -15,7 +15,7 @@ obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5420.o
obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5-subcmu.o
obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos5433.o
obj-$(CONFIG_EXYNOS_AUDSS_CLK_CON) += clk-exynos-audss.o
-obj-$(CONFIG_ARCH_EXYNOS) += clk-exynos-clkout.o
+obj-$(CONFIG_EXYNOS_CLKOUT) += clk-exynos-clkout.o
obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos7.o
obj-$(CONFIG_S3C2410_COMMON_CLK)+= clk-s3c2410.o
obj-$(CONFIG_S3C2410_COMMON_DCLK)+= clk-s3c2410-dclk.o
diff --git a/drivers/clk/samsung/clk-exynos-clkout.c b/drivers/clk/samsung/clk-exynos-clkout.c
index 34ccb1d23bc3..9ec2f40cc400 100644
--- a/drivers/clk/samsung/clk-exynos-clkout.c
+++ b/drivers/clk/samsung/clk-exynos-clkout.c
@@ -9,10 +9,13 @@
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
+#include <linux/module.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/syscore_ops.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
#define EXYNOS_CLKOUT_NR_CLKS 1
#define EXYNOS_CLKOUT_PARENTS 32
@@ -28,41 +31,103 @@ struct exynos_clkout {
struct clk_mux mux;
spinlock_t slock;
void __iomem *reg;
+ struct device_node *np;
u32 pmu_debug_save;
struct clk_hw_onecell_data data;
};
-static struct exynos_clkout *clkout;
+struct exynos_clkout_variant {
+ u32 mux_mask;
+};
-static int exynos_clkout_suspend(void)
-{
- clkout->pmu_debug_save = readl(clkout->reg + EXYNOS_PMU_DEBUG_REG);
+static const struct exynos_clkout_variant exynos_clkout_exynos4 = {
+ .mux_mask = EXYNOS4_CLKOUT_MUX_MASK,
+};
- return 0;
-}
+static const struct exynos_clkout_variant exynos_clkout_exynos5 = {
+ .mux_mask = EXYNOS5_CLKOUT_MUX_MASK,
+};
-static void exynos_clkout_resume(void)
+static const struct of_device_id exynos_clkout_ids[] = {
+ {
+ .compatible = "samsung,exynos3250-pmu",
+ .data = &exynos_clkout_exynos4,
+ }, {
+ .compatible = "samsung,exynos4210-pmu",
+ .data = &exynos_clkout_exynos4,
+ }, {
+ .compatible = "samsung,exynos4412-pmu",
+ .data = &exynos_clkout_exynos4,
+ }, {
+ .compatible = "samsung,exynos5250-pmu",
+ .data = &exynos_clkout_exynos5,
+ }, {
+ .compatible = "samsung,exynos5410-pmu",
+ .data = &exynos_clkout_exynos5,
+ }, {
+ .compatible = "samsung,exynos5420-pmu",
+ .data = &exynos_clkout_exynos5,
+ }, {
+ .compatible = "samsung,exynos5433-pmu",
+ .data = &exynos_clkout_exynos5,
+ }, { }
+};
+MODULE_DEVICE_TABLE(of, exynos_clkout_ids);
+
+/*
+ * Device will be instantiated as child of PMU device without its own
+ * device node. Therefore match compatibles against parent.
+ */
+static int exynos_clkout_match_parent_dev(struct device *dev, u32 *mux_mask)
{
- writel(clkout->pmu_debug_save, clkout->reg + EXYNOS_PMU_DEBUG_REG);
-}
+ const struct exynos_clkout_variant *variant;
+ const struct of_device_id *match;
-static struct syscore_ops exynos_clkout_syscore_ops = {
- .suspend = exynos_clkout_suspend,
- .resume = exynos_clkout_resume,
-};
+ if (!dev->parent) {
+ dev_err(dev, "not instantiated from MFD\n");
+ return -EINVAL;
+ }
+
+ match = of_match_device(exynos_clkout_ids, dev->parent);
+ if (!match) {
+ dev_err(dev, "cannot match parent device\n");
+ return -EINVAL;
+ }
+ variant = match->data;
-static void __init exynos_clkout_init(struct device_node *node, u32 mux_mask)
+ *mux_mask = variant->mux_mask;
+
+ return 0;
+}
+
+static int exynos_clkout_probe(struct platform_device *pdev)
{
const char *parent_names[EXYNOS_CLKOUT_PARENTS];
struct clk *parents[EXYNOS_CLKOUT_PARENTS];
- int parent_count;
- int ret;
- int i;
+ struct exynos_clkout *clkout;
+ int parent_count, ret, i;
+ u32 mux_mask;
- clkout = kzalloc(struct_size(clkout, data.hws, EXYNOS_CLKOUT_NR_CLKS),
- GFP_KERNEL);
+ clkout = devm_kzalloc(&pdev->dev,
+ struct_size(clkout, data.hws, EXYNOS_CLKOUT_NR_CLKS),
+ GFP_KERNEL);
if (!clkout)
- return;
+ return -ENOMEM;
+
+ ret = exynos_clkout_match_parent_dev(&pdev->dev, &mux_mask);
+ if (ret)
+ return ret;
+
+ clkout->np = pdev->dev.of_node;
+ if (!clkout->np) {
+ /*
+ * pdev->dev.parent was checked by exynos_clkout_match_parent_dev()
+ * so it is not NULL.
+ */
+ clkout->np = pdev->dev.parent->of_node;
+ }
+
+ platform_set_drvdata(pdev, clkout);
spin_lock_init(&clkout->slock);
@@ -71,7 +136,7 @@ static void __init exynos_clkout_init(struct device_node *node, u32 mux_mask)
char name[] = "clkoutXX";
snprintf(name, sizeof(name), "clkout%d", i);
- parents[i] = of_clk_get_by_name(node, name);
+ parents[i] = of_clk_get_by_name(clkout->np, name);
if (IS_ERR(parents[i])) {
parent_names[i] = "none";
continue;
@@ -82,11 +147,13 @@ static void __init exynos_clkout_init(struct device_node *node, u32 mux_mask)
}
if (!parent_count)
- goto free_clkout;
+ return -EINVAL;
- clkout->reg = of_iomap(node, 0);
- if (!clkout->reg)
+ clkout->reg = of_iomap(clkout->np, 0);
+ if (!clkout->reg) {
+ ret = -ENODEV;
goto clks_put;
+ }
clkout->gate.reg = clkout->reg + EXYNOS_PMU_DEBUG_REG;
clkout->gate.bit_idx = EXYNOS_CLKOUT_DISABLE_SHIFT;
@@ -103,17 +170,17 @@ static void __init exynos_clkout_init(struct device_node *node, u32 mux_mask)
&clk_mux_ops, NULL, NULL, &clkout->gate.hw,
&clk_gate_ops, CLK_SET_RATE_PARENT
| CLK_SET_RATE_NO_REPARENT);
- if (IS_ERR(clkout->data.hws[0]))
+ if (IS_ERR(clkout->data.hws[0])) {
+ ret = PTR_ERR(clkout->data.hws[0]);
goto err_unmap;
+ }
clkout->data.num = EXYNOS_CLKOUT_NR_CLKS;
- ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, &clkout->data);
+ ret = of_clk_add_hw_provider(clkout->np, of_clk_hw_onecell_get, &clkout->data);
if (ret)
goto err_clk_unreg;
- register_syscore_ops(&exynos_clkout_syscore_ops);
-
- return;
+ return 0;
err_clk_unreg:
clk_hw_unregister(clkout->data.hws[0]);
@@ -123,38 +190,56 @@ clks_put:
for (i = 0; i < EXYNOS_CLKOUT_PARENTS; ++i)
if (!IS_ERR(parents[i]))
clk_put(parents[i]);
-free_clkout:
- kfree(clkout);
- pr_err("%s: failed to register clkout clock\n", __func__);
+ dev_err(&pdev->dev, "failed to register clkout clock\n");
+
+ return ret;
}
-/*
- * We use CLK_OF_DECLARE_DRIVER initialization method to avoid setting
- * the OF_POPULATED flag on the pmu device tree node, so later the
- * Exynos PMU platform device can be properly probed with PMU driver.
- */
+static int exynos_clkout_remove(struct platform_device *pdev)
+{
+ struct exynos_clkout *clkout = platform_get_drvdata(pdev);
+
+ of_clk_del_provider(clkout->np);
+ clk_hw_unregister(clkout->data.hws[0]);
+ iounmap(clkout->reg);
+
+ return 0;
+}
-static void __init exynos4_clkout_init(struct device_node *node)
+static int exynos_clkout_suspend(struct device *dev)
{
- exynos_clkout_init(node, EXYNOS4_CLKOUT_MUX_MASK);
+ struct exynos_clkout *clkout = dev_get_drvdata(dev);
+
+ clkout->pmu_debug_save = readl(clkout->reg + EXYNOS_PMU_DEBUG_REG);
+
+ return 0;
}
-CLK_OF_DECLARE_DRIVER(exynos4210_clkout, "samsung,exynos4210-pmu",
- exynos4_clkout_init);
-CLK_OF_DECLARE_DRIVER(exynos4412_clkout, "samsung,exynos4412-pmu",
- exynos4_clkout_init);
-CLK_OF_DECLARE_DRIVER(exynos3250_clkout, "samsung,exynos3250-pmu",
- exynos4_clkout_init);
-
-static void __init exynos5_clkout_init(struct device_node *node)
+
+static int exynos_clkout_resume(struct device *dev)
{
- exynos_clkout_init(node, EXYNOS5_CLKOUT_MUX_MASK);
+ struct exynos_clkout *clkout = dev_get_drvdata(dev);
+
+ writel(clkout->pmu_debug_save, clkout->reg + EXYNOS_PMU_DEBUG_REG);
+
+ return 0;
}
-CLK_OF_DECLARE_DRIVER(exynos5250_clkout, "samsung,exynos5250-pmu",
- exynos5_clkout_init);
-CLK_OF_DECLARE_DRIVER(exynos5410_clkout, "samsung,exynos5410-pmu",
- exynos5_clkout_init);
-CLK_OF_DECLARE_DRIVER(exynos5420_clkout, "samsung,exynos5420-pmu",
- exynos5_clkout_init);
-CLK_OF_DECLARE_DRIVER(exynos5433_clkout, "samsung,exynos5433-pmu",
- exynos5_clkout_init);
+
+static SIMPLE_DEV_PM_OPS(exynos_clkout_pm_ops, exynos_clkout_suspend,
+ exynos_clkout_resume);
+
+static struct platform_driver exynos_clkout_driver = {
+ .driver = {
+ .name = "exynos-clkout",
+ .of_match_table = exynos_clkout_ids,
+ .pm = &exynos_clkout_pm_ops,
+ },
+ .probe = exynos_clkout_probe,
+ .remove = exynos_clkout_remove,
+};
+module_platform_driver(exynos_clkout_driver);
+
+MODULE_AUTHOR("Krzysztof Kozlowski <krzk@kernel.org>");
+MODULE_AUTHOR("Tomasz Figa <tomasz.figa@gmail.com>");
+MODULE_DESCRIPTION("Samsung Exynos clock output driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/cpuidle/cpuidle-big_little.c b/drivers/cpuidle/cpuidle-big_little.c
index 7f8ddc04342d..abe51185f243 100644
--- a/drivers/cpuidle/cpuidle-big_little.c
+++ b/drivers/cpuidle/cpuidle-big_little.c
@@ -155,8 +155,7 @@ static int __init bl_idle_driver_init(struct cpuidle_driver *drv, int part_id)
static const struct of_device_id compatible_machine_match[] = {
{ .compatible = "arm,vexpress,v2p-ca15_a7" },
- { .compatible = "samsung,exynos5420" },
- { .compatible = "samsung,exynos5800" },
+ { .compatible = "google,peach" },
{},
};
diff --git a/drivers/soc/samsung/exynos-pmu.c b/drivers/soc/samsung/exynos-pmu.c
index 17304fa18429..a18c93a4646c 100644
--- a/drivers/soc/samsung/exynos-pmu.c
+++ b/drivers/soc/samsung/exynos-pmu.c
@@ -8,6 +8,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
+#include <linux/mfd/core.h>
#include <linux/mfd/syscon.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
@@ -97,6 +98,10 @@ static const struct of_device_id exynos_pmu_of_device_ids[] = {
{ /*sentinel*/ },
};
+static const struct mfd_cell exynos_pmu_devs[] = {
+ { .name = "exynos-clkout", },
+};
+
struct regmap *exynos_get_pmu_regmap(void)
{
struct device_node *np = of_find_matching_node(NULL,
@@ -110,6 +115,7 @@ EXPORT_SYMBOL_GPL(exynos_get_pmu_regmap);
static int exynos_pmu_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ int ret;
pmu_base_addr = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(pmu_base_addr))
@@ -128,6 +134,11 @@ static int exynos_pmu_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, pmu_context);
+ ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, exynos_pmu_devs,
+ ARRAY_SIZE(exynos_pmu_devs), NULL, 0, NULL);
+ if (ret)
+ return ret;
+
if (devm_of_platform_populate(dev))
dev_err(dev, "Error populating children, reboot and poweroff might not work properly\n");
diff --git a/drivers/soc/samsung/exynos5422-asv.c b/drivers/soc/samsung/exynos5422-asv.c
index 01bb3050d678..ca409a976e34 100644
--- a/drivers/soc/samsung/exynos5422-asv.c
+++ b/drivers/soc/samsung/exynos5422-asv.c
@@ -383,7 +383,7 @@ static int __asv_offset_voltage(unsigned int index)
return 25000;
default:
return 0;
- };
+ }
}
static void exynos5422_asv_offset_voltage_setup(struct exynos_asv *asv)
diff --git a/drivers/soc/samsung/s3c-pm-check.c b/drivers/soc/samsung/s3c-pm-check.c
index ff3e099fc208..439d5c372512 100644
--- a/drivers/soc/samsung/s3c-pm-check.c
+++ b/drivers/soc/samsung/s3c-pm-check.c
@@ -151,7 +151,7 @@ static inline int in_region(void *ptr, int size, void *what, size_t whatsz)
/**
* s3c_pm_runcheck() - helper to check a resource on restore.
* @res: The resource to check
- * @vak: Pointer to list of CRC32 values to check.
+ * @val: Pointer to list of CRC32 values to check.
*
* Called from the s3c_pm_check_restore() via s3c_pm_run_sysram(), this
* function runs the given memory resource checking it against the stored