Merge "msm: kgsl: Add support for voting vdd parent supply voltage"

This commit is contained in:
qctecmdr 2020-11-09 09:59:52 -08:00 • committed by Gerrit - the friendly Code Review server
commit a3b4c5531f
5 changed files with 66 additions and 3 deletions

View file

@ -3572,9 +3572,16 @@ static void adreno_regulator_disable_poll(struct kgsl_device *device)
{
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
/* Set the parent in retention voltage to disable CPR interrupts */
kgsl_regulator_set_voltage(device->dev, pwr->gx_gdsc_parent,
pwr->gx_gdsc_parent_min_corner);
if (!kgsl_regulator_disable_wait(pwr->gx_gdsc, 200))
dev_err(device->dev, "Regulator vdd is stuck on\n");
/* Remove the vote for the vdd parent supply */
kgsl_regulator_set_voltage(device->dev, pwr->gx_gdsc_parent, 0);
if (!kgsl_regulator_disable_wait(pwr->cx_gdsc, 200))
dev_err(device->dev, "Regulator vddcx is stuck on\n");
}

View file

@ -14,6 +14,7 @@
#include "kgsl_pwrscale.h"
#include "kgsl_sysfs.h"
#include "kgsl_trace.h"
#include "kgsl_util.h"
#define UPDATE_BUSY_VAL 1000000
@ -1328,8 +1329,15 @@ static int enable_regulators(struct kgsl_device *device)
return 0;
ret = enable_regulator(&device->pdev->dev, pwr->cx_gdsc, "vddcx");
if (!ret)
ret = enable_regulator(&device->pdev->dev, pwr->gx_gdsc, "vdd");
if (!ret) {
/* Set parent in retention voltage to power up vdd supply */
ret = kgsl_regulator_set_voltage(device->dev,
pwr->gx_gdsc_parent,
pwr->gx_gdsc_parent_min_corner);
if (!ret)
ret = enable_regulator(&device->pdev->dev,
pwr->gx_gdsc, "vdd");
}
if (ret) {
clear_bit(KGSL_PWRFLAGS_POWER_ON, &pwr->power_flags);
@ -1572,6 +1580,24 @@ int kgsl_pwrctrl_init(struct kgsl_device *device)
if (of_property_read_bool(pdev->dev.of_node, "vdd-supply"))
pwr->gx_gdsc = devm_regulator_get(&pdev->dev, "vdd");
if (of_property_read_bool(pdev->dev.of_node, "vdd-parent-supply")) {
pwr->gx_gdsc_parent = devm_regulator_get(&pdev->dev,
"vdd-parent");
if (IS_ERR(pwr->gx_gdsc_parent)) {
dev_err(device->dev,
"Failed to get vdd-parent regulator:%d\n",
PTR_ERR(pwr->gx_gdsc_parent));
return -ENODEV;
}
if (of_property_read_u32(pdev->dev.of_node,
"vdd-parent-min-corner",
&pwr->gx_gdsc_parent_min_corner)) {
dev_err(device->dev,
"vdd-parent-min-corner not found\n");
return -ENODEV;
}
}
pwr->power_flags = 0;
pm_runtime_enable(&pdev->dev);

View file

@ -120,6 +120,10 @@ struct kgsl_pwrctrl {
struct regulator *cx_gdsc;
/** @gx_gdsc: Pointer to the GX domain regulator if applicable */
struct regulator *gx_gdsc;
/** @gx_gdsc: Pointer to the GX domain parent supply */
struct regulator *gx_gdsc_parent;
/** @gx_gdsc_parent_min_corner: Minimum supply voltage for GX parent */
u32 gx_gdsc_parent_min_corner;
int isense_clk_indx;
int isense_clk_on_level;
unsigned long power_flags;

View file

@ -7,6 +7,7 @@
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/ktime.h>
#include <linux/regulator/consumer.h>
#include <linux/string.h>
@ -44,3 +45,18 @@ struct clk *kgsl_of_clk_by_name(struct clk_bulk_data *clks, int count,
return NULL;
}
int kgsl_regulator_set_voltage(struct device *dev,
struct regulator *reg, u32 voltage)
{
int ret;
if (IS_ERR_OR_NULL(reg))
return 0;
ret = regulator_set_voltage(reg, voltage, INT_MAX);
if (ret)
dev_err(dev, "Regulator set voltage:%d failed:%d\n", voltage, ret);
return ret;
}

View file

@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*/
#ifndef _KGSL_UTIL_H_
@ -32,4 +32,14 @@ bool kgsl_regulator_disable_wait(struct regulator *reg, u32 timeout);
*/
struct clk *kgsl_of_clk_by_name(struct clk_bulk_data *clks, int count,
const char *id);
/**
* kgsl_regulator_set_voltage - Set voltage level for regulator
* @dev: A &struct device pointer
* @reg: A &struct regulator handle
* @voltage: Voltage value to set regulator
*
* Return: 0 on success and negative error on failure.
*/
int kgsl_regulator_set_voltage(struct device *dev,
struct regulator *reg, u32 voltage);
#endif