Loading Documentation/devicetree/bindings/power/qcom/apm.txt +17 −1 Original line number Diff line number Diff line Loading @@ -7,7 +7,7 @@ SRAM minimum operating voltage, the APM controller can be used to request a switch to a power supply that will guarantee logic state retention. Required properties - compatible: "qcom,msm-apm" - compatible: "qcom,msm-apm", "qcom,msmtitanium-apm" - reg: Specifies physical base address and size of memory mapped regions containing the APM controller, APCS CSR, APC PLL controller, and SPM event registers. Loading @@ -21,6 +21,18 @@ Optional properties clock sources to GPLL0 before the APM switch begins and to switch back to the original clock source after the APM switch completes. - qcom,apm-post-halt-delay: The APM controller post halt delay counter value that SW needs to program one time before starting the APM HW controller for msmtitanium target. - qcom,apm-halt-clk-delay: The APM controller halt clock delay counter value that SW needs to program one time before starting the APM HW controller for msmtitanium target. - qcom,apm-resume-clk-delay: The APM controller resume clock delay counter value that SW needs to program one time before starting the APM HW controller for msmtitanium target. - qcom,apm-sel-switch-delay: The APM controller switch selection delay counter value that SW needs to program one time before starting the APM HW controller for msmtitanium target. MSM APM Users Loading Loading @@ -50,6 +62,10 @@ Example: "apc1-cpu1-spm", "apc0-l2-spm", "apc1-l2-spm"; qcom,apm-post-halt-delay = <0x2>; qcom,apm-halt-clk-delay = <0x11>; qcom,apm-resume-clk-delay = <0x10>; qcom,apm-sel-switch-delay = <0x01>; foo_user { ... Loading drivers/power/qcom/apm.c +284 −11 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ #include <linux/debugfs.h> #include <linux/delay.h> #include <linux/of_device.h> #include <linux/init.h> #include <linux/io.h> #include <linux/kernel.h> Loading Loading @@ -86,6 +87,13 @@ enum { CLOCK_ASSERT_TOGGLE, }; enum { MSM8996_ID, MSMTITANIUM_ID, }; static int msm_id[] = {MSM8996_ID, MSMTITANIUM_ID}; struct msm_apm_ctrl_dev { struct list_head list; struct device *dev; Loading @@ -99,6 +107,7 @@ struct msm_apm_ctrl_dev { bool clk_src_override; u32 version; struct dentry *debugfs; u32 msm_id; }; #if defined(CONFIG_DEBUG_FS) Loading Loading @@ -231,6 +240,117 @@ free_events: return ret; } /* Titanium register offset definition */ #define MSMTITANIUM_APM_DLY_CNTR 0x2ac /* Register field shift definitions */ #define APM_CTL_SEL_SWITCH_DLY_SHIFT 0 #define APM_CTL_RESUME_CLK_DLY_SHIFT 8 #define APM_CTL_HALT_CLK_DLY_SHIFT 16 #define APM_CTL_POST_HALT_DLY_SHIFT 24 /* Register field mask definitions */ #define APM_CTL_SEL_SWITCH_DLY_MASK GENMASK(7, 0) #define APM_CTL_RESUME_CLK_DLY_MASK GENMASK(15, 8) #define APM_CTL_HALT_CLK_DLY_MASK GENMASK(23, 16) #define APM_CTL_POST_HALT_DLY_MASK GENMASK(31, 24) /* * Get the resources associated with the msmtitanium APM controller from * device tree, remap all I/O addresses, and program the initial * register configuration required for the titanium APM controller device. */ static int msmtitanium_apm_ctrl_init(struct platform_device *pdev, struct msm_apm_ctrl_dev *ctrl) { struct device *dev = &pdev->dev; struct resource *res; u32 delay_counter, val = 0, regval = 0; int rc = 0; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pm-apcc-glb"); if (!res) { dev_err(dev, "Missing PM APCC Global register physical address\n"); return -ENODEV; } ctrl->reg_base = devm_ioremap(dev, res->start, resource_size(res)); if (!ctrl->reg_base) { dev_err(dev, "Failed to map PM APCC Global registers\n"); return -ENOMEM; } /* * Initial APM register configuration required before starting * APM HW controller. */ regval = readl_relaxed(ctrl->reg_base + MSMTITANIUM_APM_DLY_CNTR); val = regval; if (of_find_property(dev->of_node, "qcom,apm-post-halt-delay", NULL)) { rc = of_property_read_u32(dev->of_node, "qcom,apm-post-halt-delay", &delay_counter); if (rc < 0) { dev_err(dev, "apm-post-halt-delay read failed, rc = %d", rc); return rc; } val &= ~APM_CTL_POST_HALT_DLY_MASK; val |= (delay_counter << APM_CTL_POST_HALT_DLY_SHIFT) & APM_CTL_POST_HALT_DLY_MASK; } if (of_find_property(dev->of_node, "qcom,apm-halt-clk-delay", NULL)) { rc = of_property_read_u32(dev->of_node, "qcom,apm-halt-clk-delay", &delay_counter); if (rc < 0) { dev_err(dev, "apm-halt-clk-delay read failed, rc = %d", rc); return rc; } val &= ~APM_CTL_HALT_CLK_DLY_MASK; val |= (delay_counter << APM_CTL_HALT_CLK_DLY_SHIFT) & APM_CTL_HALT_CLK_DLY_MASK; } if (of_find_property(dev->of_node, "qcom,apm-resume-clk-delay", NULL)) { rc = of_property_read_u32(dev->of_node, "qcom,apm-resume-clk-delay", &delay_counter); if (rc < 0) { dev_err(dev, "apm-resume-clk-delay read failed, rc = %d", rc); return rc; } val &= ~APM_CTL_RESUME_CLK_DLY_MASK; val |= (delay_counter << APM_CTL_RESUME_CLK_DLY_SHIFT) & APM_CTL_RESUME_CLK_DLY_MASK; } if (of_find_property(dev->of_node, "qcom,apm-sel-switch-delay", NULL)) { rc = of_property_read_u32(dev->of_node, "qcom,apm-sel-switch-delay", &delay_counter); if (rc < 0) { dev_err(dev, "apm-sel-switch-delay read failed, rc = %d", rc); return rc; } val &= ~APM_CTL_SEL_SWITCH_DLY_MASK; val |= (delay_counter << APM_CTL_SEL_SWITCH_DLY_SHIFT) & APM_CTL_SEL_SWITCH_DLY_MASK; } if (val != regval) { writel_relaxed(val, ctrl->reg_base + MSMTITANIUM_APM_DLY_CNTR); /* make sure write completes before return */ mb(); } return rc; } static int msm_apm_secure_clock_source_override( struct msm_apm_ctrl_dev *ctrl_dev, bool enable) { Loading @@ -248,7 +368,7 @@ static int msm_apm_secure_clock_source_override( return 0; } static int msm_apm_switch_to_mx(struct msm_apm_ctrl_dev *ctrl_dev) static int msm8996_apm_switch_to_mx(struct msm_apm_ctrl_dev *ctrl_dev) { int i, timeout = MSM_APM_SWITCH_TIMEOUT_US; u32 regval; Loading Loading @@ -344,7 +464,7 @@ static int msm_apm_switch_to_mx(struct msm_apm_ctrl_dev *ctrl_dev) return ret; } static int msm_apm_switch_to_apcc(struct msm_apm_ctrl_dev *ctrl_dev) static int msm8996_apm_switch_to_apcc(struct msm_apm_ctrl_dev *ctrl_dev) { int i, timeout = MSM_APM_SWITCH_TIMEOUT_US; u32 regval; Loading Loading @@ -440,6 +560,130 @@ static int msm_apm_switch_to_apcc(struct msm_apm_ctrl_dev *ctrl_dev) return ret; } /* Titanium register value definitions */ #define MSMTITANIUM_APM_MX_MODE_VAL 0x00 #define MSMTITANIUM_APM_APCC_MODE_VAL 0x02 #define MSMTITANIUM_APM_MX_DONE_VAL 0x00 #define MSMTITANIUM_APM_APCC_DONE_VAL 0x02 /* Titanium register offset definitions */ #define MSMTITANIUM_APCC_APM_MODE 0x000002a8 #define MSMTITANIUM_APCC_APM_CTL_STS 0x000002b0 static int msmtitanium_apm_switch_to_mx(struct msm_apm_ctrl_dev *ctrl_dev) { int timeout = MSM_APM_SWITCH_TIMEOUT_US; u32 regval; int ret = 0; unsigned long flags; spin_lock_irqsave(&ctrl_dev->lock, flags); /* Switch arrays to MX supply and wait for its completion */ writel_relaxed(MSMTITANIUM_APM_MX_MODE_VAL, ctrl_dev->reg_base + MSMTITANIUM_APCC_APM_MODE); /* Ensure write above completes before delaying */ mb(); while (timeout > 0) { regval = readl_relaxed(ctrl_dev->reg_base + MSMTITANIUM_APCC_APM_CTL_STS); if ((regval & MSM_APM_CTL_STS_MASK) == MSMTITANIUM_APM_MX_DONE_VAL) break; udelay(1); timeout--; } if (timeout == 0) { ret = -ETIMEDOUT; dev_err(ctrl_dev->dev, "APCC to MX APM switch timed out. APCC_APM_CTL_STS=0x%x\n", regval); } else { ctrl_dev->supply = MSM_APM_SUPPLY_MX; dev_dbg(ctrl_dev->dev, "APM supply switched to MX\n"); } spin_unlock_irqrestore(&ctrl_dev->lock, flags); return ret; } static int msmtitanium_apm_switch_to_apcc(struct msm_apm_ctrl_dev *ctrl_dev) { int timeout = MSM_APM_SWITCH_TIMEOUT_US; u32 regval; int ret = 0; unsigned long flags; spin_lock_irqsave(&ctrl_dev->lock, flags); /* Switch arrays to APCC supply and wait for its completion */ writel_relaxed(MSMTITANIUM_APM_APCC_MODE_VAL, ctrl_dev->reg_base + MSMTITANIUM_APCC_APM_MODE); /* Ensure write above completes before delaying */ mb(); while (timeout > 0) { regval = readl_relaxed(ctrl_dev->reg_base + MSMTITANIUM_APCC_APM_CTL_STS); if ((regval & MSM_APM_CTL_STS_MASK) == MSMTITANIUM_APM_APCC_DONE_VAL) break; udelay(1); timeout--; } if (timeout == 0) { ret = -ETIMEDOUT; dev_err(ctrl_dev->dev, "MX to APCC APM switch timed out. APCC_APM_CTL_STS=0x%x\n", regval); } else { ctrl_dev->supply = MSM_APM_SUPPLY_APCC; dev_dbg(ctrl_dev->dev, "APM supply switched to APCC\n"); } spin_unlock_irqrestore(&ctrl_dev->lock, flags); return ret; } static int msm_apm_switch_to_mx(struct msm_apm_ctrl_dev *ctrl_dev) { int ret = 0; switch (ctrl_dev->msm_id) { case MSM8996_ID: ret = msm8996_apm_switch_to_mx(ctrl_dev); break; case MSMTITANIUM_ID: ret = msmtitanium_apm_switch_to_mx(ctrl_dev); break; } return ret; } static int msm_apm_switch_to_apcc(struct msm_apm_ctrl_dev *ctrl_dev) { int ret = 0; switch (ctrl_dev->msm_id) { case MSM8996_ID: ret = msm8996_apm_switch_to_apcc(ctrl_dev); break; case MSMTITANIUM_ID: ret = msmtitanium_apm_switch_to_apcc(ctrl_dev); break; } return ret; } /** * msm_apm_get_supply() - Returns the supply that is currently * powering the memory arrays Loading Loading @@ -623,10 +867,23 @@ static void apm_debugfs_base_remove(void) #endif static struct of_device_id msm_apm_match_table[] = { { .compatible = "qcom,msm-apm", .data = &msm_id[MSM8996_ID] }, { .compatible = "qcom,msmtitanium-apm", .data = &msm_id[MSMTITANIUM_ID] }, {} }; static int msm_apm_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct msm_apm_ctrl_dev *ctrl; const struct of_device_id *match; int ret = 0; dev_dbg(dev, "probing MSM Array Power Mux driver\n"); Loading @@ -636,6 +893,10 @@ static int msm_apm_probe(struct platform_device *pdev) return -ENODEV; } match = of_match_device(msm_apm_match_table, dev); if (!match) return -ENODEV; ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL); if (!ctrl) { dev_err(dev, "MSM APM controller memory allocation failed\n"); Loading @@ -645,13 +906,30 @@ static int msm_apm_probe(struct platform_device *pdev) INIT_LIST_HEAD(&ctrl->list); spin_lock_init(&ctrl->lock); ctrl->dev = dev; ctrl->msm_id = *(int *)match->data; platform_set_drvdata(pdev, ctrl); switch (ctrl->msm_id) { case MSM8996_ID: ret = msm_apm_ctrl_devm_ioremap(pdev, ctrl); if (ret) { dev_err(dev, "Failed to add APM controller device\n"); return ret; } break; case MSMTITANIUM_ID: ret = msmtitanium_apm_ctrl_init(pdev, ctrl); if (ret) { dev_err(dev, "Failed to initialize APM controller device: ret=%d\n", ret); return ret; } break; default: dev_err(dev, "unable to add APM controller device for msm_id:%d\n", ctrl->msm_id); return -ENODEV; } apm_debugfs_init(ctrl); mutex_lock(&apm_ctrl_list_mutex); Loading @@ -678,11 +956,6 @@ static int msm_apm_remove(struct platform_device *pdev) return 0; } static struct of_device_id msm_apm_match_table[] = { { .compatible = MSM_APM_DRIVER_NAME, }, {} }; static struct platform_driver msm_apm_driver = { .driver = { .name = MSM_APM_DRIVER_NAME, Loading Loading
Documentation/devicetree/bindings/power/qcom/apm.txt +17 −1 Original line number Diff line number Diff line Loading @@ -7,7 +7,7 @@ SRAM minimum operating voltage, the APM controller can be used to request a switch to a power supply that will guarantee logic state retention. Required properties - compatible: "qcom,msm-apm" - compatible: "qcom,msm-apm", "qcom,msmtitanium-apm" - reg: Specifies physical base address and size of memory mapped regions containing the APM controller, APCS CSR, APC PLL controller, and SPM event registers. Loading @@ -21,6 +21,18 @@ Optional properties clock sources to GPLL0 before the APM switch begins and to switch back to the original clock source after the APM switch completes. - qcom,apm-post-halt-delay: The APM controller post halt delay counter value that SW needs to program one time before starting the APM HW controller for msmtitanium target. - qcom,apm-halt-clk-delay: The APM controller halt clock delay counter value that SW needs to program one time before starting the APM HW controller for msmtitanium target. - qcom,apm-resume-clk-delay: The APM controller resume clock delay counter value that SW needs to program one time before starting the APM HW controller for msmtitanium target. - qcom,apm-sel-switch-delay: The APM controller switch selection delay counter value that SW needs to program one time before starting the APM HW controller for msmtitanium target. MSM APM Users Loading Loading @@ -50,6 +62,10 @@ Example: "apc1-cpu1-spm", "apc0-l2-spm", "apc1-l2-spm"; qcom,apm-post-halt-delay = <0x2>; qcom,apm-halt-clk-delay = <0x11>; qcom,apm-resume-clk-delay = <0x10>; qcom,apm-sel-switch-delay = <0x01>; foo_user { ... Loading
drivers/power/qcom/apm.c +284 −11 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ #include <linux/debugfs.h> #include <linux/delay.h> #include <linux/of_device.h> #include <linux/init.h> #include <linux/io.h> #include <linux/kernel.h> Loading Loading @@ -86,6 +87,13 @@ enum { CLOCK_ASSERT_TOGGLE, }; enum { MSM8996_ID, MSMTITANIUM_ID, }; static int msm_id[] = {MSM8996_ID, MSMTITANIUM_ID}; struct msm_apm_ctrl_dev { struct list_head list; struct device *dev; Loading @@ -99,6 +107,7 @@ struct msm_apm_ctrl_dev { bool clk_src_override; u32 version; struct dentry *debugfs; u32 msm_id; }; #if defined(CONFIG_DEBUG_FS) Loading Loading @@ -231,6 +240,117 @@ free_events: return ret; } /* Titanium register offset definition */ #define MSMTITANIUM_APM_DLY_CNTR 0x2ac /* Register field shift definitions */ #define APM_CTL_SEL_SWITCH_DLY_SHIFT 0 #define APM_CTL_RESUME_CLK_DLY_SHIFT 8 #define APM_CTL_HALT_CLK_DLY_SHIFT 16 #define APM_CTL_POST_HALT_DLY_SHIFT 24 /* Register field mask definitions */ #define APM_CTL_SEL_SWITCH_DLY_MASK GENMASK(7, 0) #define APM_CTL_RESUME_CLK_DLY_MASK GENMASK(15, 8) #define APM_CTL_HALT_CLK_DLY_MASK GENMASK(23, 16) #define APM_CTL_POST_HALT_DLY_MASK GENMASK(31, 24) /* * Get the resources associated with the msmtitanium APM controller from * device tree, remap all I/O addresses, and program the initial * register configuration required for the titanium APM controller device. */ static int msmtitanium_apm_ctrl_init(struct platform_device *pdev, struct msm_apm_ctrl_dev *ctrl) { struct device *dev = &pdev->dev; struct resource *res; u32 delay_counter, val = 0, regval = 0; int rc = 0; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pm-apcc-glb"); if (!res) { dev_err(dev, "Missing PM APCC Global register physical address\n"); return -ENODEV; } ctrl->reg_base = devm_ioremap(dev, res->start, resource_size(res)); if (!ctrl->reg_base) { dev_err(dev, "Failed to map PM APCC Global registers\n"); return -ENOMEM; } /* * Initial APM register configuration required before starting * APM HW controller. */ regval = readl_relaxed(ctrl->reg_base + MSMTITANIUM_APM_DLY_CNTR); val = regval; if (of_find_property(dev->of_node, "qcom,apm-post-halt-delay", NULL)) { rc = of_property_read_u32(dev->of_node, "qcom,apm-post-halt-delay", &delay_counter); if (rc < 0) { dev_err(dev, "apm-post-halt-delay read failed, rc = %d", rc); return rc; } val &= ~APM_CTL_POST_HALT_DLY_MASK; val |= (delay_counter << APM_CTL_POST_HALT_DLY_SHIFT) & APM_CTL_POST_HALT_DLY_MASK; } if (of_find_property(dev->of_node, "qcom,apm-halt-clk-delay", NULL)) { rc = of_property_read_u32(dev->of_node, "qcom,apm-halt-clk-delay", &delay_counter); if (rc < 0) { dev_err(dev, "apm-halt-clk-delay read failed, rc = %d", rc); return rc; } val &= ~APM_CTL_HALT_CLK_DLY_MASK; val |= (delay_counter << APM_CTL_HALT_CLK_DLY_SHIFT) & APM_CTL_HALT_CLK_DLY_MASK; } if (of_find_property(dev->of_node, "qcom,apm-resume-clk-delay", NULL)) { rc = of_property_read_u32(dev->of_node, "qcom,apm-resume-clk-delay", &delay_counter); if (rc < 0) { dev_err(dev, "apm-resume-clk-delay read failed, rc = %d", rc); return rc; } val &= ~APM_CTL_RESUME_CLK_DLY_MASK; val |= (delay_counter << APM_CTL_RESUME_CLK_DLY_SHIFT) & APM_CTL_RESUME_CLK_DLY_MASK; } if (of_find_property(dev->of_node, "qcom,apm-sel-switch-delay", NULL)) { rc = of_property_read_u32(dev->of_node, "qcom,apm-sel-switch-delay", &delay_counter); if (rc < 0) { dev_err(dev, "apm-sel-switch-delay read failed, rc = %d", rc); return rc; } val &= ~APM_CTL_SEL_SWITCH_DLY_MASK; val |= (delay_counter << APM_CTL_SEL_SWITCH_DLY_SHIFT) & APM_CTL_SEL_SWITCH_DLY_MASK; } if (val != regval) { writel_relaxed(val, ctrl->reg_base + MSMTITANIUM_APM_DLY_CNTR); /* make sure write completes before return */ mb(); } return rc; } static int msm_apm_secure_clock_source_override( struct msm_apm_ctrl_dev *ctrl_dev, bool enable) { Loading @@ -248,7 +368,7 @@ static int msm_apm_secure_clock_source_override( return 0; } static int msm_apm_switch_to_mx(struct msm_apm_ctrl_dev *ctrl_dev) static int msm8996_apm_switch_to_mx(struct msm_apm_ctrl_dev *ctrl_dev) { int i, timeout = MSM_APM_SWITCH_TIMEOUT_US; u32 regval; Loading Loading @@ -344,7 +464,7 @@ static int msm_apm_switch_to_mx(struct msm_apm_ctrl_dev *ctrl_dev) return ret; } static int msm_apm_switch_to_apcc(struct msm_apm_ctrl_dev *ctrl_dev) static int msm8996_apm_switch_to_apcc(struct msm_apm_ctrl_dev *ctrl_dev) { int i, timeout = MSM_APM_SWITCH_TIMEOUT_US; u32 regval; Loading Loading @@ -440,6 +560,130 @@ static int msm_apm_switch_to_apcc(struct msm_apm_ctrl_dev *ctrl_dev) return ret; } /* Titanium register value definitions */ #define MSMTITANIUM_APM_MX_MODE_VAL 0x00 #define MSMTITANIUM_APM_APCC_MODE_VAL 0x02 #define MSMTITANIUM_APM_MX_DONE_VAL 0x00 #define MSMTITANIUM_APM_APCC_DONE_VAL 0x02 /* Titanium register offset definitions */ #define MSMTITANIUM_APCC_APM_MODE 0x000002a8 #define MSMTITANIUM_APCC_APM_CTL_STS 0x000002b0 static int msmtitanium_apm_switch_to_mx(struct msm_apm_ctrl_dev *ctrl_dev) { int timeout = MSM_APM_SWITCH_TIMEOUT_US; u32 regval; int ret = 0; unsigned long flags; spin_lock_irqsave(&ctrl_dev->lock, flags); /* Switch arrays to MX supply and wait for its completion */ writel_relaxed(MSMTITANIUM_APM_MX_MODE_VAL, ctrl_dev->reg_base + MSMTITANIUM_APCC_APM_MODE); /* Ensure write above completes before delaying */ mb(); while (timeout > 0) { regval = readl_relaxed(ctrl_dev->reg_base + MSMTITANIUM_APCC_APM_CTL_STS); if ((regval & MSM_APM_CTL_STS_MASK) == MSMTITANIUM_APM_MX_DONE_VAL) break; udelay(1); timeout--; } if (timeout == 0) { ret = -ETIMEDOUT; dev_err(ctrl_dev->dev, "APCC to MX APM switch timed out. APCC_APM_CTL_STS=0x%x\n", regval); } else { ctrl_dev->supply = MSM_APM_SUPPLY_MX; dev_dbg(ctrl_dev->dev, "APM supply switched to MX\n"); } spin_unlock_irqrestore(&ctrl_dev->lock, flags); return ret; } static int msmtitanium_apm_switch_to_apcc(struct msm_apm_ctrl_dev *ctrl_dev) { int timeout = MSM_APM_SWITCH_TIMEOUT_US; u32 regval; int ret = 0; unsigned long flags; spin_lock_irqsave(&ctrl_dev->lock, flags); /* Switch arrays to APCC supply and wait for its completion */ writel_relaxed(MSMTITANIUM_APM_APCC_MODE_VAL, ctrl_dev->reg_base + MSMTITANIUM_APCC_APM_MODE); /* Ensure write above completes before delaying */ mb(); while (timeout > 0) { regval = readl_relaxed(ctrl_dev->reg_base + MSMTITANIUM_APCC_APM_CTL_STS); if ((regval & MSM_APM_CTL_STS_MASK) == MSMTITANIUM_APM_APCC_DONE_VAL) break; udelay(1); timeout--; } if (timeout == 0) { ret = -ETIMEDOUT; dev_err(ctrl_dev->dev, "MX to APCC APM switch timed out. APCC_APM_CTL_STS=0x%x\n", regval); } else { ctrl_dev->supply = MSM_APM_SUPPLY_APCC; dev_dbg(ctrl_dev->dev, "APM supply switched to APCC\n"); } spin_unlock_irqrestore(&ctrl_dev->lock, flags); return ret; } static int msm_apm_switch_to_mx(struct msm_apm_ctrl_dev *ctrl_dev) { int ret = 0; switch (ctrl_dev->msm_id) { case MSM8996_ID: ret = msm8996_apm_switch_to_mx(ctrl_dev); break; case MSMTITANIUM_ID: ret = msmtitanium_apm_switch_to_mx(ctrl_dev); break; } return ret; } static int msm_apm_switch_to_apcc(struct msm_apm_ctrl_dev *ctrl_dev) { int ret = 0; switch (ctrl_dev->msm_id) { case MSM8996_ID: ret = msm8996_apm_switch_to_apcc(ctrl_dev); break; case MSMTITANIUM_ID: ret = msmtitanium_apm_switch_to_apcc(ctrl_dev); break; } return ret; } /** * msm_apm_get_supply() - Returns the supply that is currently * powering the memory arrays Loading Loading @@ -623,10 +867,23 @@ static void apm_debugfs_base_remove(void) #endif static struct of_device_id msm_apm_match_table[] = { { .compatible = "qcom,msm-apm", .data = &msm_id[MSM8996_ID] }, { .compatible = "qcom,msmtitanium-apm", .data = &msm_id[MSMTITANIUM_ID] }, {} }; static int msm_apm_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct msm_apm_ctrl_dev *ctrl; const struct of_device_id *match; int ret = 0; dev_dbg(dev, "probing MSM Array Power Mux driver\n"); Loading @@ -636,6 +893,10 @@ static int msm_apm_probe(struct platform_device *pdev) return -ENODEV; } match = of_match_device(msm_apm_match_table, dev); if (!match) return -ENODEV; ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL); if (!ctrl) { dev_err(dev, "MSM APM controller memory allocation failed\n"); Loading @@ -645,13 +906,30 @@ static int msm_apm_probe(struct platform_device *pdev) INIT_LIST_HEAD(&ctrl->list); spin_lock_init(&ctrl->lock); ctrl->dev = dev; ctrl->msm_id = *(int *)match->data; platform_set_drvdata(pdev, ctrl); switch (ctrl->msm_id) { case MSM8996_ID: ret = msm_apm_ctrl_devm_ioremap(pdev, ctrl); if (ret) { dev_err(dev, "Failed to add APM controller device\n"); return ret; } break; case MSMTITANIUM_ID: ret = msmtitanium_apm_ctrl_init(pdev, ctrl); if (ret) { dev_err(dev, "Failed to initialize APM controller device: ret=%d\n", ret); return ret; } break; default: dev_err(dev, "unable to add APM controller device for msm_id:%d\n", ctrl->msm_id); return -ENODEV; } apm_debugfs_init(ctrl); mutex_lock(&apm_ctrl_list_mutex); Loading @@ -678,11 +956,6 @@ static int msm_apm_remove(struct platform_device *pdev) return 0; } static struct of_device_id msm_apm_match_table[] = { { .compatible = MSM_APM_DRIVER_NAME, }, {} }; static struct platform_driver msm_apm_driver = { .driver = { .name = MSM_APM_DRIVER_NAME, Loading