From c299364c21b0b5c1bb4cd522e4fafa02f2487fc8 Mon Sep 17 00:00:00 2001 From: Shunzhou Jiang Date: Thu, 21 Mar 2019 17:43:57 +0800 Subject: [PATCH] power: sm1: add power control driver [1/1] PD#SWPL-6186 Problem: add power control register Solution: avoid same register access at the same time Verify: sm1_skt Change-Id: I0ec61cda9721c1b95a9d78f7884458f442581fe5 Signed-off-by: Shunzhou Jiang Signed-off-by: Luan Yuan --- MAINTAINERS | 5 + arch/arm/boot/dts/amlogic/mesonsm1.dtsi | 6 + arch/arm/configs/meson64_a32_defconfig | 1 + arch/arm64/boot/dts/amlogic/mesonsm1.dtsi | 6 + arch/arm64/configs/meson64_defconfig | 1 + drivers/amlogic/power/Kconfig | 1 - drivers/amlogic/power/Makefile | 1 + drivers/amlogic/power/power_ctrl.c | 181 ++++++++++++++++++++++ include/linux/amlogic/power_ctrl.h | 25 +++ 9 files changed, 226 insertions(+), 1 deletion(-) create mode 100644 drivers/amlogic/power/power_ctrl.c create mode 100644 include/linux/amlogic/power_ctrl.h diff --git a/MAINTAINERS b/MAINTAINERS index d3472a6d9d2d..93251e31352d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14778,3 +14778,8 @@ F: arch/arm/boot/dts/amlogic/sm1_pxp.dts AMLOGIC SM1 CLOCK DRIVERS M: Shunzhou Jiang F: drivers/amlogic/clk/sm1/* + +AMLOGIC SM1 POWER CTRL DRIVERS +M: Shunzhou Jiang +F: drivers/amlogic/power/power_ctrl.c +F: include/linux/amlogic/power_ctrl.h diff --git a/arch/arm/boot/dts/amlogic/mesonsm1.dtsi b/arch/arm/boot/dts/amlogic/mesonsm1.dtsi index e09ef961774d..61aba2f91bb3 100644 --- a/arch/arm/boot/dts/amlogic/mesonsm1.dtsi +++ b/arch/arm/boot/dts/amlogic/mesonsm1.dtsi @@ -509,6 +509,12 @@ #thermal-sensor-cells = <1>; }; + power_ctrl: power_ctrl@ff8000e8 { + compatible = "amlogic, sm1-powerctrl"; + reg = <0xff8000e8 0x10>, + <0xff63c100 0x10>; + }; + soc { compatible = "simple-bus"; #address-cells = <1>; diff --git a/arch/arm/configs/meson64_a32_defconfig b/arch/arm/configs/meson64_a32_defconfig index f40ccea1e14f..2e1cef27d18a 100644 --- a/arch/arm/configs/meson64_a32_defconfig +++ b/arch/arm/configs/meson64_a32_defconfig @@ -361,6 +361,7 @@ CONFIG_AMLOGIC_WDT_MESON_V3=y CONFIG_AMLOGIC_ESM=y CONFIG_AMLOGIC_WIFI=y CONFIG_AMLOGIC_BT_DEVICE=y +CONFIG_AMLOGIC_POWER=y CONFIG_AMLOGIC_PCIE=y CONFIG_AMLOGIC_IRBLASTER=y CONFIG_AMLOGIC_IIO=y diff --git a/arch/arm64/boot/dts/amlogic/mesonsm1.dtsi b/arch/arm64/boot/dts/amlogic/mesonsm1.dtsi index b522feda104c..05bfb88dad36 100644 --- a/arch/arm64/boot/dts/amlogic/mesonsm1.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesonsm1.dtsi @@ -509,6 +509,12 @@ #thermal-sensor-cells = <1>; }; + power_ctrl: power_ctrl@ff8000e8 { + compatible = "amlogic, sm1-powerctrl"; + reg = <0x0 0xff8000e8 0x0 0x10>, + <0x0 0xff63c100 0x0 0x10>; + }; + soc { compatible = "simple-bus"; #address-cells = <2>; diff --git a/arch/arm64/configs/meson64_defconfig b/arch/arm64/configs/meson64_defconfig index f5191cbad37e..87e804661efc 100644 --- a/arch/arm64/configs/meson64_defconfig +++ b/arch/arm64/configs/meson64_defconfig @@ -355,6 +355,7 @@ CONFIG_AMLOGIC_WDT_MESON_V3=y CONFIG_AMLOGIC_ESM=y CONFIG_AMLOGIC_WIFI=y CONFIG_AMLOGIC_BT_DEVICE=y +CONFIG_AMLOGIC_POWER=y CONFIG_AMLOGIC_PCIE=y CONFIG_AMLOGIC_IRBLASTER=y CONFIG_AMLOGIC_IIO=y diff --git a/drivers/amlogic/power/Kconfig b/drivers/amlogic/power/Kconfig index 3c405e2f0ef3..53941f9e38ce 100644 --- a/drivers/amlogic/power/Kconfig +++ b/drivers/amlogic/power/Kconfig @@ -1,6 +1,5 @@ config AMLOGIC_POWER bool "Amloigc power related driver support" - depends on MACH_MESON8B default n help this config enables to use amlogic power management driver diff --git a/drivers/amlogic/power/Makefile b/drivers/amlogic/power/Makefile index 294b54188e4e..ea86bf8f9f8a 100644 --- a/drivers/amlogic/power/Makefile +++ b/drivers/amlogic/power/Makefile @@ -3,3 +3,4 @@ obj-$(CONFIG_AMLOGIC_PMU) += aml_pmu/ obj-$(CONFIG_AMLOGIC_PMU_OF) += aml_pmu_of_common.o obj-$(CONFIG_AMLOGIC_M8B_DVFS) += aml_dvfs/ +obj-$(CONFIG_AMLOGIC_POWER) += power_ctrl.o diff --git a/drivers/amlogic/power/power_ctrl.c b/drivers/amlogic/power/power_ctrl.c new file mode 100644 index 000000000000..9654f6a5ca6f --- /dev/null +++ b/drivers/amlogic/power/power_ctrl.c @@ -0,0 +1,181 @@ +/* + * drivers/amlogic/power/power_ctrl.c + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct power_ctrl { + void __iomem *sleep_addr; + void __iomem *iso_addr; + void __iomem *mempd0_addr; + void __iomem *reset_addr_base; + spinlock_t sleep_lock; + spinlock_t iso_lock; + spinlock_t mempd0_lock; +}; + +struct power_ctrl ctrl; +static bool probe_done; + +int power_ctrl_sleep(bool power_on, unsigned int shift) +{ + unsigned int val; + unsigned long flags; + + if (!probe_done) + return -ENXIO; + + if (power_on) { + spin_lock_irqsave(&ctrl.sleep_lock, flags); + val = readl(ctrl.sleep_addr); + val = val & (~(1 << shift)); + writel(val, ctrl.sleep_addr); + spin_unlock_irqrestore(&ctrl.sleep_lock, flags); + } else { + spin_lock_irqsave(&ctrl.sleep_lock, flags); + val = readl(ctrl.sleep_addr); + val = val | (1 << shift); + writel(val, ctrl.sleep_addr); + spin_unlock_irqrestore(&ctrl.sleep_lock, flags); + } + return 0; +} +EXPORT_SYMBOL(power_ctrl_sleep); + +int power_ctrl_iso(bool power_on, unsigned int shift) +{ + unsigned int val; + unsigned long flags; + + if (!probe_done) + return -ENXIO; + + if (power_on) { + spin_lock_irqsave(&(ctrl.iso_lock), flags); + val = readl(ctrl.iso_addr); + val = val & (~(1 << shift)); + writel(val, ctrl.iso_addr); + spin_unlock_irqrestore(&(ctrl.iso_lock), flags); + } else { + spin_lock_irqsave((&ctrl.iso_lock), flags); + val = readl(ctrl.iso_addr); + val = val | (1 << shift); + writel(val, ctrl.iso_addr); + spin_unlock_irqrestore(&(ctrl.iso_lock), flags); + } + return 0; +} +EXPORT_SYMBOL(power_ctrl_iso); + +int power_ctrl_mempd0(bool power_on, unsigned int mask_val, unsigned int shift) +{ + unsigned int val; + unsigned long flags; + + if (!probe_done) + return -ENXIO; + + if (power_on) { + spin_lock_irqsave(&(ctrl.mempd0_lock), flags); + val = readl(ctrl.mempd0_addr); + val = val & (~(mask_val << shift)); + writel(val, ctrl.mempd0_addr); + spin_unlock_irqrestore(&(ctrl.mempd0_lock), flags); + } else { + spin_lock_irqsave((&ctrl.mempd0_lock), flags); + val = readl(ctrl.mempd0_addr); + val = val | (mask_val << shift); + writel(val, ctrl.mempd0_addr); + spin_unlock_irqrestore(&(ctrl.mempd0_lock), flags); + } + return 0; +} +EXPORT_SYMBOL(power_ctrl_mempd0); + +static int amlogic_powerctrl_probe(struct platform_device *pdev) +{ + struct resource *res; + struct device *dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "Fail to get power ctrl memory res0\n"); + return -ENXIO; + } + + ctrl.sleep_addr = devm_ioremap_resource(dev, res); + if (IS_ERR(ctrl.sleep_addr)) + return PTR_ERR(ctrl.sleep_addr); + + ctrl.iso_addr = ctrl.sleep_addr + 4; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res) { + dev_err(dev, "Fail to get power ctrl memory res1\n"); + return -ENXIO; + } + ctrl.mempd0_addr = devm_ioremap_resource(dev, res); + if (IS_ERR(ctrl.mempd0_addr)) + return PTR_ERR(ctrl.mempd0_addr); + + spin_lock_init(&ctrl.sleep_lock); + spin_lock_init(&ctrl.iso_lock); + spin_lock_init(&ctrl.mempd0_lock); + + probe_done = 1; + return 0; +} + +static int amlogic_powerctrl_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + + devm_iounmap(dev, ctrl.sleep_addr); + devm_iounmap(dev, ctrl.mempd0_addr); + devm_iounmap(dev, ctrl.reset_addr_base); + return 0; +} + +static const struct of_device_id amlogic_powerctrl_match[] = { + { .compatible = "amlogic, sm1-powerctrl", }, + {} +}; + +static struct platform_driver amlogic_powerctrl_driver = { + .driver = { + .name = "amlogic, sm1-powerctrl", + .of_match_table = amlogic_powerctrl_match, + }, + .probe = amlogic_powerctrl_probe, + .remove = amlogic_powerctrl_remove, +}; + +static int __init amlogic_powerctrl_init(void) +{ + return platform_driver_register(&amlogic_powerctrl_driver); +} +arch_initcall(amlogic_powerctrl_init); + +MODULE_AUTHOR("shunzhou jiang + +int power_ctrl_sleep(bool power_on, unsigned int shift); +int power_ctrl_iso(bool power_on, unsigned int shift); +int power_ctrl_mempd0(bool power_on, unsigned int mask_val, unsigned int shift); +#endif /*_POWER_CTRL_H_*/