Loading Documentation/devicetree/bindings/regulator/cpr3-hmss-regulator.txt +15 −1 Original line number Diff line number Diff line Loading @@ -37,6 +37,19 @@ HMSS specific properties: Value type: <string> Definition: should be "qcom,cpr3-msm8996-hmss-regulator" - interrupts Usage: required Value type: <prop-encoded-array> Definition: CPR interrupt specifier and a hardware closed-loop ceiling interrupt specifier. - interrupt-names Usage: required Value type: <stringlist> Definition: Interrupt names. This list must match up 1-to-1 with the interrupts specified in the 'interrupts' property. "cpr" and "ceiling" must be specified. - qcom,apm-ctrl Usage: required on systems that need APM management Value type: <phandle> Loading Loading @@ -181,7 +194,8 @@ apcc_cpr: cpr3-ctrl@99e8000 { reg-names = "cpr_ctrl", "fuse_base"; clocks = <&clock_gcc clk_gcc_hmss_rbcpr_clk>; clock-names = "core_clk"; interrupts = <0 48 0>; interrupts = <0 48 0>, <0 47 0>; interrupt-names = "cpr", "ceiling"; qcom,cpr-ctrl-name = "apcc"; qcom,cpr-sensor-time = <1000>; Loading Documentation/devicetree/bindings/regulator/cpr3-mmss-regulator.txt +1 −0 Original line number Diff line number Diff line Loading @@ -116,6 +116,7 @@ gfx_cpr: cpr3-ctrl@838000 { <&clock_mmss clk_mmss_mmagic_ahb_clk>; clock-names = "core_clk", "iface_clk", "bus_clk"; interrupts = <0 166 0>; interrupt-names = "cpr"; qcom,cpr-ctrl-name = "gfx"; qcom,cpr-sensor-time = <1000>; Loading Documentation/devicetree/bindings/regulator/cpr3-regulator.txt +10 −1 Original line number Diff line number Diff line Loading @@ -74,7 +74,16 @@ Platform independent properties: - interrupts Usage: required Value type: <prop-encoded-array> Definition: CPR interrupt specifier. Definition: CPR interrupt specifier and optionally a hardware closed-loop ceiling interrupt specifier. - interrupt-names Usage: required Value type: <stringlist> Definition: Interrupt names. This list must match up 1-to-1 with the interrupts specified in the 'interrupts' property. "cpr" must be specified. "ceiling" may be specified for some platforms. - qcom,cpr-sensor-time Usage: required Loading arch/arm/boot/dts/qcom/msm8996-regulator.dtsi +3 −1 Original line number Diff line number Diff line Loading @@ -551,7 +551,8 @@ reg-names = "cpr_ctrl", "fuse_base"; clocks = <&clock_gcc clk_gcc_hmss_rbcpr_clk>; clock-names = "core_clk"; interrupts = <0 48 0>; interrupts = <0 48 0>, <0 47 0>; interrupt-names = "cpr", "ceiling"; qcom,cpr-ctrl-name = "apcc"; qcom,cpr-sensor-time = <1000>; Loading Loading @@ -708,6 +709,7 @@ <&clock_mmss clk_mmss_mmagic_ahb_clk>; clock-names = "core_clk", "iface_clk", "bus_clk"; interrupts = <0 166 0>; interrupt-names = "cpr"; qcom,cpr-ctrl-name = "gfx"; qcom,cpr-sensor-time = <1000>; Loading drivers/regulator/cpr3-regulator.c +148 −8 Original line number Diff line number Diff line Loading @@ -34,6 +34,8 @@ #include <linux/regulator/of_regulator.h> #include <linux/regulator/kryo-regulator.h> #include <soc/qcom/spm.h> #include "cpr3-regulator.h" #define CPR3_REGULATOR_CORNER_INVALID (-1) Loading Loading @@ -121,6 +123,7 @@ /* Registers found only on controllers that support HW closed-loop. */ #define CPR3_REG_PD_THROTTLE 0xE8 #define CPR3_PD_THROTTLE_DISABLE 0x0 #define CPR3_REG_HW_CLOSED_LOOP 0x3000 #define CPR3_HW_CLOSED_LOOP_ENABLE 0x0 Loading Loading @@ -493,9 +496,8 @@ static int cpr3_regulator_init_ctrl(struct cpr3_controller *ctrl) ? CPR3_HW_CLOSED_LOOP_ENABLE : CPR3_HW_CLOSED_LOOP_DISABLE); val = ctrl->proc_clock_throttle; cpr3_write(ctrl, CPR3_REG_PD_THROTTLE, val); cpr3_debug(ctrl, "PD_THROTTLE=0x%08X\n", val); cpr3_debug(ctrl, "PD_THROTTLE=0x%08X\n", ctrl->proc_clock_throttle); } if (ctrl->use_hw_closed_loop) { Loading @@ -505,6 +507,12 @@ static int cpr3_regulator_init_ctrl(struct cpr3_controller *ctrl) rc); return rc; } rc = msm_spm_avs_enable_irq(0, MSM_SPM_AVS_IRQ_MAX); if (rc) { cpr3_err(ctrl, "could not enable max IRQ, rc=%d\n", rc); return rc; } } /* Ensure that all register writes complete before disabling clocks. */ Loading Loading @@ -1091,6 +1099,17 @@ static int cpr3_regulator_update_ctrl_state(struct cpr3_controller *ctrl) = thread->current_corner; } if (ctrl->proc_clock_throttle) { if (aggr_corner.ceiling_volt > aggr_corner.floor_volt && (ctrl->use_hw_closed_loop || new_volt < aggr_corner.ceiling_volt)) cpr3_write(ctrl, CPR3_REG_PD_THROTTLE, ctrl->proc_clock_throttle); else cpr3_write(ctrl, CPR3_REG_PD_THROTTLE, CPR3_PD_THROTTLE_DISABLE); } /* * Ensure that all CPR register writes complete before * re-enabling CPR loop operation. Loading Loading @@ -1491,8 +1510,9 @@ static irqreturn_t cpr3_irq_handler(int irq, void *data) cpr3_debug(ctrl, "CPR interrupt received but no up or down status bit is set\n"); goto done; } else if (up && down) { cpr3_err(ctrl, "both up and down status bits set\n"); goto done; cpr3_debug(ctrl, "both up and down status bits set\n"); /* The up flag takes precedence over the down flag. */ down = false; } for (i = 0; i < ctrl->thread_count; i++) { Loading Loading @@ -1525,6 +1545,11 @@ static irqreturn_t cpr3_irq_handler(int irq, void *data) cpr3_debug(ctrl, "%s: new_volt=%d uV, last_volt=%d uV\n", up ? "UP" : "DN", new_volt, last_volt); if (ctrl->proc_clock_throttle && last_volt == aggr->ceiling_volt && new_volt < last_volt) cpr3_write(ctrl, CPR3_REG_PD_THROTTLE, ctrl->proc_clock_throttle); if (new_volt != last_volt) { rc = regulator_set_voltage(ctrl->vdd_regulator, new_volt, aggr->ceiling_volt); Loading @@ -1536,6 +1561,10 @@ static irqreturn_t cpr3_irq_handler(int irq, void *data) cont = CPR3_CONT_CMD_ACK; } if (ctrl->proc_clock_throttle && new_volt == aggr->ceiling_volt) cpr3_write(ctrl, CPR3_REG_PD_THROTTLE, CPR3_PD_THROTTLE_DISABLE); corner = &ctrl->thread[0].corner[ctrl->thread[0].current_corner]; if (irq_en != aggr->irq_en) { Loading @@ -1558,6 +1587,60 @@ done: return IRQ_HANDLED; } /** * cpr3_ceiling_irq_handler() - CPR ceiling reached interrupt handler callback * function used for hardware closed-loop operation * @irq: CPR ceiling interrupt number * @data: Private data corresponding to the CPR3 controller * pointer * * This function disables processor clock throttling and closed-loop operation * when the ceiling voltage is reached. * * Return: IRQ_HANDLED */ static irqreturn_t cpr3_ceiling_irq_handler(int irq, void *data) { struct cpr3_controller *ctrl = data; int rc, volt; mutex_lock(&ctrl->lock); if (!ctrl->cpr_enabled) { cpr3_debug(ctrl, "CPR ceiling interrupt received but CPR is disabled\n"); goto done; } else if (!ctrl->use_hw_closed_loop) { cpr3_debug(ctrl, "CPR ceiling interrupt received but CPR is using SW closed-loop\n"); goto done; } volt = regulator_get_voltage(ctrl->vdd_regulator); if (volt < 0) { cpr3_err(ctrl, "could not get vdd voltage, rc=%d\n", volt); goto done; } else if (volt != ctrl->aggr_corner.ceiling_volt) { cpr3_debug(ctrl, "CPR ceiling interrupt received but vdd voltage: %d uV != ceiling voltage: %d uV\n", volt, ctrl->aggr_corner.ceiling_volt); goto done; } /* * Since the ceiling voltage has been reached, disable processor clock * throttling as well as CPR closed-loop operation. */ cpr3_write(ctrl, CPR3_REG_PD_THROTTLE, CPR3_PD_THROTTLE_DISABLE); cpr3_ctrl_loop_disable(ctrl); cpr3_debug(ctrl, "CPR closed-loop and throttling disabled\n"); done: rc = msm_spm_avs_clear_irq(0, MSM_SPM_AVS_IRQ_MAX); if (rc) cpr3_err(ctrl, "could not clear max IRQ, rc=%d\n", rc); mutex_unlock(&ctrl->lock); return IRQ_HANDLED; } /** * cpr3_regulator_thread_register() - register a regulator device for a CPR3 * thread Loading Loading @@ -2176,6 +2259,21 @@ static int cpr3_debug_closed_loop_enable_set(void *data, u64 val) goto done; } if (ctrl->proc_clock_throttle && !ctrl->cpr_enabled) { rc = cpr3_clock_enable(ctrl); if (rc) { cpr3_err(ctrl, "clock enable failed, rc=%d\n", rc); goto done; } ctrl->cpr_enabled = true; cpr3_write(ctrl, CPR3_REG_PD_THROTTLE, CPR3_PD_THROTTLE_DISABLE); cpr3_clock_disable(ctrl); ctrl->cpr_enabled = false; } cpr3_debug(ctrl, "closed-loop=%s\n", enable ? "enabled" : "disabled"); done: Loading Loading @@ -2267,6 +2365,12 @@ static int cpr3_debug_hw_closed_loop_enable_set(void *data, u64 val) rc); goto done; } rc = msm_spm_avs_enable_irq(0, MSM_SPM_AVS_IRQ_MAX); if (rc) { cpr3_err(ctrl, "could not enable max IRQ, rc=%d\n", rc); goto done; } } else { rc = regulator_disable(ctrl->vdd_limit_regulator); if (rc) { Loading @@ -2274,6 +2378,13 @@ static int cpr3_debug_hw_closed_loop_enable_set(void *data, u64 val) rc); goto done; } rc = msm_spm_avs_disable_irq(0, MSM_SPM_AVS_IRQ_MAX); if (rc) { cpr3_err(ctrl, "could not disable max IRQ, rc=%d\n", rc); goto done; } } rc = cpr3_regulator_update_ctrl_state(ctrl); Loading Loading @@ -2601,10 +2712,25 @@ int cpr3_regulator_register(struct platform_device *pdev, } ctrl->cpr_ctrl_base = devm_ioremap(dev, res->start, resource_size(res)); ctrl->irq = platform_get_irq(pdev, 0); ctrl->irq = platform_get_irq_byname(pdev, "cpr"); if (ctrl->irq < 0) { cpr3_err(ctrl, "missing CPR interrupt\n"); return -EINVAL; return ctrl->irq; } if (ctrl->supports_hw_closed_loop) { rc = msm_spm_probe_done(); if (rc) { if (rc != -EPROBE_DEFER) cpr3_err(ctrl, "spm unavailable, rc=%d\n", rc); return rc; } ctrl->ceiling_irq = platform_get_irq_byname(pdev, "ceiling"); if (ctrl->ceiling_irq < 0) { cpr3_err(ctrl, "missing ceiling interrupt\n"); return ctrl->ceiling_irq; } } rc = cpr3_regulator_init_ctrl_data(ctrl); Loading Loading @@ -2649,6 +2775,18 @@ int cpr3_regulator_register(struct platform_device *pdev, goto free_regulators; } if (ctrl->supports_hw_closed_loop) { rc = devm_request_threaded_irq(dev, ctrl->ceiling_irq, NULL, cpr3_ceiling_irq_handler, IRQF_ONESHOT | IRQF_TRIGGER_RISING, "cpr3_ceiling", ctrl); if (rc) { cpr3_err(ctrl, "could not request ceiling IRQ %d, rc=%d\n", ctrl->ceiling_irq, rc); goto free_regulators; } } mutex_lock(&cpr3_controller_list_mutex); cpr3_regulator_debugfs_ctrl_add(ctrl); list_add(&ctrl->list, &cpr3_controller_list); Loading Loading @@ -2682,8 +2820,10 @@ int cpr3_regulator_unregister(struct cpr3_controller *ctrl) cpr3_ctrl_loop_disable(ctrl); cpr3_closed_loop_disable(ctrl); if (ctrl->use_hw_closed_loop) if (ctrl->use_hw_closed_loop) { regulator_disable(ctrl->vdd_limit_regulator); msm_spm_avs_disable_irq(0, MSM_SPM_AVS_IRQ_MAX); } for (i = 0; i < ctrl->thread_count; i++) regulator_unregister(ctrl->thread[i].rdev); Loading Loading
Documentation/devicetree/bindings/regulator/cpr3-hmss-regulator.txt +15 −1 Original line number Diff line number Diff line Loading @@ -37,6 +37,19 @@ HMSS specific properties: Value type: <string> Definition: should be "qcom,cpr3-msm8996-hmss-regulator" - interrupts Usage: required Value type: <prop-encoded-array> Definition: CPR interrupt specifier and a hardware closed-loop ceiling interrupt specifier. - interrupt-names Usage: required Value type: <stringlist> Definition: Interrupt names. This list must match up 1-to-1 with the interrupts specified in the 'interrupts' property. "cpr" and "ceiling" must be specified. - qcom,apm-ctrl Usage: required on systems that need APM management Value type: <phandle> Loading Loading @@ -181,7 +194,8 @@ apcc_cpr: cpr3-ctrl@99e8000 { reg-names = "cpr_ctrl", "fuse_base"; clocks = <&clock_gcc clk_gcc_hmss_rbcpr_clk>; clock-names = "core_clk"; interrupts = <0 48 0>; interrupts = <0 48 0>, <0 47 0>; interrupt-names = "cpr", "ceiling"; qcom,cpr-ctrl-name = "apcc"; qcom,cpr-sensor-time = <1000>; Loading
Documentation/devicetree/bindings/regulator/cpr3-mmss-regulator.txt +1 −0 Original line number Diff line number Diff line Loading @@ -116,6 +116,7 @@ gfx_cpr: cpr3-ctrl@838000 { <&clock_mmss clk_mmss_mmagic_ahb_clk>; clock-names = "core_clk", "iface_clk", "bus_clk"; interrupts = <0 166 0>; interrupt-names = "cpr"; qcom,cpr-ctrl-name = "gfx"; qcom,cpr-sensor-time = <1000>; Loading
Documentation/devicetree/bindings/regulator/cpr3-regulator.txt +10 −1 Original line number Diff line number Diff line Loading @@ -74,7 +74,16 @@ Platform independent properties: - interrupts Usage: required Value type: <prop-encoded-array> Definition: CPR interrupt specifier. Definition: CPR interrupt specifier and optionally a hardware closed-loop ceiling interrupt specifier. - interrupt-names Usage: required Value type: <stringlist> Definition: Interrupt names. This list must match up 1-to-1 with the interrupts specified in the 'interrupts' property. "cpr" must be specified. "ceiling" may be specified for some platforms. - qcom,cpr-sensor-time Usage: required Loading
arch/arm/boot/dts/qcom/msm8996-regulator.dtsi +3 −1 Original line number Diff line number Diff line Loading @@ -551,7 +551,8 @@ reg-names = "cpr_ctrl", "fuse_base"; clocks = <&clock_gcc clk_gcc_hmss_rbcpr_clk>; clock-names = "core_clk"; interrupts = <0 48 0>; interrupts = <0 48 0>, <0 47 0>; interrupt-names = "cpr", "ceiling"; qcom,cpr-ctrl-name = "apcc"; qcom,cpr-sensor-time = <1000>; Loading Loading @@ -708,6 +709,7 @@ <&clock_mmss clk_mmss_mmagic_ahb_clk>; clock-names = "core_clk", "iface_clk", "bus_clk"; interrupts = <0 166 0>; interrupt-names = "cpr"; qcom,cpr-ctrl-name = "gfx"; qcom,cpr-sensor-time = <1000>; Loading
drivers/regulator/cpr3-regulator.c +148 −8 Original line number Diff line number Diff line Loading @@ -34,6 +34,8 @@ #include <linux/regulator/of_regulator.h> #include <linux/regulator/kryo-regulator.h> #include <soc/qcom/spm.h> #include "cpr3-regulator.h" #define CPR3_REGULATOR_CORNER_INVALID (-1) Loading Loading @@ -121,6 +123,7 @@ /* Registers found only on controllers that support HW closed-loop. */ #define CPR3_REG_PD_THROTTLE 0xE8 #define CPR3_PD_THROTTLE_DISABLE 0x0 #define CPR3_REG_HW_CLOSED_LOOP 0x3000 #define CPR3_HW_CLOSED_LOOP_ENABLE 0x0 Loading Loading @@ -493,9 +496,8 @@ static int cpr3_regulator_init_ctrl(struct cpr3_controller *ctrl) ? CPR3_HW_CLOSED_LOOP_ENABLE : CPR3_HW_CLOSED_LOOP_DISABLE); val = ctrl->proc_clock_throttle; cpr3_write(ctrl, CPR3_REG_PD_THROTTLE, val); cpr3_debug(ctrl, "PD_THROTTLE=0x%08X\n", val); cpr3_debug(ctrl, "PD_THROTTLE=0x%08X\n", ctrl->proc_clock_throttle); } if (ctrl->use_hw_closed_loop) { Loading @@ -505,6 +507,12 @@ static int cpr3_regulator_init_ctrl(struct cpr3_controller *ctrl) rc); return rc; } rc = msm_spm_avs_enable_irq(0, MSM_SPM_AVS_IRQ_MAX); if (rc) { cpr3_err(ctrl, "could not enable max IRQ, rc=%d\n", rc); return rc; } } /* Ensure that all register writes complete before disabling clocks. */ Loading Loading @@ -1091,6 +1099,17 @@ static int cpr3_regulator_update_ctrl_state(struct cpr3_controller *ctrl) = thread->current_corner; } if (ctrl->proc_clock_throttle) { if (aggr_corner.ceiling_volt > aggr_corner.floor_volt && (ctrl->use_hw_closed_loop || new_volt < aggr_corner.ceiling_volt)) cpr3_write(ctrl, CPR3_REG_PD_THROTTLE, ctrl->proc_clock_throttle); else cpr3_write(ctrl, CPR3_REG_PD_THROTTLE, CPR3_PD_THROTTLE_DISABLE); } /* * Ensure that all CPR register writes complete before * re-enabling CPR loop operation. Loading Loading @@ -1491,8 +1510,9 @@ static irqreturn_t cpr3_irq_handler(int irq, void *data) cpr3_debug(ctrl, "CPR interrupt received but no up or down status bit is set\n"); goto done; } else if (up && down) { cpr3_err(ctrl, "both up and down status bits set\n"); goto done; cpr3_debug(ctrl, "both up and down status bits set\n"); /* The up flag takes precedence over the down flag. */ down = false; } for (i = 0; i < ctrl->thread_count; i++) { Loading Loading @@ -1525,6 +1545,11 @@ static irqreturn_t cpr3_irq_handler(int irq, void *data) cpr3_debug(ctrl, "%s: new_volt=%d uV, last_volt=%d uV\n", up ? "UP" : "DN", new_volt, last_volt); if (ctrl->proc_clock_throttle && last_volt == aggr->ceiling_volt && new_volt < last_volt) cpr3_write(ctrl, CPR3_REG_PD_THROTTLE, ctrl->proc_clock_throttle); if (new_volt != last_volt) { rc = regulator_set_voltage(ctrl->vdd_regulator, new_volt, aggr->ceiling_volt); Loading @@ -1536,6 +1561,10 @@ static irqreturn_t cpr3_irq_handler(int irq, void *data) cont = CPR3_CONT_CMD_ACK; } if (ctrl->proc_clock_throttle && new_volt == aggr->ceiling_volt) cpr3_write(ctrl, CPR3_REG_PD_THROTTLE, CPR3_PD_THROTTLE_DISABLE); corner = &ctrl->thread[0].corner[ctrl->thread[0].current_corner]; if (irq_en != aggr->irq_en) { Loading @@ -1558,6 +1587,60 @@ done: return IRQ_HANDLED; } /** * cpr3_ceiling_irq_handler() - CPR ceiling reached interrupt handler callback * function used for hardware closed-loop operation * @irq: CPR ceiling interrupt number * @data: Private data corresponding to the CPR3 controller * pointer * * This function disables processor clock throttling and closed-loop operation * when the ceiling voltage is reached. * * Return: IRQ_HANDLED */ static irqreturn_t cpr3_ceiling_irq_handler(int irq, void *data) { struct cpr3_controller *ctrl = data; int rc, volt; mutex_lock(&ctrl->lock); if (!ctrl->cpr_enabled) { cpr3_debug(ctrl, "CPR ceiling interrupt received but CPR is disabled\n"); goto done; } else if (!ctrl->use_hw_closed_loop) { cpr3_debug(ctrl, "CPR ceiling interrupt received but CPR is using SW closed-loop\n"); goto done; } volt = regulator_get_voltage(ctrl->vdd_regulator); if (volt < 0) { cpr3_err(ctrl, "could not get vdd voltage, rc=%d\n", volt); goto done; } else if (volt != ctrl->aggr_corner.ceiling_volt) { cpr3_debug(ctrl, "CPR ceiling interrupt received but vdd voltage: %d uV != ceiling voltage: %d uV\n", volt, ctrl->aggr_corner.ceiling_volt); goto done; } /* * Since the ceiling voltage has been reached, disable processor clock * throttling as well as CPR closed-loop operation. */ cpr3_write(ctrl, CPR3_REG_PD_THROTTLE, CPR3_PD_THROTTLE_DISABLE); cpr3_ctrl_loop_disable(ctrl); cpr3_debug(ctrl, "CPR closed-loop and throttling disabled\n"); done: rc = msm_spm_avs_clear_irq(0, MSM_SPM_AVS_IRQ_MAX); if (rc) cpr3_err(ctrl, "could not clear max IRQ, rc=%d\n", rc); mutex_unlock(&ctrl->lock); return IRQ_HANDLED; } /** * cpr3_regulator_thread_register() - register a regulator device for a CPR3 * thread Loading Loading @@ -2176,6 +2259,21 @@ static int cpr3_debug_closed_loop_enable_set(void *data, u64 val) goto done; } if (ctrl->proc_clock_throttle && !ctrl->cpr_enabled) { rc = cpr3_clock_enable(ctrl); if (rc) { cpr3_err(ctrl, "clock enable failed, rc=%d\n", rc); goto done; } ctrl->cpr_enabled = true; cpr3_write(ctrl, CPR3_REG_PD_THROTTLE, CPR3_PD_THROTTLE_DISABLE); cpr3_clock_disable(ctrl); ctrl->cpr_enabled = false; } cpr3_debug(ctrl, "closed-loop=%s\n", enable ? "enabled" : "disabled"); done: Loading Loading @@ -2267,6 +2365,12 @@ static int cpr3_debug_hw_closed_loop_enable_set(void *data, u64 val) rc); goto done; } rc = msm_spm_avs_enable_irq(0, MSM_SPM_AVS_IRQ_MAX); if (rc) { cpr3_err(ctrl, "could not enable max IRQ, rc=%d\n", rc); goto done; } } else { rc = regulator_disable(ctrl->vdd_limit_regulator); if (rc) { Loading @@ -2274,6 +2378,13 @@ static int cpr3_debug_hw_closed_loop_enable_set(void *data, u64 val) rc); goto done; } rc = msm_spm_avs_disable_irq(0, MSM_SPM_AVS_IRQ_MAX); if (rc) { cpr3_err(ctrl, "could not disable max IRQ, rc=%d\n", rc); goto done; } } rc = cpr3_regulator_update_ctrl_state(ctrl); Loading Loading @@ -2601,10 +2712,25 @@ int cpr3_regulator_register(struct platform_device *pdev, } ctrl->cpr_ctrl_base = devm_ioremap(dev, res->start, resource_size(res)); ctrl->irq = platform_get_irq(pdev, 0); ctrl->irq = platform_get_irq_byname(pdev, "cpr"); if (ctrl->irq < 0) { cpr3_err(ctrl, "missing CPR interrupt\n"); return -EINVAL; return ctrl->irq; } if (ctrl->supports_hw_closed_loop) { rc = msm_spm_probe_done(); if (rc) { if (rc != -EPROBE_DEFER) cpr3_err(ctrl, "spm unavailable, rc=%d\n", rc); return rc; } ctrl->ceiling_irq = platform_get_irq_byname(pdev, "ceiling"); if (ctrl->ceiling_irq < 0) { cpr3_err(ctrl, "missing ceiling interrupt\n"); return ctrl->ceiling_irq; } } rc = cpr3_regulator_init_ctrl_data(ctrl); Loading Loading @@ -2649,6 +2775,18 @@ int cpr3_regulator_register(struct platform_device *pdev, goto free_regulators; } if (ctrl->supports_hw_closed_loop) { rc = devm_request_threaded_irq(dev, ctrl->ceiling_irq, NULL, cpr3_ceiling_irq_handler, IRQF_ONESHOT | IRQF_TRIGGER_RISING, "cpr3_ceiling", ctrl); if (rc) { cpr3_err(ctrl, "could not request ceiling IRQ %d, rc=%d\n", ctrl->ceiling_irq, rc); goto free_regulators; } } mutex_lock(&cpr3_controller_list_mutex); cpr3_regulator_debugfs_ctrl_add(ctrl); list_add(&ctrl->list, &cpr3_controller_list); Loading Loading @@ -2682,8 +2820,10 @@ int cpr3_regulator_unregister(struct cpr3_controller *ctrl) cpr3_ctrl_loop_disable(ctrl); cpr3_closed_loop_disable(ctrl); if (ctrl->use_hw_closed_loop) if (ctrl->use_hw_closed_loop) { regulator_disable(ctrl->vdd_limit_regulator); msm_spm_avs_disable_irq(0, MSM_SPM_AVS_IRQ_MAX); } for (i = 0; i < ctrl->thread_count; i++) regulator_unregister(ctrl->thread[i].rdev); Loading