mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 03:40:35 +09:00
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:
committed by
Luan Yuan
parent
b5d490abb3
commit
c299364c21
@@ -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
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
181
drivers/amlogic/power/power_ctrl.c
Normal file
181
drivers/amlogic/power/power_ctrl.c
Normal 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");
|
||||
25
include/linux/amlogic/power_ctrl.h
Normal file
25
include/linux/amlogic/power_ctrl.h
Normal 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_*/
|
||||
Reference in New Issue
Block a user