Loading drivers/thermal/qcom/sdpm_clk.c +66 −1 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ #include <linux/module.h> #include <linux/clk.h> #include <linux/regulator/consumer.h> #include <linux/platform_device.h> #include <linux/err.h> #include <linux/slab.h> Loading @@ -25,9 +26,13 @@ struct sdpm_clk_data { struct notifier_block clk_rate_nb; struct clk *clk; const char *clock_name; struct notifier_block reg_nb; struct regulator *reg; uint8_t reg_enable; uint32_t cpu_id; uint32_t csr_id; unsigned long last_freq; struct mutex sdpm_mutex; struct sdpm_clk_instance *sdpm_inst; }; struct sdpm_clk_instance { Loading @@ -41,7 +46,7 @@ static void sdpm_csr_write(struct sdpm_clk_data *sdpm_data, unsigned long clk_rate) { struct sdpm_clk_instance *sdpm_inst = sdpm_data->sdpm_inst; uint32_t val = clk_rate; uint32_t val = sdpm_data->reg_enable ? clk_rate : 0; sdpm_data->last_freq = clk_rate; Loading Loading @@ -81,6 +86,34 @@ static int sdpm_cpu_notifier(struct notifier_block *nb, return NOTIFY_DONE; } static int sdpm_reg_notifier(struct notifier_block *nb, unsigned long event, void *data) { struct sdpm_clk_data *sdpm_data = container_of(nb, struct sdpm_clk_data, reg_nb); dev_dbg(sdpm_data->sdpm_inst->dev, "reg:%s event:%lu\n", sdpm_data->clock_name, event); switch (event) { case REGULATOR_EVENT_ENABLE: mutex_lock(&sdpm_data->sdpm_mutex); sdpm_data->reg_enable = 1; sdpm_csr_write(sdpm_data, sdpm_data->last_freq); mutex_unlock(&sdpm_data->sdpm_mutex); return NOTIFY_OK; case REGULATOR_EVENT_DISABLE: mutex_lock(&sdpm_data->sdpm_mutex); sdpm_data->reg_enable = 0; sdpm_csr_write(sdpm_data, sdpm_data->last_freq); mutex_unlock(&sdpm_data->sdpm_mutex); return NOTIFY_OK; default: return NOTIFY_OK; } return NOTIFY_OK; } static int sdpm_clock_notifier(struct notifier_block *nb, unsigned long event, void *data) { Loading @@ -92,19 +125,25 @@ static int sdpm_clock_notifier(struct notifier_block *nb, sdpm_data->clock_name, event); switch (event) { case PRE_RATE_CHANGE: mutex_lock(&sdpm_data->sdpm_mutex); if (ndata->new_rate > ndata->old_rate) sdpm_csr_write(sdpm_data, FREQ_HZ_TO_MHZ(ndata->new_rate)); mutex_unlock(&sdpm_data->sdpm_mutex); return NOTIFY_DONE; case POST_RATE_CHANGE: mutex_lock(&sdpm_data->sdpm_mutex); if (ndata->new_rate < ndata->old_rate) sdpm_csr_write(sdpm_data, FREQ_HZ_TO_MHZ(ndata->new_rate)); mutex_unlock(&sdpm_data->sdpm_mutex); return NOTIFY_DONE; case ABORT_RATE_CHANGE: mutex_lock(&sdpm_data->sdpm_mutex); if (ndata->new_rate > ndata->old_rate) sdpm_csr_write(sdpm_data, FREQ_HZ_TO_MHZ(ndata->old_rate)); mutex_unlock(&sdpm_data->sdpm_mutex); return NOTIFY_DONE; default: return NOTIFY_DONE; Loading Loading @@ -198,10 +237,29 @@ static int sdpm_clk_device_probe(struct platform_device *pdev) sdpm_clock_notifier; sdpm_clk->clk_data[idx].last_freq = FREQ_HZ_TO_MHZ( clk_get_rate(sdpm_clk->clk_data[idx].clk)); sdpm_clk->clk_data[idx].reg_enable = 1; sdpm_clk->clk_data[idx].reg = NULL; sdpm_csr_write(&sdpm_clk->clk_data[idx], sdpm_clk->clk_data[idx].last_freq); mutex_init(&sdpm_clk->clk_data[idx].sdpm_mutex); clk_notifier_register(sdpm_clk->clk_data[idx].clk, &sdpm_clk->clk_data[idx].clk_rate_nb); sdpm_clk->clk_data[idx].reg = devm_regulator_get(dev, sdpm_clk->clk_data[idx].clock_name); if (IS_ERR(sdpm_clk->clk_data[idx].reg)) { dev_err(dev, "regulator:%s get err:%d\n", dev, sdpm_clk->clk_data[idx].clock_name, PTR_ERR(sdpm_clk->clk_data[idx].reg)); if (PTR_ERR(sdpm_clk->clk_data[idx].reg) == -EPROBE_DEFER) return PTR_ERR(sdpm_clk->clk_data[idx].reg); } else { sdpm_clk->clk_data[idx].reg_nb.notifier_call = sdpm_reg_notifier; regulator_register_notifier( sdpm_clk->clk_data[idx].reg, &sdpm_clk->clk_data[idx].reg_nb); } } cpu_phandle = of_parse_phandle(dev_node, "cpu", 0); if (!cpu_phandle) Loading @@ -213,6 +271,8 @@ static int sdpm_clk_device_probe(struct platform_device *pdev) continue; sdpm_clk->clk_data[idx].clk = NULL; sdpm_clk->clk_data[idx].clock_name = NULL; sdpm_clk->clk_data[idx].reg = NULL; sdpm_clk->clk_data[idx].reg_enable = 1; ret = of_property_read_u32_index(dev_node, "csr-id", idx, &csr); if (ret < 0) { Loading @@ -231,6 +291,7 @@ static int sdpm_clk_device_probe(struct platform_device *pdev) sdpm_clk->clk_data[idx].sdpm_inst = sdpm_clk; sdpm_clk->clk_data[idx].clk_rate_nb.notifier_call = sdpm_cpu_notifier; mutex_init(&sdpm_clk->clk_data[idx].sdpm_mutex); freq = UINT_MAX; opp = dev_pm_opp_find_freq_floor(cpu_dev, &freq); if (IS_ERR(opp)) { Loading Loading @@ -259,6 +320,10 @@ static int sdpm_clk_device_remove(struct platform_device *pdev) for (idx = 0; idx < sdpm_clk->clk_ct; idx++) { clk_notifier_unregister(sdpm_clk->clk_data[idx].clk, &sdpm_clk->clk_data[idx].clk_rate_nb); if (!sdpm_clk->clk_data[idx].reg) continue; regulator_unregister_notifier(sdpm_clk->clk_data[idx].reg, &sdpm_clk->clk_data[idx].reg_nb); } cpufreq_unregister_notifier(&sdpm_clk->clk_data[idx].clk_rate_nb, CPUFREQ_TRANSITION_NOTIFIER); Loading Loading
drivers/thermal/qcom/sdpm_clk.c +66 −1 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ #include <linux/module.h> #include <linux/clk.h> #include <linux/regulator/consumer.h> #include <linux/platform_device.h> #include <linux/err.h> #include <linux/slab.h> Loading @@ -25,9 +26,13 @@ struct sdpm_clk_data { struct notifier_block clk_rate_nb; struct clk *clk; const char *clock_name; struct notifier_block reg_nb; struct regulator *reg; uint8_t reg_enable; uint32_t cpu_id; uint32_t csr_id; unsigned long last_freq; struct mutex sdpm_mutex; struct sdpm_clk_instance *sdpm_inst; }; struct sdpm_clk_instance { Loading @@ -41,7 +46,7 @@ static void sdpm_csr_write(struct sdpm_clk_data *sdpm_data, unsigned long clk_rate) { struct sdpm_clk_instance *sdpm_inst = sdpm_data->sdpm_inst; uint32_t val = clk_rate; uint32_t val = sdpm_data->reg_enable ? clk_rate : 0; sdpm_data->last_freq = clk_rate; Loading Loading @@ -81,6 +86,34 @@ static int sdpm_cpu_notifier(struct notifier_block *nb, return NOTIFY_DONE; } static int sdpm_reg_notifier(struct notifier_block *nb, unsigned long event, void *data) { struct sdpm_clk_data *sdpm_data = container_of(nb, struct sdpm_clk_data, reg_nb); dev_dbg(sdpm_data->sdpm_inst->dev, "reg:%s event:%lu\n", sdpm_data->clock_name, event); switch (event) { case REGULATOR_EVENT_ENABLE: mutex_lock(&sdpm_data->sdpm_mutex); sdpm_data->reg_enable = 1; sdpm_csr_write(sdpm_data, sdpm_data->last_freq); mutex_unlock(&sdpm_data->sdpm_mutex); return NOTIFY_OK; case REGULATOR_EVENT_DISABLE: mutex_lock(&sdpm_data->sdpm_mutex); sdpm_data->reg_enable = 0; sdpm_csr_write(sdpm_data, sdpm_data->last_freq); mutex_unlock(&sdpm_data->sdpm_mutex); return NOTIFY_OK; default: return NOTIFY_OK; } return NOTIFY_OK; } static int sdpm_clock_notifier(struct notifier_block *nb, unsigned long event, void *data) { Loading @@ -92,19 +125,25 @@ static int sdpm_clock_notifier(struct notifier_block *nb, sdpm_data->clock_name, event); switch (event) { case PRE_RATE_CHANGE: mutex_lock(&sdpm_data->sdpm_mutex); if (ndata->new_rate > ndata->old_rate) sdpm_csr_write(sdpm_data, FREQ_HZ_TO_MHZ(ndata->new_rate)); mutex_unlock(&sdpm_data->sdpm_mutex); return NOTIFY_DONE; case POST_RATE_CHANGE: mutex_lock(&sdpm_data->sdpm_mutex); if (ndata->new_rate < ndata->old_rate) sdpm_csr_write(sdpm_data, FREQ_HZ_TO_MHZ(ndata->new_rate)); mutex_unlock(&sdpm_data->sdpm_mutex); return NOTIFY_DONE; case ABORT_RATE_CHANGE: mutex_lock(&sdpm_data->sdpm_mutex); if (ndata->new_rate > ndata->old_rate) sdpm_csr_write(sdpm_data, FREQ_HZ_TO_MHZ(ndata->old_rate)); mutex_unlock(&sdpm_data->sdpm_mutex); return NOTIFY_DONE; default: return NOTIFY_DONE; Loading Loading @@ -198,10 +237,29 @@ static int sdpm_clk_device_probe(struct platform_device *pdev) sdpm_clock_notifier; sdpm_clk->clk_data[idx].last_freq = FREQ_HZ_TO_MHZ( clk_get_rate(sdpm_clk->clk_data[idx].clk)); sdpm_clk->clk_data[idx].reg_enable = 1; sdpm_clk->clk_data[idx].reg = NULL; sdpm_csr_write(&sdpm_clk->clk_data[idx], sdpm_clk->clk_data[idx].last_freq); mutex_init(&sdpm_clk->clk_data[idx].sdpm_mutex); clk_notifier_register(sdpm_clk->clk_data[idx].clk, &sdpm_clk->clk_data[idx].clk_rate_nb); sdpm_clk->clk_data[idx].reg = devm_regulator_get(dev, sdpm_clk->clk_data[idx].clock_name); if (IS_ERR(sdpm_clk->clk_data[idx].reg)) { dev_err(dev, "regulator:%s get err:%d\n", dev, sdpm_clk->clk_data[idx].clock_name, PTR_ERR(sdpm_clk->clk_data[idx].reg)); if (PTR_ERR(sdpm_clk->clk_data[idx].reg) == -EPROBE_DEFER) return PTR_ERR(sdpm_clk->clk_data[idx].reg); } else { sdpm_clk->clk_data[idx].reg_nb.notifier_call = sdpm_reg_notifier; regulator_register_notifier( sdpm_clk->clk_data[idx].reg, &sdpm_clk->clk_data[idx].reg_nb); } } cpu_phandle = of_parse_phandle(dev_node, "cpu", 0); if (!cpu_phandle) Loading @@ -213,6 +271,8 @@ static int sdpm_clk_device_probe(struct platform_device *pdev) continue; sdpm_clk->clk_data[idx].clk = NULL; sdpm_clk->clk_data[idx].clock_name = NULL; sdpm_clk->clk_data[idx].reg = NULL; sdpm_clk->clk_data[idx].reg_enable = 1; ret = of_property_read_u32_index(dev_node, "csr-id", idx, &csr); if (ret < 0) { Loading @@ -231,6 +291,7 @@ static int sdpm_clk_device_probe(struct platform_device *pdev) sdpm_clk->clk_data[idx].sdpm_inst = sdpm_clk; sdpm_clk->clk_data[idx].clk_rate_nb.notifier_call = sdpm_cpu_notifier; mutex_init(&sdpm_clk->clk_data[idx].sdpm_mutex); freq = UINT_MAX; opp = dev_pm_opp_find_freq_floor(cpu_dev, &freq); if (IS_ERR(opp)) { Loading Loading @@ -259,6 +320,10 @@ static int sdpm_clk_device_remove(struct platform_device *pdev) for (idx = 0; idx < sdpm_clk->clk_ct; idx++) { clk_notifier_unregister(sdpm_clk->clk_data[idx].clk, &sdpm_clk->clk_data[idx].clk_rate_nb); if (!sdpm_clk->clk_data[idx].reg) continue; regulator_unregister_notifier(sdpm_clk->clk_data[idx].reg, &sdpm_clk->clk_data[idx].reg_nb); } cpufreq_unregister_notifier(&sdpm_clk->clk_data[idx].clk_rate_nb, CPUFREQ_TRANSITION_NOTIFIER); Loading