regulator: gfx-ldo: support voltage based regulator operations

The current gfx ldo driver supports only corner based regulator
operations. The gfx ldo(LDO300) regulator in msmfalcon is CPR
managed and requires support for voltage based regulator operations.
Add voltage based regulator operations for msmfalcon.

CRs-Fixed: 1068294
Change-Id: I510c2fe7f763c8d44c67794c889c687df60398d7
Signed-off-by: Tirupathi Reddy <tirupath@codeaurora.org>
This commit is contained in:
Tirupathi Reddy 2016-09-06 09:11:47 +05:30
parent 23603a7dc4
commit cd881ce2aa
2 changed files with 317 additions and 103 deletions

View file

@ -8,7 +8,8 @@ This document describes the bindings that apply for the GFX LDO regulator.
- compatible
Usage: required
Value type: <string>
Definition: should be "qcom,msm8953-gfx-ldo" for MSM8953.
Definition: should be "qcom,msm8953-gfx-ldo" for MSM8953 and
"qcom,msmfalcon-gfx-ldo" for MSMFALCON
- reg
Usage: required

View file

@ -27,11 +27,13 @@
#include <linux/regulator/of_regulator.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/regulator/msm-ldo-regulator.h>
#define LDO_ATEST_REG 0x0
#define LDO_CFG0_REG 0x4
#define LDO_CFG1_REG 0x8
#define LDO_CFG2_REG 0xC
#define LDO_LD_DATA_REG 0x10
#define LDO_VREF_TEST_CFG 0x14
#define ENABLE_LDO_STATUS_BIT (BIT(8) | BIT(12))
@ -46,6 +48,7 @@
#define LDO_CLAMP_IO_BIT BIT(31)
#define CPR_BYPASS_IN_LDO_MODE_BIT BIT(30)
#define EN_LDOAP_CTRL_CPR_BIT BIT(29)
#define CX_CPR_BYPASS_IN_LDO_MODE_BIT BIT(10)
#define PWR_SRC_SEL_BIT BIT(9)
#define ACK_SW_OVR_BIT BIT(8)
#define LDO_PREON_SW_OVR_BIT BIT(7)
@ -63,6 +66,10 @@
#define LDO_READY_BIT BIT(2)
#define BHS_EN_REST_ACK_BIT BIT(1)
#define REF_CURRENT_X1_REG 0x2C
#define REF_CURRENT_X2_REG 0x30
#define ADC_CTL_REG 0x34
#define MIN_LDO_VOLTAGE 375000
#define MAX_LDO_VOLTAGE 980000
#define LDO_STEP_VOLATGE 5000
@ -76,17 +83,17 @@
#define GFX_LDO_FUSE_STEP_VOLT 10000
#define GFX_LDO_FUSE_SIZE 5
enum regulator_mode {
LDO,
BHS,
};
enum direction {
NO_CHANGE,
UP,
DOWN,
};
enum voltage_handling {
VOLTAGE,
CORNER,
};
struct fuse_param {
unsigned row;
unsigned bit_start;
@ -127,10 +134,11 @@ struct msm_gfx_ldo {
phys_addr_t ldo_addr;
bool vreg_enabled;
enum regulator_mode mode;
enum msm_ldo_supply_mode mode;
u32 corner;
int ldo_voltage_uv;
struct mutex ldo_mutex;
enum voltage_handling ops_type;
};
#define MSM8953_LDO_FUSE_CORNERS 3
@ -144,6 +152,19 @@ static struct ldo_config msm8953_ldo_config[] = {
{LDO_MAX_OFFSET, LDO_MAX_OFFSET},
};
static struct ldo_config msmfalcon_ldo_config[] = {
{LDO_ATEST_REG, 0x00000080},
{LDO_CFG0_REG, 0x0100A600},
{LDO_CFG1_REG, 0x000000A0},
{LDO_CFG2_REG, 0x0000C3FE},
{LDO_LD_DATA_REG, 0x00000000},
{LDO_VREF_TEST_CFG, 0x00401100},
{REF_CURRENT_X1_REG, 0x00000230},
{REF_CURRENT_X2_REG, 0x00000048},
{ADC_CTL_REG, 0x00000000},
{LDO_MAX_OFFSET, LDO_MAX_OFFSET},
};
static struct fuse_param msm8953_ldo_enable_param[] = {
{65, 11, 11},
{},
@ -162,6 +183,11 @@ static const int msm8953_fuse_ref_volt[MSM8953_LDO_FUSE_CORNERS] = {
720000,
};
enum {
MSM8953_SOC_ID,
MSMFALCON_SOC_ID,
};
static int convert_open_loop_voltage_fuse(int ref_volt, int step_volt,
u32 fuse, int fuse_len)
{
@ -209,14 +235,14 @@ static int read_fuse_param(void __iomem *fuse_base_addr,
return 0;
}
static enum regulator_mode get_operating_mode(struct msm_gfx_ldo *ldo_vreg,
static enum msm_ldo_supply_mode get_operating_mode(struct msm_gfx_ldo *ldo_vreg,
int corner)
{
if (!ldo_vreg->ldo_mode_disable && ldo_vreg->ldo_fuse_enable
&& ldo_vreg->ldo_corner_en_map[corner])
return LDO;
return LDO_MODE;
return BHS;
return BHS_MODE;
}
static char *register_str[] = {
@ -247,14 +273,12 @@ static void dump_registers(struct msm_gfx_ldo *ldo_vreg, char *func)
#define GET_VREF(a) DIV_ROUND_UP(a - MIN_LDO_VOLTAGE, LDO_STEP_VOLATGE)
static void configure_ldo_voltage(struct msm_gfx_ldo *ldo_vreg, int new_corner)
static void configure_ldo_voltage(struct msm_gfx_ldo *ldo_vreg, int new_uv)
{
int new_uv = 0, val = 0;
int val = 0;
u32 reg = 0;
new_uv = ldo_vreg->open_loop_volt[new_corner];
val = GET_VREF(new_uv);
reg = readl_relaxed(ldo_vreg->ldo_base + LDO_VREF_SET_REG);
/* set the new voltage */
@ -266,6 +290,9 @@ static void configure_ldo_voltage(struct msm_gfx_ldo *ldo_vreg, int new_corner)
reg |= UPDATE_VREF_BIT;
writel_relaxed(reg, ldo_vreg->ldo_base + LDO_VREF_SET_REG);
/* complete the writes */
mb();
reg &= ~UPDATE_VREF_BIT;
writel_relaxed(reg, ldo_vreg->ldo_base + LDO_VREF_SET_REG);
@ -275,12 +302,12 @@ static void configure_ldo_voltage(struct msm_gfx_ldo *ldo_vreg, int new_corner)
mb();
}
static int ldo_update_voltage(struct msm_gfx_ldo *ldo_vreg, int new_corner)
static int ldo_update_voltage(struct msm_gfx_ldo *ldo_vreg, int new_uv)
{
int timeout = 50;
u32 reg = 0;
configure_ldo_voltage(ldo_vreg, new_corner);
configure_ldo_voltage(ldo_vreg, new_uv);
while (--timeout) {
reg = readl_relaxed(ldo_vreg->ldo_base +
@ -303,16 +330,12 @@ static int ldo_update_voltage(struct msm_gfx_ldo *ldo_vreg, int new_corner)
return 0;
}
static int enable_ldo_mode(struct msm_gfx_ldo *ldo_vreg)
static int enable_ldo_mode(struct msm_gfx_ldo *ldo_vreg, int new_uv)
{
u32 ctl = 0;
/* set the ldo-vref */
configure_ldo_voltage(ldo_vreg, ldo_vreg->corner);
pr_debug("LDO voltage configured =%d uV corner=%d\n",
ldo_vreg->ldo_voltage_uv,
ldo_vreg->corner + MIN_CORNER_OFFSET);
configure_ldo_voltage(ldo_vreg, new_uv);
/* configure the LDO for power-up */
ctl = readl_relaxed(ldo_vreg->ldo_base + PWRSWITCH_CTRL_REG);
@ -342,8 +365,10 @@ static int enable_ldo_mode(struct msm_gfx_ldo *ldo_vreg)
writel_relaxed(ctl, ldo_vreg->ldo_base + PWRSWITCH_CTRL_REG);
/* put CPR in bypass mode */
ctl |= CPR_BYPASS_IN_LDO_MODE_BIT;
writel_relaxed(ctl, ldo_vreg->ldo_base + PWRSWITCH_CTRL_REG);
if (ldo_vreg->ops_type == CORNER) {
ctl |= CPR_BYPASS_IN_LDO_MODE_BIT;
writel_relaxed(ctl, ldo_vreg->ldo_base + PWRSWITCH_CTRL_REG);
}
/* complete all writes */
mb();
@ -367,9 +392,11 @@ static int enable_bhs_mode(struct msm_gfx_ldo *ldo_vreg)
ctl &= ~PWR_SRC_SEL_BIT;
writel_relaxed(ctl, ldo_vreg->ldo_base + PWRSWITCH_CTRL_REG);
/* clear CPR in by-pass mode */
ctl &= ~CPR_BYPASS_IN_LDO_MODE_BIT;
writel_relaxed(ctl, ldo_vreg->ldo_base + PWRSWITCH_CTRL_REG);
if (ldo_vreg->ops_type == CORNER) {
/* clear GFX CPR in by-pass mode */
ctl &= ~CPR_BYPASS_IN_LDO_MODE_BIT;
writel_relaxed(ctl, ldo_vreg->ldo_base + PWRSWITCH_CTRL_REG);
}
/* Enable the BHS control signals to gdsc */
ctl &= ~BHS_EN_FEW_BIT;
@ -386,11 +413,11 @@ static int enable_bhs_mode(struct msm_gfx_ldo *ldo_vreg)
return 0;
}
static int msm_gfx_ldo_enable(struct regulator_dev *rdev)
static int msm_gfx_ldo_corner_enable(struct regulator_dev *rdev)
{
struct msm_gfx_ldo *ldo_vreg = rdev_get_drvdata(rdev);
int rc = 0;
enum regulator_mode enable_mode;
int rc = 0, new_uv;
enum msm_ldo_supply_mode enable_mode;
mutex_lock(&ldo_vreg->ldo_mutex);
@ -415,19 +442,24 @@ static int msm_gfx_ldo_enable(struct regulator_dev *rdev)
}
enable_mode = get_operating_mode(ldo_vreg, ldo_vreg->corner);
if (enable_mode == LDO)
rc = enable_ldo_mode(ldo_vreg);
else
if (enable_mode == LDO_MODE) {
new_uv = ldo_vreg->open_loop_volt[ldo_vreg->corner];
rc = enable_ldo_mode(ldo_vreg, new_uv);
pr_debug("LDO voltage configured =%d uV corner=%d\n",
ldo_vreg->ldo_voltage_uv,
ldo_vreg->corner + MIN_CORNER_OFFSET);
} else {
rc = enable_bhs_mode(ldo_vreg);
}
if (rc) {
pr_err("Failed to enable regulator in %s mode rc=%d\n",
(enable_mode == LDO) ? "LDO" : "BHS", rc);
(enable_mode == LDO_MODE) ? "LDO" : "BHS", rc);
goto disable_cx;
}
pr_debug("regulator_enable complete. mode=%s, corner=%d\n",
(enable_mode == LDO) ? "LDO" : "BHS",
(enable_mode == LDO_MODE) ? "LDO" : "BHS",
ldo_vreg->corner + MIN_CORNER_OFFSET);
ldo_vreg->mode = enable_mode;
@ -471,15 +503,17 @@ done:
return rc;
}
static int switch_mode_to_ldo(struct msm_gfx_ldo *ldo_vreg, int new_corner)
static int switch_mode_to_ldo(struct msm_gfx_ldo *ldo_vreg, int new_uv)
{
u32 ctl = 0, status = 0, timeout = 50;
ctl = readl_relaxed(ldo_vreg->ldo_base + PWRSWITCH_CTRL_REG);
/* enable CPR bypass mode for LDO */
ctl |= CPR_BYPASS_IN_LDO_MODE_BIT;
writel_relaxed(ctl, ldo_vreg->ldo_base + PWRSWITCH_CTRL_REG);
if (ldo_vreg->ops_type == CORNER) {
/* enable CPR bypass mode for LDO */
ctl |= CPR_BYPASS_IN_LDO_MODE_BIT;
writel_relaxed(ctl, ldo_vreg->ldo_base + PWRSWITCH_CTRL_REG);
}
/* fake ack to GDSC */
ctl |= ACK_SW_OVR_BIT;
@ -512,7 +546,7 @@ static int switch_mode_to_ldo(struct msm_gfx_ldo *ldo_vreg, int new_corner)
writel_relaxed(ctl, ldo_vreg->ldo_base + PWRSWITCH_CTRL_REG);
/* set the new LDO voltage */
ldo_update_voltage(ldo_vreg, new_corner);
ldo_update_voltage(ldo_vreg, new_uv);
pr_debug("LDO voltage =%d uV\n", ldo_vreg->ldo_voltage_uv);
@ -616,9 +650,11 @@ static int switch_mode_to_bhs(struct msm_gfx_ldo *ldo_vreg)
ctl &= ~BHS_UNDER_SW_CTL;
writel_relaxed(ctl, ldo_vreg->ldo_base + PWRSWITCH_CTRL_REG);
/* Enable CPR in BHS mode */
ctl &= ~CPR_BYPASS_IN_LDO_MODE_BIT;
writel_relaxed(ctl, ldo_vreg->ldo_base + PWRSWITCH_CTRL_REG);
if (ldo_vreg->ops_type == CORNER) {
/* Enable CPR in BHS mode */
ctl &= ~CPR_BYPASS_IN_LDO_MODE_BIT;
writel_relaxed(ctl, ldo_vreg->ldo_base + PWRSWITCH_CTRL_REG);
}
/* make sure that all configuration is complete */
mb();
@ -628,12 +664,12 @@ static int switch_mode_to_bhs(struct msm_gfx_ldo *ldo_vreg)
return 0;
}
static int msm_gfx_ldo_set_voltage(struct regulator_dev *rdev,
static int msm_gfx_ldo_set_corner(struct regulator_dev *rdev,
int corner, int corner_max, unsigned *selector)
{
struct msm_gfx_ldo *ldo_vreg = rdev_get_drvdata(rdev);
int rc = 0, mem_acc_corner;
enum regulator_mode new_mode;
int rc = 0, mem_acc_corner, new_uv;
enum msm_ldo_supply_mode new_mode;
enum direction dir = NO_CHANGE;
corner -= MIN_CORNER_OFFSET;
@ -645,7 +681,7 @@ static int msm_gfx_ldo_set_voltage(struct regulator_dev *rdev,
goto done;
pr_debug("set-voltage requested: old_mode=%s old_corner=%d new_corner=%d vreg_enabled=%d\n",
ldo_vreg->mode == BHS ? "BHS" : "LDO",
ldo_vreg->mode == BHS_MODE ? "BHS" : "LDO",
ldo_vreg->corner + MIN_CORNER_OFFSET,
corner + MIN_CORNER_OFFSET,
ldo_vreg->vreg_enabled);
@ -679,21 +715,23 @@ static int msm_gfx_ldo_set_voltage(struct regulator_dev *rdev,
new_mode = get_operating_mode(ldo_vreg, corner);
if (new_mode == BHS) {
if (ldo_vreg->mode == LDO) {
if (new_mode == BHS_MODE) {
if (ldo_vreg->mode == LDO_MODE) {
rc = switch_mode_to_bhs(ldo_vreg);
if (rc)
pr_err("Switch to BHS corner=%d failed rc=%d\n",
corner + MIN_CORNER_OFFSET, rc);
}
} else { /* new mode - LDO */
if (ldo_vreg->mode == BHS) {
rc = switch_mode_to_ldo(ldo_vreg, corner);
new_uv = ldo_vreg->open_loop_volt[ldo_vreg->corner];
if (ldo_vreg->mode == BHS_MODE) {
rc = switch_mode_to_ldo(ldo_vreg, new_uv);
if (rc)
pr_err("Switch to LDO failed corner=%d rc=%d\n",
corner + MIN_CORNER_OFFSET, rc);
} else {
rc = ldo_update_voltage(ldo_vreg, corner);
rc = ldo_update_voltage(ldo_vreg, new_uv);
if (rc)
pr_err("Update voltage failed corner=%d rc=%d\n",
corner + MIN_CORNER_OFFSET, rc);
@ -702,8 +740,8 @@ static int msm_gfx_ldo_set_voltage(struct regulator_dev *rdev,
if (!rc) {
pr_debug("set-voltage complete. old_mode=%s new_mode=%s old_corner=%d new_corner=%d\n",
ldo_vreg->mode == BHS ? "BHS" : "LDO",
new_mode == BHS ? "BHS" : "LDO",
ldo_vreg->mode == BHS_MODE ? "BHS" : "LDO",
new_mode == BHS_MODE ? "BHS" : "LDO",
ldo_vreg->corner + MIN_CORNER_OFFSET,
corner + MIN_CORNER_OFFSET);
@ -721,7 +759,7 @@ done:
return rc;
}
static int msm_gfx_ldo_get_voltage(struct regulator_dev *rdev)
static int msm_gfx_ldo_get_corner(struct regulator_dev *rdev)
{
struct msm_gfx_ldo *ldo_vreg = rdev_get_drvdata(rdev);
@ -736,11 +774,132 @@ static int msm_gfx_ldo_is_enabled(struct regulator_dev *rdev)
}
static struct regulator_ops msm_gfx_ldo_corner_ops = {
.enable = msm_gfx_ldo_enable,
.enable = msm_gfx_ldo_corner_enable,
.disable = msm_gfx_ldo_disable,
.is_enabled = msm_gfx_ldo_is_enabled,
.set_voltage = msm_gfx_ldo_set_corner,
.get_voltage = msm_gfx_ldo_get_corner,
};
static int msm_gfx_ldo_get_bypass(struct regulator_dev *rdev,
bool *enable)
{
struct msm_gfx_ldo *ldo_vreg = rdev_get_drvdata(rdev);
*enable = ldo_vreg->mode;
return 0;
}
static int msm_gfx_ldo_set_bypass(struct regulator_dev *rdev,
bool mode)
{
struct msm_gfx_ldo *ldo_vreg = rdev_get_drvdata(rdev);
int rc = 0;
mutex_lock(&ldo_vreg->ldo_mutex);
if (ldo_vreg->mode == mode || !ldo_vreg->vreg_enabled)
goto done;
if (mode == LDO_MODE)
rc = switch_mode_to_ldo(ldo_vreg, ldo_vreg->ldo_voltage_uv);
else
rc = switch_mode_to_bhs(ldo_vreg);
if (rc) {
pr_err("Failed to configure regulator in %s mode rc=%d\n",
(mode == LDO_MODE) ? "LDO" : "BHS", rc);
goto done;
}
pr_debug("regulator_set_bypass complete. mode=%s, voltage = %d uV\n",
(mode == LDO_MODE) ? "LDO" : "BHS",
(mode == LDO_MODE) ? ldo_vreg->ldo_voltage_uv : 0);
ldo_vreg->mode = mode;
done:
mutex_unlock(&ldo_vreg->ldo_mutex);
return rc;
}
static int msm_gfx_ldo_voltage_enable(struct regulator_dev *rdev)
{
struct msm_gfx_ldo *ldo_vreg = rdev_get_drvdata(rdev);
int rc = 0;
enum msm_ldo_supply_mode enable_mode;
mutex_lock(&ldo_vreg->ldo_mutex);
pr_debug("regulator_enable requested. voltage=%d\n",
ldo_vreg->ldo_voltage_uv);
enable_mode = ldo_vreg->mode;
if (enable_mode == LDO_MODE)
rc = enable_ldo_mode(ldo_vreg, ldo_vreg->ldo_voltage_uv);
else
rc = enable_bhs_mode(ldo_vreg);
if (rc) {
pr_err("Failed to enable regulator in %s mode rc=%d\n",
(enable_mode == LDO_MODE) ? "LDO" : "BHS", rc);
goto fail;
}
pr_debug("regulator_enable complete. mode=%s, voltage = %d uV\n",
(enable_mode == LDO_MODE) ? "LDO" : "BHS",
(enable_mode == LDO_MODE) ? ldo_vreg->ldo_voltage_uv : 0);
ldo_vreg->vreg_enabled = true;
fail:
mutex_unlock(&ldo_vreg->ldo_mutex);
return rc;
}
static int msm_gfx_ldo_set_voltage(struct regulator_dev *rdev,
int new_uv, int max_uv, unsigned *selector)
{
struct msm_gfx_ldo *ldo_vreg = rdev_get_drvdata(rdev);
int rc = 0;
mutex_lock(&ldo_vreg->ldo_mutex);
if (new_uv == ldo_vreg->ldo_voltage_uv)
goto done;
if (!ldo_vreg->vreg_enabled || ldo_vreg->mode != LDO_MODE) {
ldo_vreg->ldo_voltage_uv = new_uv;
goto done;
}
/* update LDO voltage */
rc = ldo_update_voltage(ldo_vreg, new_uv);
if (rc)
pr_err("Update voltage failed for [%d, %d], rc=%d\n",
new_uv, max_uv, rc);
done:
mutex_unlock(&ldo_vreg->ldo_mutex);
return rc;
}
static int msm_gfx_ldo_get_voltage(struct regulator_dev *rdev)
{
struct msm_gfx_ldo *ldo_vreg = rdev_get_drvdata(rdev);
return ldo_vreg->ldo_voltage_uv;
}
static struct regulator_ops msm_gfx_ldo_voltage_ops = {
.enable = msm_gfx_ldo_voltage_enable,
.disable = msm_gfx_ldo_disable,
.is_enabled = msm_gfx_ldo_is_enabled,
.set_voltage = msm_gfx_ldo_set_voltage,
.get_voltage = msm_gfx_ldo_get_voltage,
.set_bypass = msm_gfx_ldo_set_bypass,
.get_bypass = msm_gfx_ldo_get_bypass,
};
static int msm_gfx_ldo_adjust_init_voltage(struct msm_gfx_ldo *ldo_vreg)
@ -764,6 +923,9 @@ static int msm_gfx_ldo_adjust_init_voltage(struct msm_gfx_ldo *ldo_vreg)
volt_adjust = devm_kcalloc(ldo_vreg->dev, size, sizeof(*volt_adjust),
GFP_KERNEL);
if (!volt_adjust)
return -ENOMEM;
rc = of_property_read_u32_array(of_node, prop_name, volt_adjust, size);
if (rc) {
pr_err("failed to read %s property rc=%d\n", prop_name, rc);
@ -950,7 +1112,7 @@ static int msm_gfx_ldo_init(struct platform_device *pdev,
{
struct resource *res;
u32 len, ctl;
int rc, i = 0;
int i = 0;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ldo_addr");
if (!res || !res->start) {
@ -969,12 +1131,6 @@ static int msm_gfx_ldo_init(struct platform_device *pdev,
return -EINVAL;
}
rc = msm_gfx_ldo_mem_acc_init(ldo_vreg);
if (rc) {
pr_err("Unable to initialize mem_acc rc=%d\n", rc);
return rc;
}
/* HW initialization */
/* clear clamp_io, enable CPR in auto-bypass*/
@ -1117,7 +1273,6 @@ static int msm_gfx_ldo_target_init(struct msm_gfx_ldo *ldo_vreg)
ldo_vreg->init_volt_param[i] =
msm8953_init_voltage_param[i];
ldo_vreg->ldo_init_config = msm8953_ldo_config;
ldo_vreg->ref_volt = msm8953_fuse_ref_volt;
ldo_vreg->ldo_enable_param = msm8953_ldo_enable_param;
@ -1156,7 +1311,7 @@ static int debugfs_ldo_set_voltage(void *data, u64 val)
mutex_lock(&ldo_vreg->ldo_mutex);
if (ldo_vreg->mode == BHS || !ldo_vreg->vreg_enabled ||
if (ldo_vreg->mode == BHS_MODE || !ldo_vreg->vreg_enabled ||
val > MAX_LDO_VOLTAGE || val < MIN_LDO_VOLTAGE) {
rc = -EINVAL;
goto done;
@ -1174,6 +1329,9 @@ static int debugfs_ldo_set_voltage(void *data, u64 val)
reg |= UPDATE_VREF_BIT;
writel_relaxed(reg, ldo_vreg->ldo_base + LDO_VREF_SET_REG);
/* complete the writes */
mb();
reg &= ~UPDATE_VREF_BIT;
writel_relaxed(reg, ldo_vreg->ldo_base + LDO_VREF_SET_REG);
@ -1210,7 +1368,7 @@ static int debugfs_ldo_get_voltage(void *data, u64 *val)
mutex_lock(&ldo_vreg->ldo_mutex);
if (ldo_vreg->mode == BHS || !ldo_vreg->vreg_enabled) {
if (ldo_vreg->mode == BHS_MODE || !ldo_vreg->vreg_enabled) {
rc = -EINVAL;
goto done;
}
@ -1250,7 +1408,7 @@ static ssize_t msm_gfx_ldo_debug_info_read(struct file *file, char __user *buff,
len = snprintf(debugfs_buf + ret, PAGE_SIZE - ret,
"Regulator_enable = %d Regulator mode = %s Corner = %d LDO-voltage = %d uV\n",
ldo_vreg->vreg_enabled,
ldo_vreg->mode == BHS ? "BHS" : "LDO",
ldo_vreg->mode == BHS_MODE ? "BHS" : "LDO",
ldo_vreg->corner + MIN_CORNER_OFFSET,
ldo_vreg->ldo_voltage_uv);
ret += len;
@ -1313,39 +1471,11 @@ static void msm_gfx_ldo_debugfs_remove(struct msm_gfx_ldo *ldo_vreg)
debugfs_remove_recursive(ldo_vreg->debugfs);
}
static int msm_gfx_ldo_probe(struct platform_device *pdev)
static int msm_gfx_ldo_corner_config_init(struct msm_gfx_ldo *ldo_vreg,
struct platform_device *pdev)
{
struct msm_gfx_ldo *ldo_vreg;
struct regulator_config reg_config = {};
struct regulator_desc *rdesc;
struct regulator_init_data *init_data = pdev->dev.platform_data;
struct device *dev = &pdev->dev;
int rc;
ldo_vreg = devm_kzalloc(dev, sizeof(*ldo_vreg), GFP_KERNEL);
if (!ldo_vreg)
return -ENOMEM;
init_data = of_get_regulator_init_data(dev, dev->of_node);
if (!init_data) {
pr_err("regulator init data is missing\n");
return -EINVAL;
}
init_data->constraints.input_uV = init_data->constraints.max_uV;
init_data->constraints.valid_ops_mask
|= REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS;
ldo_vreg->rdesc.name = init_data->constraints.name;
if (ldo_vreg->rdesc.name == NULL) {
dev_err(dev, "regulator-name missing\n");
return -EINVAL;
}
ldo_vreg->dev = &pdev->dev;
mutex_init(&ldo_vreg->ldo_mutex);
platform_set_drvdata(pdev, ldo_vreg);
rc = msm_gfx_ldo_target_init(ldo_vreg);
if (rc) {
pr_err("Unable to initialize target specific data rc=%d", rc);
@ -1370,6 +1500,90 @@ static int msm_gfx_ldo_probe(struct platform_device *pdev)
return rc;
}
rc = msm_gfx_ldo_mem_acc_init(ldo_vreg);
if (rc) {
pr_err("Unable to initialize mem_acc rc=%d\n", rc);
return rc;
}
return rc;
};
/* Data corresponds to the SoC revision */
static const struct of_device_id msm_gfx_ldo_match_table[] = {
{
.compatible = "qcom,msm8953-gfx-ldo",
.data = (void *)(uintptr_t)MSM8953_SOC_ID,
},
{
.compatible = "qcom,msmfalcon-gfx-ldo",
.data = (void *)(uintptr_t)MSMFALCON_SOC_ID,
},
{}
};
static int msm_gfx_ldo_probe(struct platform_device *pdev)
{
struct msm_gfx_ldo *ldo_vreg;
struct regulator_config reg_config = {};
struct regulator_desc *rdesc;
struct regulator_init_data *init_data = pdev->dev.platform_data;
struct device *dev = &pdev->dev;
const struct of_device_id *match;
int soc_id, rc;
match = of_match_device(msm_gfx_ldo_match_table, dev);
if (!match)
return -ENODEV;
ldo_vreg = devm_kzalloc(dev, sizeof(*ldo_vreg), GFP_KERNEL);
if (!ldo_vreg)
return -ENOMEM;
init_data = of_get_regulator_init_data(dev, dev->of_node, NULL);
if (!init_data) {
pr_err("regulator init data is missing\n");
return -EINVAL;
}
init_data->constraints.input_uV = init_data->constraints.max_uV;
init_data->constraints.valid_ops_mask
|= REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS;
ldo_vreg->rdesc.name = init_data->constraints.name;
if (ldo_vreg->rdesc.name == NULL) {
dev_err(dev, "regulator-name missing\n");
return -EINVAL;
}
soc_id = (uintptr_t)match->data;
ldo_vreg->dev = &pdev->dev;
mutex_init(&ldo_vreg->ldo_mutex);
platform_set_drvdata(pdev, ldo_vreg);
switch (soc_id) {
case MSM8953_SOC_ID:
ldo_vreg->ldo_init_config = msm8953_ldo_config;
ldo_vreg->ops_type = CORNER;
rc = msm_gfx_ldo_corner_config_init(ldo_vreg, pdev);
if (rc) {
pr_err("ldo corner handling initialization failed, rc=%d\n",
rc);
return rc;
}
break;
case MSMFALCON_SOC_ID:
ldo_vreg->ldo_init_config = msmfalcon_ldo_config;
ldo_vreg->ops_type = VOLTAGE;
init_data->constraints.valid_ops_mask
|= REGULATOR_CHANGE_BYPASS;
break;
default:
pr_err("invalid SOC ID = %d\n", soc_id);
return -EINVAL;
}
/* HW initialization */
rc = msm_gfx_ldo_init(pdev, ldo_vreg);
if (rc) {
pr_err("ldo_init failed rc=%d\n", rc);
@ -1379,7 +1593,11 @@ static int msm_gfx_ldo_probe(struct platform_device *pdev)
rdesc = &ldo_vreg->rdesc;
rdesc->owner = THIS_MODULE;
rdesc->type = REGULATOR_VOLTAGE;
rdesc->ops = &msm_gfx_ldo_corner_ops;
if (ldo_vreg->ops_type == CORNER)
rdesc->ops = &msm_gfx_ldo_corner_ops;
else
rdesc->ops = &msm_gfx_ldo_voltage_ops;
reg_config.dev = &pdev->dev;
reg_config.init_data = init_data;
@ -1408,11 +1626,6 @@ static int msm_gfx_ldo_remove(struct platform_device *pdev)
return 0;
}
static struct of_device_id msm_gfx_ldo_match_table[] = {
{ .compatible = "qcom,msm8953-gfx-ldo", },
{}
};
static struct platform_driver msm_gfx_ldo_driver = {
.driver = {
.name = "qcom,msm-gfx-ldo",