From 46a7ad3f1c9fc7e5f6fb381ba2d005739bc26f63 Mon Sep 17 00:00:00 2001 From: Abhijeet Dharmapurikar Date: Sat, 23 Feb 2013 12:50:19 -0800 Subject: [PATCH] msm: krait-regulator: use phase management for v2 The PMIC 8841 v2 that comes with msm8974 v2 is capable of doing phase switching on ganged regulators. Enable this feature for v2. Change-Id: I21826f4cf7be332f5ab7621325fa6cbe6aa2ea95 Signed-off-by: Abhijeet Dharmapurikar --- .../bindings/regulator/krait-regulator.txt | 52 ++++-- arch/arm/boot/dts/msm8974-regulator.dtsi | 125 +++++++------- arch/arm/boot/dts/msm8974-v2.dtsi | 4 + arch/arm/mach-msm/krait-regulator.c | 155 +++++++++++------- include/linux/regulator/krait-regulator.h | 3 +- 5 files changed, 209 insertions(+), 130 deletions(-) diff --git a/Documentation/devicetree/bindings/regulator/krait-regulator.txt b/Documentation/devicetree/bindings/regulator/krait-regulator.txt index f0578347185..c783ac83918 100644 --- a/Documentation/devicetree/bindings/regulator/krait-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/krait-regulator.txt @@ -1,5 +1,20 @@ Krait Voltage regulators +The cpus are powered using a single supply powered by PMIC ganged regulators operating in +different phases. Individual kraits further can draw power from the single supply via +a LDO or a head switch (BHS). The first level node represents the PMIC ganged regulator +and its properties and encompasses second level nodes that represent the individual +krait LDO/BHS control regulator. + +[First Level Nodes] +Required properties: +- compatible: Must be "qcom,krait-pdn" + +Optional properties: +- qcom,use-phase-switching indicates whether the driver should add/shed phases on the PMIC + ganged regulator as cpus are hotplugged. + +[Second Level Nodes] Required properties: - compatible: Must be "qcom,krait-regulator" - reg: Specifies the address and size for this regulator device, @@ -27,19 +42,26 @@ Any property defined as part of the core regulator binding, defined in regulator.txt, can also be used. Example: - krait0_vreg: regulator@f9088000 { - compatible = "qcom,krait-regulator"; - regulator-name = "krait0"; - reg = <0xf9088000 0x1000>, /* APCS_ALIAS0_KPSS_ACS */ - <0xf908a800 0x1000>; /* APCS_ALIAS0_KPSS_MDD */ - reg-names = "acs", "mdd"; - regulator-min-microvolt = <500000>; - regulator-max-microvolt = <1100000>; - qcom,headroom-voltage = <150000>; - qcom,retention-voltage = <745000>; - qcom,ldo-default-voltage = <745000>; - qcom,ldo-threshold-voltage = <750000>; - qcom,ldo-delta-voltage = <50000>; - qcom,cpu-num = 0; - }; + krait_pdn: krait-pdn { + compatible = "qcom,krait-pdn"; + qcom,use-phase-switching; + #address-cells = <1>; + #size-cells = <1>; + ranges; + krait0_vreg: regulator@f9088000 { + compatible = "qcom,krait-regulator"; + regulator-name = "krait0"; + reg = <0xf9088000 0x1000>, /* APCS_ALIAS0_KPSS_ACS */ + <0xf908a800 0x1000>; /* APCS_ALIAS0_KPSS_MDD */ + reg-names = "acs", "mdd"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1100000>; + qcom,headroom-voltage = <150000>; + qcom,retention-voltage = <675000>; + qcom,ldo-default-voltage = <750000>; + qcom,ldo-threshold-voltage = <850000>; + qcom,ldo-delta-voltage = <50000>; + qcom,cpu-num = <0>; + }; + }; diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi index 1a6d9ba4bf9..2dad8e71ae2 100644 --- a/arch/arm/boot/dts/msm8974-regulator.dtsi +++ b/arch/arm/boot/dts/msm8974-regulator.dtsi @@ -423,68 +423,75 @@ }; / { - krait0_vreg: regulator@f9088000 { - compatible = "qcom,krait-regulator"; - regulator-name = "krait0"; - reg = <0xf9088000 0x1000>, /* APCS_ALIAS0_KPSS_ACS */ - <0xf908a800 0x1000>; /* APCS_ALIAS0_KPSS_MDD */ - reg-names = "acs", "mdd"; - regulator-min-microvolt = <500000>; - regulator-max-microvolt = <1100000>; - qcom,headroom-voltage = <150000>; - qcom,retention-voltage = <675000>; - qcom,ldo-default-voltage = <750000>; - qcom,ldo-threshold-voltage = <850000>; - qcom,ldo-delta-voltage = <50000>; - qcom,cpu-num = <0>; - }; + krait_pdn: krait-pdn { + compatible = "qcom,krait-pdn"; + #address-cells = <1>; + #size-cells = <1>; + ranges; - krait1_vreg: regulator@f9098000 { - compatible = "qcom,krait-regulator"; - regulator-name = "krait1"; - reg = <0xf9098000 0x1000>, /* APCS_ALIAS1_KPSS_ACS */ - <0xf909a800 0x1000>; /* APCS_ALIAS1_KPSS_MDD */ - reg-names = "acs", "mdd"; - regulator-min-microvolt = <500000>; - regulator-max-microvolt = <1100000>; - qcom,headroom-voltage = <150000>; - qcom,retention-voltage = <675000>; - qcom,ldo-default-voltage = <750000>; - qcom,ldo-threshold-voltage = <850000>; - qcom,ldo-delta-voltage = <50000>; - qcom,cpu-num = <1>; - }; + krait0_vreg: regulator@f9088000 { + compatible = "qcom,krait-regulator"; + regulator-name = "krait0"; + reg = <0xf9088000 0x1000>, /* APCS_ALIAS0_KPSS_ACS */ + <0xf908a800 0x1000>; /* APCS_ALIAS0_KPSS_MDD */ + reg-names = "acs", "mdd"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1100000>; + qcom,headroom-voltage = <150000>; + qcom,retention-voltage = <675000>; + qcom,ldo-default-voltage = <750000>; + qcom,ldo-threshold-voltage = <850000>; + qcom,ldo-delta-voltage = <50000>; + qcom,cpu-num = <0>; + }; - krait2_vreg: regulator@f90a8000 { - compatible = "qcom,krait-regulator"; - regulator-name = "krait2"; - reg = <0xf90a8000 0x1000>, /* APCS_ALIAS2_KPSS_ACS */ - <0xf90aa800 0x1000>; /* APCS_ALIAS2_KPSS_MDD */ - reg-names = "acs", "mdd"; - regulator-min-microvolt = <500000>; - regulator-max-microvolt = <1100000>; - qcom,headroom-voltage = <150000>; - qcom,retention-voltage = <675000>; - qcom,ldo-default-voltage = <750000>; - qcom,ldo-threshold-voltage = <850000>; - qcom,ldo-delta-voltage = <50000>; - qcom,cpu-num = <2>; - }; + krait1_vreg: regulator@f9098000 { + compatible = "qcom,krait-regulator"; + regulator-name = "krait1"; + reg = <0xf9098000 0x1000>, /* APCS_ALIAS1_KPSS_ACS */ + <0xf909a800 0x1000>; /* APCS_ALIAS1_KPSS_MDD */ + reg-names = "acs", "mdd"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1100000>; + qcom,headroom-voltage = <150000>; + qcom,retention-voltage = <675000>; + qcom,ldo-default-voltage = <750000>; + qcom,ldo-threshold-voltage = <850000>; + qcom,ldo-delta-voltage = <50000>; + qcom,cpu-num = <1>; + }; - krait3_vreg: regulator@f90b8000 { - compatible = "qcom,krait-regulator"; - regulator-name = "krait3"; - reg = <0xf90b8000 0x1000>, /* APCS_ALIAS3_KPSS_ACS */ - <0xf90ba800 0x1000>; /* APCS_ALIAS3_KPSS_MDD */ - reg-names = "acs", "mdd"; - regulator-min-microvolt = <500000>; - regulator-max-microvolt = <1100000>; - qcom,headroom-voltage = <150000>; - qcom,retention-voltage = <675000>; - qcom,ldo-default-voltage = <750000>; - qcom,ldo-threshold-voltage = <850000>; - qcom,ldo-delta-voltage = <50000>; - qcom,cpu-num = <3>; + krait2_vreg: regulator@f90a8000 { + compatible = "qcom,krait-regulator"; + regulator-name = "krait2"; + reg = <0xf90a8000 0x1000>, /* APCS_ALIAS2_KPSS_ACS */ + <0xf90aa800 0x1000>; /* APCS_ALIAS2_KPSS_MDD */ + reg-names = "acs", "mdd"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1100000>; + qcom,headroom-voltage = <150000>; + qcom,retention-voltage = <675000>; + qcom,ldo-default-voltage = <750000>; + qcom,ldo-threshold-voltage = <850000>; + qcom,ldo-delta-voltage = <50000>; + qcom,cpu-num = <2>; + }; + + krait3_vreg: regulator@f90b8000 { + compatible = "qcom,krait-regulator"; + regulator-name = "krait3"; + reg = <0xf90b8000 0x1000>, /* APCS_ALIAS3_KPSS_ACS */ + <0xf90ba800 0x1000>; /* APCS_ALIAS3_KPSS_MDD */ + reg-names = "acs", "mdd"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1100000>; + qcom,headroom-voltage = <150000>; + qcom,retention-voltage = <675000>; + qcom,ldo-default-voltage = <750000>; + qcom,ldo-threshold-voltage = <850000>; + qcom,ldo-delta-voltage = <50000>; + qcom,cpu-num = <3>; + }; }; spi_eth_vreg: spi_eth_phy_vreg { diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi index 1a7c6281f98..7e6c0bf964f 100644 --- a/arch/arm/boot/dts/msm8974-v2.dtsi +++ b/arch/arm/boot/dts/msm8974-v2.dtsi @@ -111,3 +111,7 @@ <2024000 1212000>, <2132000 1279000>; }; + +&krait_pdn { + qcom,use-phase-switching; +}; diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c index 0c1e279b4d1..dc0b7550e10 100644 --- a/arch/arm/mach-msm/krait-regulator.c +++ b/arch/arm/mach-msm/krait-regulator.c @@ -155,6 +155,7 @@ struct pmic_gang_vreg { bool pfm_mode; int pmic_min_uV_for_retention; bool retention_enabled; + bool use_phase_switching; }; static struct pmic_gang_vreg *the_gang; @@ -390,13 +391,17 @@ static int switch_to_using_ldo(struct krait_power_vreg *kvreg) return 0; } -static int set_pmic_gang_phases(int phase_count) +static int set_pmic_gang_phases(struct pmic_gang_vreg *pvreg, int phase_count) { - /* - * TODO : spm writes for phase control, - * pmic phase control is not working yet - */ - return 0; + pr_debug("programming phase_count = %d\n", phase_count); + if (pvreg->use_phase_switching) + /* + * note the PMIC sets the phase count to one more than + * the value in the register - hence subtract 1 from it + */ + return msm_spm_apcs_set_phase(phase_count - 1); + else + return 0; } static int set_pmic_gang_voltage(struct pmic_gang_vreg *pvreg, int uV) @@ -547,14 +552,19 @@ static unsigned int pmic_gang_set_phases(struct krait_power_vreg *from, int load_uA) { struct pmic_gang_vreg *pvreg = from->pvreg; - int phase_count = DIV_ROUND_UP(load_uA, LOAD_PER_PHASE) - 1; + int phase_count = DIV_ROUND_UP(load_uA, LOAD_PER_PHASE); int rc = 0; - if (phase_count < 0) - phase_count = 0; + if (phase_count <= 0) + phase_count = 1; + + /* Increase phases if it is less than the number of cpus online */ + if (phase_count < num_online_cpus()) { + phase_count = num_online_cpus(); + } if (phase_count != pvreg->pmic_phase_count) { - rc = set_pmic_gang_phases(phase_count); + rc = set_pmic_gang_phases(pvreg, phase_count); if (rc < 0) { dev_err(&from->rdev->dev, "%s failed set phase %d rc = %d\n", @@ -577,32 +587,6 @@ static unsigned int pmic_gang_set_phases(struct krait_power_vreg *from, return rc; } -static int __devinit pvreg_init(struct platform_device *pdev) -{ - struct pmic_gang_vreg *pvreg; - - pvreg = devm_kzalloc(&pdev->dev, - sizeof(struct pmic_gang_vreg), GFP_KERNEL); - if (!pvreg) { - pr_err("kzalloc failed.\n"); - return -ENOMEM; - } - - pvreg->name = "pmic_gang"; - pvreg->pmic_vmax_uV = PMIC_VOLTAGE_MIN; - pvreg->pmic_phase_count = 1; - pvreg->retention_enabled = true; - pvreg->pmic_min_uV_for_retention = INT_MAX; - - mutex_init(&pvreg->krait_power_vregs_lock); - INIT_LIST_HEAD(&pvreg->krait_power_vregs); - the_gang = pvreg; - - pr_debug("name=%s inited\n", pvreg->name); - - return 0; -} - static int krait_power_get_voltage(struct regulator_dev *rdev) { struct krait_power_vreg *kvreg = rdev_get_drvdata(rdev); @@ -925,24 +909,6 @@ static int __devinit krait_power_probe(struct platform_device *pdev) int ldo_delta_uV; int cpu_num; - /* Initialize the pmic gang if it hasn't been initialized already */ - if (the_gang == NULL) { - rc = pvreg_init(pdev); - if (rc < 0) { - dev_err(&pdev->dev, - "failed to init pmic gang rc = %d\n", rc); - return rc; - } - /* global initializtion */ - glb_init(pdev); - } - - if (dent == NULL) { - dent = debugfs_create_dir(KRAIT_REGULATOR_DRIVER_NAME, NULL); - debugfs_create_file("retention_uV", - 0644, dent, the_gang, &retention_fops); - } - if (pdev->dev.of_node) { /* Get init_data from device tree. */ init_data = of_get_regulator_init_data(&pdev->dev, @@ -1139,14 +1105,93 @@ static struct platform_driver krait_power_driver = { }, }; +static struct of_device_id krait_pdn_match_table[] = { + { .compatible = "qcom,krait-pdn", }, + {} +}; + +static int __devinit krait_pdn_probe(struct platform_device *pdev) +{ + int rc; + bool use_phase_switching = false; + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + struct pmic_gang_vreg *pvreg; + + if (!dev->of_node) { + dev_err(dev, "device tree information missing\n"); + return -ENODEV; + } + + use_phase_switching = of_property_read_bool(node, + "qcom,use-phase-switching"); + pvreg = devm_kzalloc(&pdev->dev, + sizeof(struct pmic_gang_vreg), GFP_KERNEL); + if (!pvreg) { + pr_err("kzalloc failed.\n"); + return 0; + } + + pvreg->name = "pmic_gang"; + pvreg->pmic_vmax_uV = PMIC_VOLTAGE_MIN; + pvreg->pmic_phase_count = -EINVAL; + pvreg->retention_enabled = true; + pvreg->pmic_min_uV_for_retention = INT_MAX; + pvreg->use_phase_switching = use_phase_switching; + + mutex_init(&pvreg->krait_power_vregs_lock); + INIT_LIST_HEAD(&pvreg->krait_power_vregs); + the_gang = pvreg; + + pr_debug("name=%s inited\n", pvreg->name); + + /* global initializtion */ + glb_init(pdev); + + rc = of_platform_populate(node, NULL, NULL, dev); + if (rc) { + dev_err(dev, "failed to add child nodes, rc=%d\n", rc); + return rc; + } + + dent = debugfs_create_dir(KRAIT_REGULATOR_DRIVER_NAME, NULL); + debugfs_create_file("retention_uV", + 0644, dent, the_gang, &retention_fops); + return 0; +} + +static int __devexit krait_pdn_remove(struct platform_device *pdev) +{ + the_gang = NULL; + debugfs_remove_recursive(dent); + return 0; +} + +static struct platform_driver krait_pdn_driver = { + .probe = krait_pdn_probe, + .remove = __devexit_p(krait_pdn_remove), + .driver = { + .name = KRAIT_PDN_DRIVER_NAME, + .of_match_table = krait_pdn_match_table, + .owner = THIS_MODULE, + }, +}; + int __init krait_power_init(void) { - return platform_driver_register(&krait_power_driver); + int rc = platform_driver_register(&krait_power_driver); + if (rc) { + pr_err("failed to add %s driver rc = %d\n", + KRAIT_REGULATOR_DRIVER_NAME, rc); + return rc; + } + return platform_driver_register(&krait_pdn_driver); } static void __exit krait_power_exit(void) { platform_driver_unregister(&krait_power_driver); + platform_driver_unregister(&krait_pdn_driver); } module_exit(krait_power_exit); diff --git a/include/linux/regulator/krait-regulator.h b/include/linux/regulator/krait-regulator.h index 836f9d629a1..b784531bf2a 100644 --- a/include/linux/regulator/krait-regulator.h +++ b/include/linux/regulator/krait-regulator.h @@ -13,7 +13,8 @@ #ifndef __KRAIT_REGULATOR_H__ #define __KRAIT_REGULATOR_H__ -#define KRAIT_REGULATOR_DRIVER_NAME "krait-power-regulator" +#define KRAIT_REGULATOR_DRIVER_NAME "krait-power-regulator" +#define KRAIT_PDN_DRIVER_NAME "krait-pdn" /** * krait_power_init - driver initialization function