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 <shunzhou.jiang@amlogic.com>
Signed-off-by: Luan Yuan <luan.yuan@amlogic.com>
This commit is contained in:
Shunzhou Jiang
2019-03-21 17:43:57 +08:00
committed by Luan Yuan
parent b5d490abb3
commit c299364c21
9 changed files with 226 additions and 1 deletions

View File

@@ -14778,3 +14778,8 @@ F: arch/arm/boot/dts/amlogic/sm1_pxp.dts
AMLOGIC SM1 CLOCK DRIVERS
M: Shunzhou Jiang <shunzhou.jiang@amlogic.com>
F: drivers/amlogic/clk/sm1/*
AMLOGIC SM1 POWER CTRL DRIVERS
M: Shunzhou Jiang <shunzhou.jiang@amlogic.com>
F: drivers/amlogic/power/power_ctrl.c
F: include/linux/amlogic/power_ctrl.h

View File

@@ -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>;

View File

@@ -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

View File

@@ -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>;

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 <linux/err.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/types.h>
#include <linux/amlogic/power_ctrl.h>
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<shunzhou.jiang@shunzhou.jiang.com");
MODULE_DESCRIPTION("SM1 power ctrl driver");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,25 @@
/*
* include/linux/amlogic/power_ctrl.h
*
* 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.
*
*/
#ifndef _POWER_CTRL_H_
#define _POWER_CTRL_H_
#include <linux/types.h>
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_*/