support ip regulator
add ip power driver based on regulator framework for hikey970
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
/ {
|
||||
regu_ip: test_regu_ip@0xFFF35000 {
|
||||
compatible = "hisilicon,regulator-ip-test";
|
||||
reg = <0x0 0xFFF35000 0x0 0x1000>; /* 4K */
|
||||
vivobustest-supply = <&vivobus>;
|
||||
dsssubsystest-supply = <&dsssubsys>;
|
||||
vcodecsubsystest-supply = <&vcodecsubsys>;
|
||||
vdectest-supply = <&vdec>;
|
||||
venctest-supply = <&venc>;
|
||||
ispsubsystest-supply = <&ispsubsys>;
|
||||
};
|
||||
};
|
||||
@@ -13,6 +13,8 @@
|
||||
#include <dt-bindings/input/input.h>
|
||||
#include "kirin970_spmi.dtsi"
|
||||
#include "hisi_6421v600_pmic_spmi.dtsi"
|
||||
#include "kirin970_powerip.dtsi"
|
||||
#include "hisi_power_ip_test.dtsi"
|
||||
#include "kirin970-gpu.dtsi"
|
||||
#include "kirin970-ion.dtsi"
|
||||
#include "kirin970_ipc.dtsi"
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2013 Linaro Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* publishhed by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/{
|
||||
regulators_ip: regulator_ip@0xFFF35000 {
|
||||
compatible = "hisilicon,hisi_regulator_ip_atf_core";
|
||||
reg = <0x00 0xE87FF000 0x00 0x1000>;
|
||||
|
||||
media1_subsys: ip@0 {
|
||||
compatible = "ip-regulator-atf";
|
||||
regulator-name = "media1_subsys";
|
||||
hisilicon,hisi-regulator-id = <0>;
|
||||
hisilicon,hisi-regulator-type = <1>;/*0:pmu;1:ip;2:scharger*/
|
||||
hisilicon,hisi-regulator-clk-num = <0>;
|
||||
hisilicon,hisi-regulator-clk-check-flag = <0>;/*0:not check clock state;1:check clock state*/
|
||||
hisilicon,hisi-need-to-enable-clock = <0>;/*0:donot enable clock;1:enable clock*/
|
||||
hisilicon,hisi-clock-rate-set-flag = <0>;/*low frequency clock set flag:0:donot set clock rate;1:set clock rate*/
|
||||
hisilicon,hisi-clock-rate-set = <0>;/*frequency:0:not set frequency;*/
|
||||
hisilicon,hisi-ppll0-clock-rate-set-flag = <0>;/*switch to ppll0 flag:0:donot set clock rate;1:set clock rate*/
|
||||
hisilicon,hisi-ppll0-clock-rate-set = <0>;/*ppll0 frequency:0:not set frequency;*/
|
||||
hisilicon,hisi-regulator-is-fake = <0>;/*0:this ip is effective;1:this ip is ineffective*/
|
||||
};
|
||||
vivobus: ip@1 {
|
||||
compatible = "ip-regulator-atf";
|
||||
regulator-name = "vivobus";
|
||||
hisilicon,hisi-regulator-id = <1>;
|
||||
hisilicon,hisi-regulator-type = <1>;/*0:pmu;1:ip;2:scharger*/
|
||||
vivobus-supply = <&media1_subsys>;
|
||||
hisilicon,supply_name = "vivobus";
|
||||
hisilicon,hisi-regulator-clk-num = <0>;
|
||||
hisilicon,hisi-regulator-clk-check-flag = <0>;/*0:not check clock state;1:check clock state*/
|
||||
hisilicon,hisi-need-to-enable-clock = <0>;/*0:donot enable clock;1:enable clock*/
|
||||
hisilicon,hisi-clock-rate-set-flag = <0>;/*low frequency clock set flag:0:donot set clock rate;1:set clock rate*/
|
||||
hisilicon,hisi-ppll0-clock-rate-set-flag = <0>;
|
||||
hisilicon,hisi-ppll0-clock-rate-set = <0>;
|
||||
hisilicon,hisi-regulator-is-fake = <0>;/*0:this ip is effective;1:this ip is ineffective*/
|
||||
};
|
||||
|
||||
media2_subsys: ip@8 {
|
||||
compatible = "ip-regulator-atf";
|
||||
regulator-name = "media2_subsys";
|
||||
hisilicon,hisi-regulator-id = <8>;
|
||||
hisilicon,hisi-regulator-type = <1>;
|
||||
hisilicon,hisi-regulator-clk-num = <0>;
|
||||
hisilicon,hisi-regulator-clk-check-flag = <0>;
|
||||
hisilicon,hisi-need-to-enable-clock = <0>;
|
||||
hisilicon,hisi-clock-rate-set-flag = <0>;
|
||||
hisilicon,hisi-clock-rate-set = <0>;
|
||||
hisilicon,hisi-ppll0-clock-rate-set-flag = <0>;
|
||||
hisilicon,hisi-ppll0-clock-rate-set = <0>;
|
||||
hisilicon,hisi-regulator-is-fake = <0>;
|
||||
};
|
||||
|
||||
vcodecsubsys: ip@2 {
|
||||
compatible = "ip-regulator-atf";
|
||||
regulator-name = "vcodecsubsys";
|
||||
hisi,noc-node-name = "peri_vcodec_bus";
|
||||
hisilicon,hisi-regulator-id = <2>;
|
||||
vcodecsubsys-supply = <&media2_subsys>;
|
||||
hisilicon,supply_name = "vcodecsubsys";
|
||||
hisilicon,hisi-regulator-type = <1>;
|
||||
hisilicon,hisi-regulator-clk-num = <0>;
|
||||
hisilicon,hisi-regulator-clk-check-flag = <0>;
|
||||
hisilicon,hisi-need-to-enable-clock = <0>;
|
||||
hisilicon,hisi-clock-rate-set-flag = <0>;
|
||||
hisilicon,hisi-clock-rate-set = <0>;
|
||||
hisilicon,hisi-ppll0-clock-rate-set-flag = <0>;
|
||||
hisilicon,hisi-ppll0-clock-rate-set = <0>;
|
||||
hisilicon,hisi-regulator-is-fake = <0>;
|
||||
};
|
||||
dsssubsys: ip@3 {
|
||||
compatible = "ip-regulator-atf";
|
||||
regulator-name = "dsssubsys";
|
||||
hisilicon,hisi-regulator-id = <3>;
|
||||
dsssubsys-supply = <&vivobus>;
|
||||
hisilicon,supply_name = "dsssubsys";
|
||||
hisilicon,hisi-regulator-type = <1>;
|
||||
hisilicon,hisi-regulator-clk-num = <0>;
|
||||
hisilicon,hisi-regulator-clk-check-flag = <0>;
|
||||
hisilicon,hisi-need-to-enable-clock = <0>;
|
||||
hisilicon,hisi-clock-rate-set-flag = <0>;
|
||||
hisilicon,hisi-clock-rate-set = <0>;
|
||||
hisilicon,hisi-ppll0-clock-rate-set-flag = <0>;
|
||||
hisilicon,hisi-ppll0-clock-rate-set = <0>;
|
||||
hisilicon,hisi-regulator-is-fake = <0>;
|
||||
hisilicon,hisi-regulator-dss-boot-check = <0x38 0xC0>;
|
||||
};
|
||||
ispsubsys: ip@4 {
|
||||
compatible = "ip-regulator-atf";
|
||||
regulator-name = "ispsubsys";
|
||||
hisilicon,hisi-regulator-id = <4>;
|
||||
ispsubsys-supply = <&vivobus>;
|
||||
hisilicon,supply_name = "ispsubsys";
|
||||
hisilicon,hisi-regulator-type = <1>;
|
||||
hisilicon,hisi-regulator-clk-num = <0>;
|
||||
hisilicon,hisi-regulator-clk-check-flag = <0>;
|
||||
hisilicon,hisi-need-to-enable-clock = <0>;
|
||||
hisilicon,hisi-clock-rate-set-flag = <0>;
|
||||
hisilicon,hisi-clock-rate-set = <0>;
|
||||
hisilicon,hisi-ppll0-clock-rate-set-flag = <0>;
|
||||
hisilicon,hisi-ppll0-clock-rate-set = <0>;
|
||||
hisilicon,hisi-regulator-is-fake = <0>;
|
||||
};
|
||||
vdec: ip@5 {
|
||||
compatible = "ip-regulator-atf";
|
||||
regulator-name = "vdec";
|
||||
hisilicon,hisi-regulator-id = <5>;
|
||||
vdec-supply = <&vcodecsubsys>;
|
||||
hisilicon,supply_name = "vdec";
|
||||
hisilicon,hisi-regulator-type = <1>;
|
||||
hisilicon,hisi-regulator-clk-num = <0>;
|
||||
hisilicon,hisi-regulator-clk-check-flag = <0>;
|
||||
hisilicon,hisi-need-to-enable-clock = <0>;
|
||||
hisilicon,hisi-clock-rate-set-flag = <0>;
|
||||
hisilicon,hisi-clock-rate-set = <0>;
|
||||
hisilicon,hisi-ppll0-clock-rate-set-flag = <0>;
|
||||
hisilicon,hisi-ppll0-clock-rate-set = <0>;
|
||||
hisilicon,hisi-regulator-is-fake = <0>;
|
||||
};
|
||||
venc: ip@6 {
|
||||
compatible = "ip-regulator-atf";
|
||||
regulator-name = "venc";
|
||||
hisilicon,hisi-regulator-id = <6>;
|
||||
venc-supply = <&vcodecsubsys>;
|
||||
hisilicon,supply_name = "venc";
|
||||
hisilicon,hisi-regulator-type = <1>;
|
||||
hisilicon,hisi-regulator-clk-num = <0>;
|
||||
hisilicon,hisi-regulator-clk-check-flag = <0>;
|
||||
hisilicon,hisi-need-to-enable-clock = <0>;
|
||||
hisilicon,hisi-clock-rate-set-flag = <0>;
|
||||
hisilicon,hisi-clock-rate-set = <0>;
|
||||
hisilicon,hisi-ppll0-clock-rate-set-flag = <0>;
|
||||
hisilicon,hisi-ppll0-clock-rate-set = <0>;
|
||||
hisilicon,hisi-regulator-is-fake = <0>;
|
||||
};
|
||||
isp_srt: ip@7 {
|
||||
compatible = "ip-regulator-atf";
|
||||
regulator-name = "isp_srt";
|
||||
hisilicon,hisi-regulator-id = <7>;
|
||||
isp_srt-supply = <&ispsubsys>;
|
||||
hisilicon,supply_name = "isp_srt";
|
||||
hisilicon,hisi-regulator-type = <1>;
|
||||
hisilicon,hisi-regulator-clk-num = <0>;
|
||||
hisilicon,hisi-regulator-clk-check-flag = <0>;
|
||||
hisilicon,hisi-need-to-enable-clock = <0>;
|
||||
hisilicon,hisi-clock-rate-set-flag = <0>;
|
||||
hisilicon,hisi-clock-rate-set = <0>;
|
||||
hisilicon,hisi-ppll0-clock-rate-set-flag = <0>;
|
||||
hisilicon,hisi-ppll0-clock-rate-set = <0>;
|
||||
hisilicon,hisi-regulator-is-fake = <0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -398,6 +398,8 @@ CONFIG_SPI_SPIDEV=m
|
||||
CONFIG_SPMI=y
|
||||
CONFIG_HISI_PMIC_PMU_SPMI=y
|
||||
CONFIG_HISI_REGULATOR_SPMI=y
|
||||
CONFIG_MFD_HISI_IP_CORE=y
|
||||
CONFIG_DRV_HISI_IP_REGULATOR=y
|
||||
CONFIG_PINCTRL_SINGLE=y
|
||||
CONFIG_PINCTRL_MAX77620=y
|
||||
CONFIG_PINCTRL_MSM8916=y
|
||||
|
||||
@@ -367,6 +367,12 @@ config HISI_PMIC_PMU_SPMI
|
||||
mapped I/O ports are the way of communication with it. and use spmi
|
||||
passageway read pmu address.
|
||||
|
||||
config MFD_HISI_IP_CORE
|
||||
tristate "Control HiSilicon system interior area Bus on and off"
|
||||
depends on OF
|
||||
help
|
||||
This driver control HiSilicon system interior area power management from atf.
|
||||
|
||||
config HTC_PASIC3
|
||||
tristate "HTC PASIC3 LED/DS1WM chip support"
|
||||
select MFD_CORE
|
||||
|
||||
@@ -202,6 +202,7 @@ obj-$(CONFIG_MFD_MENF21BMC) += menf21bmc.o
|
||||
obj-$(CONFIG_MFD_HI6421_PMIC) += hi6421-pmic-core.o
|
||||
obj-$(CONFIG_MFD_HI655X_PMIC) += hi655x-pmic.o
|
||||
obj-$(CONFIG_HISI_PMIC_PMU_SPMI) += hisi_pmic_spmi.o
|
||||
obj-$(CONFIG_MFD_HISI_IP_CORE) += hisi_ip_core.o
|
||||
obj-$(CONFIG_MFD_DLN2) += dln2.o
|
||||
obj-$(CONFIG_MFD_RT5033) += rt5033.o
|
||||
obj-$(CONFIG_MFD_SKY81452) += sky81452.o
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Device driver for hi3xxx power manger
|
||||
*
|
||||
* Copyright (c) 2013 Linaro Ltd.
|
||||
* Copyright (c) 2011 Hisilicon.
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/mfd/hisi_ip_core.h>
|
||||
|
||||
static DEFINE_MUTEX(reg_lock_mutex);
|
||||
|
||||
static struct of_device_id of_hisi_regulator_ip_core_child_match_tbl[] = {
|
||||
/* regulators */
|
||||
{
|
||||
.compatible = "ip-regulator-atf",
|
||||
},
|
||||
{ /* end */ }
|
||||
};
|
||||
|
||||
static struct of_device_id of_hisi_regulator_ip_core_match_tbl[] = {
|
||||
{
|
||||
.compatible = "hisilicon,hisi_regulator_ip_atf_core",
|
||||
},
|
||||
{ /* end */ }
|
||||
};
|
||||
|
||||
static int hisi_regulator_ip_core_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct hisi_regulator_ip_core *pmic = NULL;
|
||||
int ret = 0;
|
||||
|
||||
pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);
|
||||
if (!pmic) {
|
||||
dev_err(dev, "cannot allocate hisi_regulator_ip_core device info\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* get resources */
|
||||
pmic->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!pmic->res) {
|
||||
dev_err(dev, "platform_get_resource err !\n");
|
||||
return -ENOENT;/*lint !e429*/
|
||||
}
|
||||
|
||||
if (!devm_request_mem_region(dev, pmic->res->start,
|
||||
resource_size(pmic->res),
|
||||
pdev->name)) {
|
||||
dev_err(dev, "cannot claim register memory\n");
|
||||
return -ENOMEM;/*lint !e429*/
|
||||
}
|
||||
|
||||
pmic->regs = devm_ioremap(dev, pmic->res->start,
|
||||
resource_size(pmic->res));
|
||||
if (!pmic->regs) {
|
||||
dev_err(dev, "cannot map register memory\n");
|
||||
return -ENOMEM;/*lint !e429*/
|
||||
}
|
||||
platform_set_drvdata(pdev, pmic);
|
||||
|
||||
of_platform_populate(np, of_hisi_regulator_ip_core_child_match_tbl, NULL, dev);
|
||||
|
||||
return ret;/*lint !e429*/
|
||||
|
||||
}
|
||||
|
||||
static int hisi_regulator_ip_core_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct hisi_regulator_ip_core *pmic = platform_get_drvdata(pdev);
|
||||
|
||||
devm_iounmap(dev, pmic->regs);
|
||||
devm_release_mem_region(dev, pmic->res->start,
|
||||
resource_size(pmic->res));
|
||||
devm_kfree(dev, pmic);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver hisi_regulator_ip_core_driver = {
|
||||
.driver = {
|
||||
.name = "hisi_regulator_ip_core",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_hisi_regulator_ip_core_match_tbl,
|
||||
},
|
||||
.probe = hisi_regulator_ip_core_probe,
|
||||
.remove = hisi_regulator_ip_core_remove,
|
||||
};
|
||||
|
||||
static int __init hisi_regulator_ip_core_init(void)
|
||||
{
|
||||
return platform_driver_register(&hisi_regulator_ip_core_driver);
|
||||
}
|
||||
fs_initcall(hisi_regulator_ip_core_init);
|
||||
|
||||
static void __exit hisi_regulator_ip_core_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&hisi_regulator_ip_core_driver);
|
||||
}
|
||||
module_exit(hisi_regulator_ip_core_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Hisi regulator ip driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -295,6 +295,17 @@ config HISI_REGULATOR_SPMI
|
||||
This driver provides support for the voltage regulators on the
|
||||
HiSilicon Hisi PMU / Codec IC.
|
||||
|
||||
config DRV_HISI_IP_REGULATOR
|
||||
tristate "HiSilicon system interior bus mtcmos control"
|
||||
depends on MFD_HISI_IP_CORE
|
||||
help
|
||||
This driver provides system interior bus switch support for the IP regulator on the HiSilicon system.
|
||||
|
||||
config REGULATOR_IP_DEBUG
|
||||
tristate "HiSilicon system regulator ip debug"
|
||||
help
|
||||
This driver provides support for system ip control test.
|
||||
|
||||
config REGULATOR_ISL9305
|
||||
tristate "Intersil ISL9305 regulator"
|
||||
depends on I2C
|
||||
|
||||
@@ -38,6 +38,8 @@ obj-$(CONFIG_REGULATOR_HI6421) += hi6421-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_HI6421V530) += hi6421v530-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_HI655X) += hi655x-regulator.o
|
||||
obj-$(CONFIG_HISI_REGULATOR_SPMI) += hisi_regulator_spmi.o
|
||||
obj-$(CONFIG_DRV_HISI_IP_REGULATOR) += hisi_ip_regulator.o
|
||||
obj-$(CONFIG_REGULATOR_IP_DEBUG) += hisi_regulator_ip_debug.o
|
||||
obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_ISL9305) += isl9305.o
|
||||
obj-$(CONFIG_REGULATOR_LM363X) += lm363x-regulator.o
|
||||
|
||||
@@ -0,0 +1,858 @@
|
||||
/*
|
||||
* Device driver for regulators in Hi3xxx IC
|
||||
*
|
||||
* Copyright (c) 2013 Linaro Ltd.
|
||||
* Copyright (c) 2011 Hisilicon.
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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/slab.h>
|
||||
#include <asm/compiler.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/regulator/of_regulator.h>
|
||||
#include <linux/mfd/hisi_ip_core.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/version.h>
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
|
||||
#include <linux/clk-private.h>
|
||||
#endif
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/hwspinlock.h>
|
||||
#include <linux/hisi/hisi_rproc.h>
|
||||
#include <linux/clk-provider.h>
|
||||
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#if CONFIG_DEBUG_FS
|
||||
#define IP_REGULATOR_DEBUG(args...) pr_err(args);
|
||||
#else
|
||||
#define IP_REGULATOR_DEBUG(args...)
|
||||
#endif
|
||||
|
||||
enum ip_regulator_id {
|
||||
MEDIA1_SUBSYS_ID = 0,
|
||||
VIVOBUS_ID,
|
||||
VCODECSUBSYS_ID,
|
||||
DSSSUBSYS_ID,
|
||||
ISPSUBSYS_ID,
|
||||
VDEC_ID,
|
||||
VENC_ID,
|
||||
ISP_SRT_ID,
|
||||
MEDIA2_SUBSYS_ID,
|
||||
IP_REGULATOR_ID_MAX,
|
||||
};
|
||||
|
||||
/******************************macro parameter*********************************/
|
||||
enum {
|
||||
REGULATOR_DISABLE = 0,
|
||||
REGULATOR_ENABLE
|
||||
};
|
||||
|
||||
#define REGULATOR_HWLOCK_TIMEOUT 1000
|
||||
#define AP_AOD_EN 0
|
||||
#define SENSORHUB_AOD_EN 1
|
||||
|
||||
static struct hwspinlock *regulator_hwlock_29;
|
||||
|
||||
/*****************************ip struct parameter*****************************/
|
||||
struct hisi_regulator_ip {
|
||||
const char *name;
|
||||
struct device_node *np;
|
||||
struct regulator_desc rdesc;
|
||||
int (*dt_parse)(struct hisi_regulator_ip *, struct platform_device *);
|
||||
int regulator_id;
|
||||
struct mutex regulator_lock;
|
||||
u32 regulator_enalbe_flag;
|
||||
int regulator_fake;
|
||||
int regulator_type;
|
||||
int clock_num;
|
||||
int clock_check_flag;
|
||||
int enable_clock;
|
||||
int clock_set_rate_flag;
|
||||
unsigned int *clock_rate_value;
|
||||
unsigned int *clock_org_rate;
|
||||
unsigned int ppll0_clock_set_rate_flag;
|
||||
unsigned int ppll0_clock_rate_value;
|
||||
void __iomem *sctrl_reg;
|
||||
int hwlock_seq; /* aod hwlock sequnce*/
|
||||
u32 aod_sc_offset; /* SC offset */
|
||||
u32 dss_boot_check[2];
|
||||
};
|
||||
|
||||
#define DSS_SOFTRESET_STATE_CHECK_BIT 0
|
||||
|
||||
/*Always on display need to vote media1,vivobus power on/off in sctrl*/
|
||||
static int aod_set_and_get_poweron_state(struct hisi_regulator_ip *sreg, u32 control_flag)
|
||||
{
|
||||
int ret = 0;
|
||||
int bit_mask = 0;
|
||||
int val = 0;
|
||||
/*sctrl 0x438 : power state vote
|
||||
*bit[0]:AP media1 vote
|
||||
*bit[1]:Sensorhub media1 vote
|
||||
*bit[2]:AP vivobus vote
|
||||
*bit[3]:Sensorhub vivobus vote
|
||||
*bit[4]:AP dss vote
|
||||
*bit[5]:Sensorhub dss vote
|
||||
*/
|
||||
if (VIVOBUS_ID == sreg->regulator_id) {
|
||||
bit_mask = 2;
|
||||
} else if (DSSSUBSYS_ID == sreg->regulator_id) {
|
||||
bit_mask = 4;
|
||||
}
|
||||
|
||||
val = readl(sreg->sctrl_reg + sreg->aod_sc_offset);
|
||||
if (0 == (val & (BIT(SENSORHUB_AOD_EN)<<bit_mask)))
|
||||
ret = 0;
|
||||
else
|
||||
ret = 1;
|
||||
if (REGULATOR_ENABLE == control_flag) {
|
||||
/* vote AP media/vivobus power up */
|
||||
val |= (BIT(AP_AOD_EN)<<bit_mask);
|
||||
} else {
|
||||
/* vote AP media/vivobus power off */
|
||||
val &= ~(BIT(AP_AOD_EN)<<bit_mask);
|
||||
}
|
||||
writel(val, sreg->sctrl_reg + sreg->aod_sc_offset);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline struct hisi_regulator_ip_core *rdev_to_ip_core(struct regulator_dev *dev)
|
||||
{
|
||||
/* regulator_dev parent to->
|
||||
* hisi ip regulator platform device_dev parent to->
|
||||
* hisi ip pmic platform device_dev
|
||||
*/
|
||||
return dev_get_drvdata(rdev_get_dev(dev)->parent->parent);
|
||||
}
|
||||
|
||||
extern bool __clk_is_enabled(struct clk *clk);
|
||||
static struct clk *of_regulator_clk_get(struct device_node *node, int index)
|
||||
{
|
||||
struct clk *clk;
|
||||
const char *clk_name;
|
||||
int ret = 0;
|
||||
IP_REGULATOR_DEBUG("<[%s]: begin>\n", __func__);
|
||||
ret = of_property_read_string_index(node, "clock-names", index, &clk_name);
|
||||
if (ret != 0) {
|
||||
pr_err("failed to get regulator clk resource! ret=%d.\n", ret);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
clk = clk_get(NULL, clk_name);
|
||||
if (IS_ERR(clk)) {
|
||||
pr_err(" %s: %s %d get failed!\n", __func__, clk_name, __LINE__);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
IP_REGULATOR_DEBUG("<[%s]: end>\n", __func__);
|
||||
return clk;
|
||||
}
|
||||
|
||||
static int hisi_clock_state_check(struct hisi_regulator_ip *sreg)
|
||||
{
|
||||
struct clk *temp_clock;
|
||||
int i;
|
||||
bool clock_flag;
|
||||
IP_REGULATOR_DEBUG("<[%s]: begin regulator_id=%d>\n", __func__, sreg->regulator_id);
|
||||
for (i = 0; i < sreg->clock_num; i++) {
|
||||
temp_clock = of_regulator_clk_get(sreg->np, i);
|
||||
if (IS_ERR(temp_clock)) {
|
||||
temp_clock = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
IP_REGULATOR_DEBUG("<[%s]: clock_name=%s>\n", __func__, __clk_get_name(temp_clock));
|
||||
clock_flag = __clk_is_enabled(temp_clock);
|
||||
if (false == clock_flag) {
|
||||
pr_err("<[%s]: clock_name=%s had closed!>\n", __func__, __clk_get_name(temp_clock));
|
||||
}
|
||||
}
|
||||
IP_REGULATOR_DEBUG("<[%s]: end regulator_id=%d>\n", __func__, sreg->regulator_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_softreset_state(struct hisi_regulator_ip_core *pmic, struct hisi_regulator_ip *sreg, unsigned int value)
|
||||
{
|
||||
int ret = 0;
|
||||
int val = 0;
|
||||
/*First boot and AOD to camera need check DSS poweron status*/
|
||||
if (sreg->hwlock_seq > 0) {
|
||||
if (NULL == regulator_hwlock_29) {
|
||||
pr_err("[%s]regulator hwlock_29 hwspinlock is null!\n", __func__);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (hwspin_lock_timeout(regulator_hwlock_29, REGULATOR_HWLOCK_TIMEOUT)) {
|
||||
pr_err("Aod regulator enable hwspinlock timout!\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
IP_REGULATOR_DEBUG("<[%s]: sreg->dss_boot_check[0]=0x%x>\n", __func__, sreg->dss_boot_check[0]);
|
||||
IP_REGULATOR_DEBUG("<[%s]: regulator_id[%d] softreset_value=0x%x softreset_state3 = 0x%x>\n", __func__,
|
||||
sreg->regulator_id, sreg->dss_boot_check[1], readl((sreg->dss_boot_check[0]+ pmic->regs)));
|
||||
if (((sreg->dss_boot_check[1]) & (readl(sreg->dss_boot_check[0]+ pmic->regs))))
|
||||
ret = 0;/*softreset*/
|
||||
else
|
||||
ret = 1;/*unreset*/
|
||||
if (sreg->hwlock_seq > 0) {
|
||||
if(ret == 1){
|
||||
val = readl(sreg->sctrl_reg + sreg->aod_sc_offset);
|
||||
val |= (BIT(4));
|
||||
pr_err("[%s]AOD DSS vote val = 0x%x !\n", __func__, val);
|
||||
writel(val, sreg->sctrl_reg + sreg->aod_sc_offset);/*vote aod dss enable*/
|
||||
}
|
||||
hwspin_unlock(regulator_hwlock_29);
|
||||
}
|
||||
return ret;
|
||||
}/*lint !e715*/
|
||||
|
||||
static int hisi_ppll0_clock_rate_set(struct hisi_regulator_ip *sreg)
|
||||
{
|
||||
struct clk *temp_clock;
|
||||
int ret;
|
||||
|
||||
IP_REGULATOR_DEBUG("<[%s]: begin regulator_id=%d clock_num=%d>\n", __func__, sreg->regulator_id, sreg->clock_num);
|
||||
/*0:get current clock*/
|
||||
temp_clock = of_regulator_clk_get(sreg->np, 0);
|
||||
if (IS_ERR(temp_clock)) {
|
||||
temp_clock = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
IP_REGULATOR_DEBUG("<[%s]: clock_name=%s, clock_rate=0x%x>\n", __func__, __clk_get_name(temp_clock), sreg->ppll0_clock_rate_value);
|
||||
/*1:set freq rate to clock*/
|
||||
ret = clk_set_rate(temp_clock, sreg->ppll0_clock_rate_value);
|
||||
if (ret < 0) {
|
||||
pr_err("file:%s line:%d temp clock[%s] set rate fail!\n", __func__, __LINE__, __clk_get_name(temp_clock));
|
||||
return -EINVAL;
|
||||
}
|
||||
IP_REGULATOR_DEBUG("<[%s]: end regulator_id=%d>\n", __func__, sreg->regulator_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hisi_clock_rate_set(struct hisi_regulator_ip *sreg, int flag)
|
||||
{
|
||||
struct clk *temp_clock;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
IP_REGULATOR_DEBUG("<[%s]: begin regulator_id=%d clock_num=%d>\n", __func__, sreg->regulator_id, sreg->clock_num);
|
||||
if (0 == flag) {/*save*/
|
||||
for (i = 0; i < sreg->clock_num; i++) {
|
||||
if (0 == sreg->clock_rate_value[i])
|
||||
continue;
|
||||
/*0:get current clock*/
|
||||
temp_clock = of_regulator_clk_get(sreg->np, i);
|
||||
if (IS_ERR(temp_clock)) {
|
||||
temp_clock = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
IP_REGULATOR_DEBUG("<[%s]: clock_name=%s>\n", __func__, __clk_get_name(temp_clock));
|
||||
/*1:get clock org value*/
|
||||
sreg->clock_org_rate[i] = clk_get_rate(temp_clock);
|
||||
/*2:set low freq rate to clock*/
|
||||
ret = clk_set_rate(temp_clock, sreg->clock_rate_value[i]);
|
||||
if (ret < 0) {
|
||||
pr_err("file:%s line:%d temp clock[%s] set rate fail!\n", __func__, __LINE__, __clk_get_name(temp_clock));
|
||||
return -EINVAL;
|
||||
}
|
||||
IP_REGULATOR_DEBUG("<[%s]: begin clock_name = %s clock_org_rate[%d]=%d, clock_current_rate[%d]=%d>\n",
|
||||
__func__, __clk_get_name(temp_clock), i, sreg->clock_org_rate[i], i, sreg->clock_rate_value[i]);
|
||||
IP_REGULATOR_DEBUG("<[%s]: current clock_name[%s] rate[%ld]>\n", __func__,
|
||||
__clk_get_name(temp_clock), clk_get_rate(temp_clock));
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < sreg->clock_num; i++) {
|
||||
if (0 == sreg->clock_rate_value[i])
|
||||
continue;
|
||||
/*0:get current clock*/
|
||||
temp_clock = of_regulator_clk_get(sreg->np, i);
|
||||
if (IS_ERR(temp_clock)) {
|
||||
temp_clock = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
/*1:resume org clock rate*/
|
||||
ret = clk_set_rate(temp_clock, sreg->clock_org_rate[i]);
|
||||
if (ret < 0) {
|
||||
pr_err("file:%s line:%d temp clock[%s] set rate fail!\n", __func__, __LINE__, __clk_get_name(temp_clock));
|
||||
return -EINVAL;
|
||||
}
|
||||
IP_REGULATOR_DEBUG("<[%s]: end clock_name = %s clock_org_rate[%d]=%d>\n",
|
||||
__func__, __clk_get_name(temp_clock), i, sreg->clock_org_rate[i]);
|
||||
IP_REGULATOR_DEBUG("<[%s]: current clock_name[%s] rate[%ld]>\n", __func__,
|
||||
__clk_get_name(temp_clock), clk_get_rate(temp_clock));
|
||||
|
||||
}
|
||||
}
|
||||
IP_REGULATOR_DEBUG("<[%s]: end regulator_id=%d>\n", __func__, sreg->regulator_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hisi_ip_clock_work(struct hisi_regulator_ip *sreg, int flag)
|
||||
{
|
||||
struct clk *temp_clock;
|
||||
int i, ret = 0;
|
||||
IP_REGULATOR_DEBUG("<[%s]: begin regulator_id=%d, clock_num = %d>\n", __func__, sreg->regulator_id, sreg->clock_num);
|
||||
for (i = 0; i < sreg->clock_num; i++) {
|
||||
temp_clock = of_regulator_clk_get(sreg->np, i);
|
||||
if (IS_ERR(temp_clock)) {
|
||||
temp_clock = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
IP_REGULATOR_DEBUG("<[%s]: clock_name = %s>\n", __func__, __clk_get_name(temp_clock));
|
||||
/*flag: 0 disable clock; 1 enable clock*/
|
||||
if (flag == REGULATOR_ENABLE) {
|
||||
ret = clk_prepare_enable(temp_clock);
|
||||
if (ret) {
|
||||
pr_err("Regulator hi3630:regulator_id[%d],clock_id[%d] enable failed\r\n", sreg->regulator_id, i);
|
||||
clk_put(temp_clock);
|
||||
return ret;
|
||||
}
|
||||
IP_REGULATOR_DEBUG("<[%s]: clock_name = %s enable>\n", __func__, __clk_get_name(temp_clock));
|
||||
} else {
|
||||
IP_REGULATOR_DEBUG("<[%s]: clock_name = %s disable>\n", __func__, __clk_get_name(temp_clock));
|
||||
clk_disable_unprepare(temp_clock);
|
||||
clk_put(temp_clock);
|
||||
}
|
||||
}
|
||||
IP_REGULATOR_DEBUG("<[%s]: end regulator_id=%d>\n", __func__, sreg->regulator_id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**************************arm trust firmware****************************************/
|
||||
#define IP_REGULATOR_REGISTER_FN_ID (0xc500fff0)
|
||||
noinline int atfd_hisi_service_ip_regulator_smc(u64 function_id, u64 arg0, u64 arg1, u64 arg2)
|
||||
{
|
||||
asm volatile(
|
||||
__asmeq("%0", "x0")
|
||||
__asmeq("%1", "x1")
|
||||
__asmeq("%2", "x2")
|
||||
__asmeq("%3", "x3")
|
||||
"smc #0\n"
|
||||
: "+r" (function_id)
|
||||
: "r" (arg0), "r" (arg1), "r" (arg2));
|
||||
|
||||
return (int)function_id;
|
||||
}
|
||||
|
||||
static int hisi_ip_to_atf_is_enabled(struct regulator_dev *dev)
|
||||
{
|
||||
struct hisi_regulator_ip *sreg = rdev_get_drvdata(dev);
|
||||
struct hisi_regulator_ip_core *pmic = rdev_to_ip_core(dev);
|
||||
|
||||
if (sreg == NULL || pmic == NULL) {
|
||||
pr_err("[%s]regulator get para is err!\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
IP_REGULATOR_DEBUG("<[%s]:regulator_id=%d>\n", __func__, sreg->regulator_id);
|
||||
return sreg->regulator_enalbe_flag;
|
||||
}
|
||||
|
||||
static int hisi_ip_power_on(struct hisi_regulator_ip *sreg)
|
||||
{
|
||||
int ret = 0;
|
||||
int aod_ret = 0;
|
||||
if (sreg->hwlock_seq > 0) {
|
||||
if (NULL == regulator_hwlock_29) {
|
||||
pr_err("[%s] regulator hwlock_29 hwspinlock is null!\n", __func__);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (hwspin_lock_timeout(regulator_hwlock_29, REGULATOR_HWLOCK_TIMEOUT)) {
|
||||
pr_err("Aod regulator enable hwspinlock timout!\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
aod_ret = aod_set_and_get_poweron_state(sreg, REGULATOR_ENABLE);
|
||||
if (0 == aod_ret) {
|
||||
ret = atfd_hisi_service_ip_regulator_smc(IP_REGULATOR_REGISTER_FN_ID, sreg->regulator_id, REGULATOR_ENABLE, 0);
|
||||
} else if (1 == aod_ret) {
|
||||
ret = 0;
|
||||
} else {
|
||||
pr_err("%s:aod set and get poweron state [%s] failled!\n\r", __func__, sreg->name);
|
||||
}
|
||||
hwspin_unlock(regulator_hwlock_29);
|
||||
} else {
|
||||
ret = atfd_hisi_service_ip_regulator_smc(IP_REGULATOR_REGISTER_FN_ID, sreg->regulator_id, REGULATOR_ENABLE, 0);
|
||||
}
|
||||
IP_REGULATOR_DEBUG("%s:hisi ip enable ldo[%s] to atf, ret=%d\n\r", __func__, sreg->name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int hisi_ip_power_off(struct hisi_regulator_ip *sreg)
|
||||
{
|
||||
int ret = 0;
|
||||
int aod_ret = 0;
|
||||
if (sreg->hwlock_seq > 0) {
|
||||
if (NULL == regulator_hwlock_29) {
|
||||
pr_err("[%s] regulator hwlock_29 hwspinlock is null!\n", __func__);
|
||||
return -ENOENT;
|
||||
}
|
||||
if (hwspin_lock_timeout(regulator_hwlock_29, REGULATOR_HWLOCK_TIMEOUT)) {
|
||||
pr_err("Aod regulator enable hwspinlock timout!\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
aod_ret = aod_set_and_get_poweron_state(sreg, REGULATOR_DISABLE);
|
||||
if (0 == aod_ret)
|
||||
ret = atfd_hisi_service_ip_regulator_smc(IP_REGULATOR_REGISTER_FN_ID, sreg->regulator_id, REGULATOR_DISABLE, 0);
|
||||
else if (1 == aod_ret)
|
||||
ret = 0;
|
||||
else
|
||||
pr_err("%s:aod set and get poweroff state [%s] failled!\n\r", __func__, sreg->name);
|
||||
hwspin_unlock(regulator_hwlock_29);
|
||||
} else {
|
||||
ret = atfd_hisi_service_ip_regulator_smc(IP_REGULATOR_REGISTER_FN_ID, sreg->regulator_id, REGULATOR_DISABLE, 0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int hisi_ip_to_atf_enabled(struct regulator_dev *dev)
|
||||
{
|
||||
struct hisi_regulator_ip *sreg = rdev_get_drvdata(dev);
|
||||
struct hisi_regulator_ip_core *pmic = rdev_to_ip_core(dev);
|
||||
int ret = 0;
|
||||
int softreset_value;
|
||||
int dss_poweron_flag = 0;
|
||||
|
||||
if (sreg == NULL || pmic == NULL) {
|
||||
pr_err("[%s]regulator get para is err!\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
IP_REGULATOR_DEBUG("\n<[%s]: begin regulator_id=%d>\n", __func__, sreg->regulator_id);
|
||||
if (sreg->regulator_fake) {
|
||||
sreg->regulator_enalbe_flag = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*this patch was resolved for dss power on in fastboot phase*/
|
||||
if ((DSSSUBSYS_ID == sreg->regulator_id)) {
|
||||
softreset_value = get_softreset_state(pmic, sreg, DSS_SOFTRESET_STATE_CHECK_BIT);
|
||||
IP_REGULATOR_DEBUG("<[%s]: regulator_id[%d] softreset_bit=%d>\n", __func__, sreg->regulator_id, softreset_value);
|
||||
if (softreset_value) {
|
||||
IP_REGULATOR_DEBUG("<[%s]: regulator_id[%d] was poweron in fastboot phase>\n", __func__, sreg->regulator_id);
|
||||
dss_poweron_flag = 1;
|
||||
sreg->regulator_enalbe_flag = 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((1 == sreg->clock_set_rate_flag) && (dss_poweron_flag == 0)) {
|
||||
ret = hisi_clock_rate_set(sreg, 0);
|
||||
if (ret)
|
||||
pr_err("%s:hisi clock rate set fail!\n", __func__);
|
||||
}
|
||||
|
||||
if (1 == sreg->clock_check_flag) {
|
||||
ret = hisi_clock_state_check(sreg);
|
||||
if (ret)
|
||||
pr_err("%s:hisi clock state check fail!\n", __func__);
|
||||
|
||||
}
|
||||
|
||||
if (1 == sreg->enable_clock) {
|
||||
ret = hisi_ip_clock_work(sreg, REGULATOR_ENABLE);
|
||||
if (ret) {
|
||||
pr_err("[%s]hisi hisi_ip_clock_work is failed. ret[%d]!\n", __func__, ret);
|
||||
}
|
||||
}
|
||||
|
||||
ret = hisi_ip_power_on(sreg);
|
||||
if (0 == ret) {
|
||||
sreg->regulator_enalbe_flag = 1;
|
||||
} else {
|
||||
pr_err("%s:hisi ip send enable ldo[%s] to atf failled!\n\r", __func__, sreg->name);
|
||||
}
|
||||
|
||||
if ((1 == sreg->clock_set_rate_flag) && (dss_poweron_flag == 0)) {
|
||||
ret = hisi_clock_rate_set(sreg, 1);
|
||||
if (ret)
|
||||
pr_err("%s:hisi clock rate set fail!\n", __func__);
|
||||
}
|
||||
|
||||
IP_REGULATOR_DEBUG("<[%s]: end regulator_id=%d>\n", __func__, sreg->regulator_id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int hisi_ip_to_atf_disabled(struct regulator_dev *dev)
|
||||
{
|
||||
struct hisi_regulator_ip *sreg = rdev_get_drvdata(dev);
|
||||
int ret = 0;
|
||||
|
||||
if (sreg == NULL) {
|
||||
pr_err("[%s]regulator get para is err!\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
IP_REGULATOR_DEBUG("\n<[%s]: begin regulator_id=%d>\n", __func__, sreg->regulator_id);
|
||||
|
||||
if (sreg->regulator_fake) {
|
||||
sreg->regulator_enalbe_flag = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sreg->clock_check_flag) {
|
||||
ret = hisi_clock_state_check(sreg);
|
||||
if (ret)
|
||||
pr_err("%s:hisi clock state check fail!\n", __func__);
|
||||
}
|
||||
|
||||
ret = hisi_ip_power_off(sreg);
|
||||
if (!ret) {
|
||||
sreg->regulator_enalbe_flag = 0;
|
||||
ret = 0;
|
||||
} else {
|
||||
pr_err("%s:hisi ip send disable ldo[%s] to atf failled!\n\r", __func__, sreg->name);
|
||||
}
|
||||
|
||||
if (1 == sreg->ppll0_clock_set_rate_flag) {
|
||||
ret = hisi_ppll0_clock_rate_set(sreg);
|
||||
if (ret) {
|
||||
pr_err("[%s]hisi ppll0_clock_set_rate_flag set failed. ret[%d]!\n", __func__, ret);
|
||||
}
|
||||
}
|
||||
/*AOD need vivobus always on*/
|
||||
if (1 == sreg->enable_clock) {
|
||||
ret = hisi_ip_clock_work(sreg, REGULATOR_DISABLE);
|
||||
if (ret) {
|
||||
pr_err("[%s]hisi hisi_ip_clock_work is failed. ret[%d]!\n", __func__, ret);
|
||||
}
|
||||
}
|
||||
|
||||
IP_REGULATOR_DEBUG("<[%s]: end regulator_id=%d>\n", __func__, sreg->regulator_id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int hisi_dt_parse_aod_atf(struct hisi_regulator_ip *sreg, struct device_node *np)
|
||||
{
|
||||
u32 aod_resource[2] = {0};
|
||||
if (NULL != of_find_property(np, "hisilicon,hisi-need-to-hwlock", NULL)) {
|
||||
if (of_property_read_u32_array(np, "hisilicon,hisi-need-to-hwlock", aod_resource, 2)) {
|
||||
pr_err("[%s]get hisilicon,hisi-need-to-hwlock attribute failed.\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
sreg->hwlock_seq = aod_resource[0];
|
||||
sreg->aod_sc_offset= aod_resource[1];
|
||||
if (sreg->hwlock_seq > 0) {
|
||||
if (NULL == regulator_hwlock_29) {
|
||||
regulator_hwlock_29 = hwspin_lock_request_specific(sreg->hwlock_seq);
|
||||
if (NULL == regulator_hwlock_29) {
|
||||
pr_err("Aod regulator request hwspin lock failed !\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hisi_dt_parse_ip_atf(struct hisi_regulator_ip *sreg,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = NULL;
|
||||
struct device_node *np = NULL;
|
||||
int id = 0, fake = 0, type = 0;
|
||||
int ret = 0;
|
||||
unsigned int register_info[2] = {0};
|
||||
|
||||
if (sreg == NULL || pdev == NULL) {
|
||||
pr_err("[%s]regulator get dt para is err!\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev = &pdev->dev;
|
||||
np = dev->of_node;
|
||||
|
||||
/* regulator-id */
|
||||
ret = of_property_read_u32_array(np, "hisilicon,hisi-regulator-id",
|
||||
&id, 1);/*lint !e64*/
|
||||
if (ret) {
|
||||
dev_err(dev, "no hisilicon,hisi-regulator-id property set\n");
|
||||
goto dt_parse_common_end;
|
||||
}
|
||||
sreg->regulator_id = id;
|
||||
|
||||
/* regulator-type */
|
||||
ret = of_property_read_u32_array(np, "hisilicon,hisi-regulator-type",
|
||||
&type, 1);/*lint !e64*/
|
||||
if (ret) {
|
||||
dev_err(dev, "no hisilicon,hisi-regulator-type property set\n");
|
||||
goto dt_parse_common_end;
|
||||
}
|
||||
sreg->regulator_type = type;
|
||||
|
||||
/* regulator-fake */
|
||||
ret = of_property_read_u32_array(np, "hisilicon,hisi-regulator-is-fake",
|
||||
&fake, 1);/*lint !e64*/
|
||||
if (ret) {
|
||||
dev_err(dev, "no hisilicon,hisi-regulator-is-fake property set\n");
|
||||
goto dt_parse_common_end;
|
||||
}
|
||||
sreg->regulator_fake = fake;
|
||||
|
||||
/* clock_check_flag */
|
||||
ret = of_property_read_u32_array(np, "hisilicon,hisi-regulator-clk-check-flag",
|
||||
&sreg->clock_check_flag, 1);/*lint !e64*/
|
||||
if (ret) {
|
||||
dev_err(dev, "no hisilicon,hisi-regulator-clk-check-flag property set\n");
|
||||
goto dt_parse_common_end;
|
||||
}
|
||||
|
||||
/* clock_num*/
|
||||
ret = of_property_read_u32_array(np, "hisilicon,hisi-regulator-clk-num",
|
||||
&sreg->clock_num, 1);/*lint !e64*/
|
||||
if (ret) {
|
||||
dev_err(dev, "no hisilicon,hisi-regulator-clk-num property set\n");
|
||||
goto dt_parse_common_end;
|
||||
}
|
||||
|
||||
/* enable clock flag*/
|
||||
ret = of_property_read_u32_array(np, "hisilicon,hisi-need-to-enable-clock",
|
||||
&sreg->enable_clock, 1);/*lint !e64*/
|
||||
if (ret) {
|
||||
dev_err(dev, "no hisilicon,hisi-need-to-enable-clock property set\n");
|
||||
goto dt_parse_common_end;
|
||||
}
|
||||
|
||||
/* clock set rate flag*/
|
||||
ret = of_property_read_u32_array(np, "hisilicon,hisi-clock-rate-set-flag",
|
||||
&sreg->clock_set_rate_flag, 1);/*lint !e64*/
|
||||
if (ret) {
|
||||
dev_err(dev, "no hisilicon,hisi-clock-rate-set-flag property set\n");
|
||||
goto dt_parse_common_end;
|
||||
}
|
||||
|
||||
if (1 == sreg->clock_set_rate_flag) {
|
||||
/* clock rate*/
|
||||
sreg->clock_rate_value = (u32 *)devm_kzalloc(dev, sizeof(u32)*sreg->clock_num, GFP_KERNEL);
|
||||
if (!sreg->clock_rate_value) {
|
||||
dev_err(dev, "[%s]kzalloc clock_rate_value buffer failed.\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
sreg->clock_org_rate = (u32 *)devm_kzalloc(dev, sizeof(u32)*sreg->clock_num, GFP_KERNEL);
|
||||
if (!sreg->clock_org_rate) {
|
||||
dev_err(dev, "[%s]kzalloc clock_org_rate buffer failed.\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32_array(np, "hisilicon,hisi-clock-rate-set",
|
||||
sreg->clock_rate_value, sreg->clock_num);
|
||||
if (ret) {
|
||||
dev_err(dev, "[%s]get hisilicon,hisi-clock-rate-set-flag attribute failed.\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
/*ppll0 clock set rate flag*/
|
||||
ret = of_property_read_u32_array(np, "hisilicon,hisi-ppll0-clock-rate-set-flag",
|
||||
&sreg->ppll0_clock_set_rate_flag, 1);
|
||||
if (ret) {
|
||||
sreg->ppll0_clock_set_rate_flag = 0;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
IP_REGULATOR_DEBUG("<[%s]: regulator_id=%d, ppll0_clock_set_rate_flag=%d>\n",
|
||||
__func__, sreg->regulator_id, sreg->ppll0_clock_set_rate_flag);
|
||||
if (1 == sreg->ppll0_clock_set_rate_flag) {
|
||||
/* clock rate*/
|
||||
ret = of_property_read_u32_array(np, "hisilicon,hisi-ppll0-clock-rate-set",
|
||||
&sreg->ppll0_clock_rate_value, 1);
|
||||
if (ret) {
|
||||
dev_err(dev, "[%s]get hisilicon,hisi-ppll0-clock-rate-set-flag attribute failed.\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
if ((DSSSUBSYS_ID == sreg->regulator_id)) {
|
||||
of_property_read_u32_array(np, "hisilicon,hisi-regulator-dss-boot-check",
|
||||
register_info, 2);
|
||||
sreg->dss_boot_check[0] = register_info[0];
|
||||
sreg->dss_boot_check[1] = register_info[1];
|
||||
}
|
||||
|
||||
hisi_dt_parse_aod_atf(sreg, np);
|
||||
dt_parse_common_end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/******************************ip voltage region ops*************************/
|
||||
struct regulator_ops hisi_ip_atf_rops = {
|
||||
.is_enabled = hisi_ip_to_atf_is_enabled,
|
||||
.enable = hisi_ip_to_atf_enabled,
|
||||
.disable = hisi_ip_to_atf_disabled,
|
||||
};
|
||||
|
||||
/******************************hisi_regulator_ip******************************/
|
||||
static const struct hisi_regulator_ip hisi_regulator_ip_atf = {
|
||||
.rdesc = {
|
||||
.ops = &hisi_ip_atf_rops,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.dt_parse = hisi_dt_parse_ip_atf,
|
||||
};
|
||||
|
||||
/*********************of_hisi_regulator_ip_match_tbl***************************/
|
||||
static struct of_device_id of_hisi_regulator_ip_match_tbl[] = {
|
||||
{
|
||||
.compatible = "ip-regulator-atf",
|
||||
.data = &hisi_regulator_ip_atf,
|
||||
},
|
||||
{ /* end */ }
|
||||
};
|
||||
|
||||
static int hisi_regulator_ip_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = NULL;
|
||||
struct device_node *np = NULL;
|
||||
struct regulator_desc *rdesc;
|
||||
struct regulator_dev *rdev;
|
||||
struct hisi_regulator_ip *sreg = NULL;
|
||||
struct regulator_init_data *initdata;
|
||||
struct regulator_config config = { };
|
||||
const struct of_device_id *match;
|
||||
const struct hisi_regulator_ip *temp = NULL;
|
||||
int ret = 0;
|
||||
const char *supplyname = NULL;
|
||||
|
||||
if (pdev == NULL) {
|
||||
pr_err("[%s]regulator get platform device para is err!\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev = &pdev->dev;
|
||||
np = dev->of_node;
|
||||
|
||||
/* to check which type of regulator this is */
|
||||
match = of_match_device(of_hisi_regulator_ip_match_tbl, &pdev->dev);
|
||||
if (NULL == match) {
|
||||
pr_err("get hi6421 regulator fail!\n\r");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
temp = match->data;
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0))
|
||||
initdata = of_get_regulator_init_data(dev, np, NULL);
|
||||
#else
|
||||
initdata = of_get_regulator_init_data(dev, np);
|
||||
#endif
|
||||
if (NULL == initdata) {
|
||||
pr_err("get regulator init data error !\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sreg = kmemdup(temp, sizeof(*sreg), GFP_KERNEL);
|
||||
if (!sreg)
|
||||
return -ENOMEM;
|
||||
|
||||
sreg->name = initdata->constraints.name;
|
||||
rdesc = &sreg->rdesc;
|
||||
rdesc->name = sreg->name;
|
||||
|
||||
supplyname = of_get_property(np, "hisilicon,supply_name", NULL);
|
||||
if (supplyname != NULL) {
|
||||
initdata->supply_regulator = supplyname;
|
||||
}
|
||||
|
||||
mutex_init(&(sreg->regulator_lock));
|
||||
/* to parse device tree data for regulator specific */
|
||||
ret = sreg->dt_parse(sreg, pdev);
|
||||
if (ret) {
|
||||
dev_err(dev, "device tree parameter parse error!\n");
|
||||
goto hisi_ip_probe_end;
|
||||
}
|
||||
|
||||
config.dev = &pdev->dev;
|
||||
config.init_data = initdata;
|
||||
config.driver_data = sreg;
|
||||
config.of_node = pdev->dev.of_node;
|
||||
sreg->np = np;
|
||||
sreg->regulator_enalbe_flag = 0;
|
||||
np = NULL;
|
||||
np = of_find_compatible_node(NULL, NULL, "hisilicon,kirin970-sctrl");
|
||||
if (!np)
|
||||
pr_err("[%s] node doesn't have sysctrl node!\n", __func__);
|
||||
else
|
||||
sreg->sctrl_reg = of_iomap(np, 0);
|
||||
if (!sreg->sctrl_reg)
|
||||
pr_err("[%s] sysctrl iomap fail!\n", __func__);
|
||||
|
||||
/* register regulator */
|
||||
rdev = regulator_register(rdesc, &config);
|
||||
if (IS_ERR(rdev)) {
|
||||
dev_err(dev, "failed to register %s\n",
|
||||
rdesc->name);
|
||||
ret = PTR_ERR(rdev);
|
||||
goto hisi_ip_probe_end;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, rdev);
|
||||
|
||||
return 0;
|
||||
|
||||
hisi_ip_probe_end:
|
||||
kfree(sreg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int hisi_regulator_ip_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct regulator_dev *rdev = platform_get_drvdata(pdev);
|
||||
struct hisi_regulator_ip *sreg = rdev_get_drvdata(rdev);
|
||||
|
||||
|
||||
regulator_unregister(rdev);
|
||||
/* TODO: should i worry about that? devm_kzalloc */
|
||||
if (sreg->rdesc.volt_table)
|
||||
devm_kfree(&pdev->dev, (unsigned int *)sreg->rdesc.volt_table);
|
||||
|
||||
kfree(sreg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver hisi_regulator_ip_driver = {
|
||||
.driver = {
|
||||
.name = "hisi_regulator_ip",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_hisi_regulator_ip_match_tbl,
|
||||
},
|
||||
.probe = hisi_regulator_ip_probe,
|
||||
.remove = hisi_regulator_ip_remove,
|
||||
};
|
||||
|
||||
static int __init hisi_regulator_ip_init(void)
|
||||
{
|
||||
return platform_driver_register(&hisi_regulator_ip_driver);
|
||||
}
|
||||
fs_initcall(hisi_regulator_ip_init);
|
||||
|
||||
static void __exit hisi_regulator_ip_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&hisi_regulator_ip_driver);
|
||||
}
|
||||
module_exit(hisi_regulator_ip_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Hisi regulator ip driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Header file for device driver hi3xxx power manger
|
||||
*
|
||||
* Copyright (c) 2013 Linaro Ltd.
|
||||
* Copyright (C) 2011 Hisilicon.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef __HISI_IP_CORE_H
|
||||
#define __HISI_IP_CORE_H
|
||||
|
||||
struct hisi_regulator_ip_core {
|
||||
struct resource *res;
|
||||
struct device *dev;
|
||||
void __iomem *regs;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
/* Register Access Helpers */
|
||||
static inline u32 hisi_regulator_ip_core_read(struct hisi_regulator_ip_core *pmic, int reg)
|
||||
{
|
||||
return readl(pmic->regs + reg);
|
||||
}
|
||||
|
||||
static inline void hisi_regulator_ip_core_write(struct hisi_regulator_ip_core *pmic, int reg, u32 val)
|
||||
{
|
||||
writel(val, pmic->regs + reg);
|
||||
}
|
||||
|
||||
#endif /* __HISI_IP_CORE_H */
|
||||
Reference in New Issue
Block a user