^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (c) 2017 Samsung Electronics Co., Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Author: Marek Szyprowski <m.szyprowski@samsung.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Common Clock Framework support for Exynos4412 ISP module.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <dt-bindings/clock/exynos4.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/clk-provider.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/pm_runtime.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include "clk.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) /* Exynos4x12 specific registers, which belong to ISP power domain */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define E4X12_DIV_ISP0 0x0300
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define E4X12_DIV_ISP1 0x0304
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define E4X12_GATE_ISP0 0x0800
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define E4X12_GATE_ISP1 0x0804
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * Support for CMU save/restore across system suspends
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) static struct samsung_clk_reg_dump *exynos4x12_save_isp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) static const unsigned long exynos4x12_clk_isp_save[] __initconst = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) E4X12_DIV_ISP0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) E4X12_DIV_ISP1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) E4X12_GATE_ISP0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) E4X12_GATE_ISP1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) static struct samsung_div_clock exynos4x12_isp_div_clks[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) DIV(CLK_ISP_DIV_ISP0, "div_isp0", "aclk200", E4X12_DIV_ISP0, 0, 3),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) DIV(CLK_ISP_DIV_ISP1, "div_isp1", "aclk200", E4X12_DIV_ISP0, 4, 3),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) DIV(CLK_ISP_DIV_MCUISP0, "div_mcuisp0", "aclk400_mcuisp",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) E4X12_DIV_ISP1, 4, 3),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) DIV(CLK_ISP_DIV_MCUISP1, "div_mcuisp1", "div_mcuisp0",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) E4X12_DIV_ISP1, 8, 3),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) DIV(0, "div_mpwm", "div_isp1", E4X12_DIV_ISP1, 0, 3),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) static struct samsung_gate_clock exynos4x12_isp_gate_clks[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) GATE(CLK_ISP_FIMC_ISP, "isp", "aclk200", E4X12_GATE_ISP0, 0, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) GATE(CLK_ISP_FIMC_DRC, "drc", "aclk200", E4X12_GATE_ISP0, 1, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) GATE(CLK_ISP_FIMC_FD, "fd", "aclk200", E4X12_GATE_ISP0, 2, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) GATE(CLK_ISP_FIMC_LITE0, "lite0", "aclk200", E4X12_GATE_ISP0, 3, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) GATE(CLK_ISP_FIMC_LITE1, "lite1", "aclk200", E4X12_GATE_ISP0, 4, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) GATE(CLK_ISP_MCUISP, "mcuisp", "aclk200", E4X12_GATE_ISP0, 5, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) GATE(CLK_ISP_GICISP, "gicisp", "aclk200", E4X12_GATE_ISP0, 7, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) GATE(CLK_ISP_SMMU_ISP, "smmu_isp", "aclk200", E4X12_GATE_ISP0, 8, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) GATE(CLK_ISP_SMMU_DRC, "smmu_drc", "aclk200", E4X12_GATE_ISP0, 9, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) GATE(CLK_ISP_SMMU_FD, "smmu_fd", "aclk200", E4X12_GATE_ISP0, 10, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) GATE(CLK_ISP_SMMU_LITE0, "smmu_lite0", "aclk200", E4X12_GATE_ISP0, 11,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) GATE(CLK_ISP_SMMU_LITE1, "smmu_lite1", "aclk200", E4X12_GATE_ISP0, 12,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) GATE(CLK_ISP_PPMUISPMX, "ppmuispmx", "aclk200", E4X12_GATE_ISP0, 20,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) GATE(CLK_ISP_PPMUISPX, "ppmuispx", "aclk200", E4X12_GATE_ISP0, 21,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) GATE(CLK_ISP_MCUCTL_ISP, "mcuctl_isp", "aclk200", E4X12_GATE_ISP0, 23,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) GATE(CLK_ISP_MPWM_ISP, "mpwm_isp", "aclk200", E4X12_GATE_ISP0, 24,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) GATE(CLK_ISP_I2C0_ISP, "i2c0_isp", "aclk200", E4X12_GATE_ISP0, 25,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) GATE(CLK_ISP_I2C1_ISP, "i2c1_isp", "aclk200", E4X12_GATE_ISP0, 26,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) GATE(CLK_ISP_MTCADC_ISP, "mtcadc_isp", "aclk200", E4X12_GATE_ISP0, 27,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) GATE(CLK_ISP_PWM_ISP, "pwm_isp", "aclk200", E4X12_GATE_ISP0, 28, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) GATE(CLK_ISP_WDT_ISP, "wdt_isp", "aclk200", E4X12_GATE_ISP0, 30, 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) GATE(CLK_ISP_UART_ISP, "uart_isp", "aclk200", E4X12_GATE_ISP0, 31,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) GATE(CLK_ISP_ASYNCAXIM, "asyncaxim", "aclk200", E4X12_GATE_ISP1, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) GATE(CLK_ISP_SMMU_ISPCX, "smmu_ispcx", "aclk200", E4X12_GATE_ISP1, 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) GATE(CLK_ISP_SPI0_ISP, "spi0_isp", "aclk200", E4X12_GATE_ISP1, 12,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) GATE(CLK_ISP_SPI1_ISP, "spi1_isp", "aclk200", E4X12_GATE_ISP1, 13,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) 0, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) static int __maybe_unused exynos4x12_isp_clk_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) struct samsung_clk_provider *ctx = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) samsung_clk_save(ctx->reg_base, exynos4x12_save_isp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) ARRAY_SIZE(exynos4x12_clk_isp_save));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) static int __maybe_unused exynos4x12_isp_clk_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) struct samsung_clk_provider *ctx = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) samsung_clk_restore(ctx->reg_base, exynos4x12_save_isp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) ARRAY_SIZE(exynos4x12_clk_isp_save));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) static int __init exynos4x12_isp_clk_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) struct samsung_clk_provider *ctx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) struct device_node *np = dev->of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) void __iomem *reg_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) reg_base = devm_ioremap_resource(dev, res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if (IS_ERR(reg_base)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) dev_err(dev, "failed to map registers\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) return PTR_ERR(reg_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) exynos4x12_save_isp = samsung_clk_alloc_reg_dump(exynos4x12_clk_isp_save,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) ARRAY_SIZE(exynos4x12_clk_isp_save));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) if (!exynos4x12_save_isp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) ctx = samsung_clk_init(np, reg_base, CLK_NR_ISP_CLKS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) ctx->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) platform_set_drvdata(pdev, ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) pm_runtime_set_active(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) pm_runtime_enable(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) pm_runtime_get_sync(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) samsung_clk_register_div(ctx, exynos4x12_isp_div_clks,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) ARRAY_SIZE(exynos4x12_isp_div_clks));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) samsung_clk_register_gate(ctx, exynos4x12_isp_gate_clks,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) ARRAY_SIZE(exynos4x12_isp_gate_clks));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) samsung_clk_of_add_provider(np, ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) pm_runtime_put(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) static const struct of_device_id exynos4x12_isp_clk_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) { .compatible = "samsung,exynos4412-isp-clock", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) { },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) static const struct dev_pm_ops exynos4x12_isp_pm_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) SET_RUNTIME_PM_OPS(exynos4x12_isp_clk_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) exynos4x12_isp_clk_resume, NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) pm_runtime_force_resume)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) static struct platform_driver exynos4x12_isp_clk_driver __refdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) .name = "exynos4x12-isp-clk",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) .of_match_table = exynos4x12_isp_clk_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) .suppress_bind_attrs = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) .pm = &exynos4x12_isp_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) .probe = exynos4x12_isp_clk_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) static int __init exynos4x12_isp_clk_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) return platform_driver_register(&exynos4x12_isp_clk_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) core_initcall(exynos4x12_isp_clk_init);