regulator: qpnp-oledb: Add lab_vreg_ok notifier callback

OLEDB driver needs the LAB_VREG_OK status to program the PD_CTL
register after the oledb module is enabled. As this status register
is not accessible from the OLEDB driver, register a notifier callback
with LABIBB driver to get LAB_VREG_OK status.

Change-Id: I85009688a2accb6246135d22e08ee21fb8296f62
Signed-off-by: Kiran Gunda <kgunda@codeaurora.org>
This commit is contained in:
Kiran Gunda 2017-02-13 19:55:40 +05:30
parent 9147c318e6
commit c3cd3d3174
2 changed files with 195 additions and 27 deletions

View file

@ -44,12 +44,12 @@ Required Node Structure
Value type: <bool> Value type: <bool>
Definition: Enables the voltage programming through SWIRE signal. Definition: Enables the voltage programming through SWIRE signal.
qcom,ext-pin-control - qcom,ext-pin-control
Usage: optional Usage: optional
Value type: <bool> Value type: <bool>
Definition: Configures the OLED module to be enabled by a external pin. Definition: Configures the OLED module to be enabled by a external pin.
qcom,dynamic-ext-pinctl-config - qcom,dynamic-ext-pinctl-config
Usage: optional Usage: optional
Value type: <bool> Value type: <bool>
Definition: Used to dynamically enable/disable the OLEDB module Definition: Used to dynamically enable/disable the OLEDB module
@ -57,13 +57,27 @@ Required Node Structure
rail. This property is applicable only if qcom,ext-pin-ctl rail. This property is applicable only if qcom,ext-pin-ctl
property is specified and it is specific to PM660A. property is specified and it is specific to PM660A.
qcom,pbs-control - qcom,force-pd-control
Usage: optional
Value type: <bool>
Definition: Used to enable the pull down control forcibly via SPMI by
disabling the pull down configuration done by hardware
automatically through SWIRE pulses.
- qcom,pbs-client
Usage: optional
Value type: <phandle>
Definition: Used to send the PBS trigger to the specified PBS client.
This property is applicable only if qcom,force-pd-control
property is specified.
- qcom,pbs-control
Usage: optional Usage: optional
Value type: <bool> Value type: <bool>
Definition: PMIC PBS logic directly configures the output voltage update Definition: PMIC PBS logic directly configures the output voltage update
and pull down control. and pull down control.
qcom,oledb-init-voltage-mv - qcom,oledb-init-voltage-mv
Usage: optional Usage: optional
Value type: <u32> Value type: <u32>
Definition: Sets the AVDD bias voltage (in mV) when the module is Definition: Sets the AVDD bias voltage (in mV) when the module is
@ -71,53 +85,53 @@ Required Node Structure
property is not specified. Supported values are from 5.0V property is not specified. Supported values are from 5.0V
to 8.1V with a step of 100mV. to 8.1V with a step of 100mV.
qcom,oledb-default-voltage-mv - qcom,oledb-default-voltage-mv
Usage: optional Usage: optional
Value type: <u32> Value type: <u32>
Definition: Sets the default AVDD bias voltage (in mV) before module Definition: Sets the default AVDD bias voltage (in mV) before module
enable. Supported values are from 5.0V to 8.1V with the enable. Supported values are from 5.0V to 8.1V with the
step of 100mV. step of 100mV.
qcom,bias-gen-warmup-delay-ns - qcom,bias-gen-warmup-delay-ns
Usage: optional Usage: optional
Value type: <u32> Value type: <u32>
Definition: Bias generator warm-up time (ns). Supported values are Definition: Bias generator warm-up time (ns). Supported values are
6700, 13300, 267000, 534000. 6700, 13300, 267000, 534000.
qcom,peak-curr-limit-ma - qcom,peak-curr-limit-ma
Usage: optional Usage: optional
Value type: <u32> Value type: <u32>
Definition: Peak current limit (in mA). Supported values are 115, 265, Definition: Peak current limit (in mA). Supported values are 115, 265,
415, 570, 720, 870, 1020, 1170. 415, 570, 720, 870, 1020, 1170.
qcom,pull-down-enable - qcom,pull-down-enable
Usage: optional Usage: optional
Value type: <u32> Value type: <u32>
Definition: Pull down configuration of OLEDB. Definition: Pull down configuration of OLEDB.
1 - Enable pull-down 1 - Enable pull-down
0 - Disable pull-down 0 - Disable pull-down
qcom,negative-curr-limit-enable - qcom,negative-curr-limit-enable
Usage: optional Usage: optional
Value type: <u32> Value type: <u32>
Definition: negative current limit enable/disable. Definition: negative current limit enable/disable.
1 = enable negative current limit 1 = enable negative current limit
0 = disable negative current limit 0 = disable negative current limit
qcom,negative-curr-limit-ma - qcom,negative-curr-limit-ma
Usage: optional Usage: optional
Value type: <u32> Value type: <u32>
Definition: Negative current limit (in mA). Supported values are Definition: Negative current limit (in mA). Supported values are
170, 300, 420, 550. 170, 300, 420, 550.
qcom,enable-short-circuit - qcom,enable-short-circuit
Usage: optional Usage: optional
Value type: <u32> Value type: <u32>
Definition: Short circuit protection enable/disable. Definition: Short circuit protection enable/disable.
1 = enable short circuit protection 1 = enable short circuit protection
0 = disable short circuit protection 0 = disable short circuit protection
qcom,short-circuit-dbnc-time - qcom,short-circuit-dbnc-time
usage: optional usage: optional
Value type: <u32> Value type: <u32>
Definitioan: Short circuit debounce time (in Fsw). Supported Definitioan: Short circuit debounce time (in Fsw). Supported
@ -126,26 +140,26 @@ qcom,short-circuit-dbnc-time
Fast precharge properties: Fast precharge properties:
------------------------- -------------------------
qcom,fast-precharge-ppulse-enable - qcom,fast-precharge-ppulse-enable
usage: optional usage: optional
Value type: <u32> Value type: <u32>
Definitioan: Fast precharge pfet pulsing enable/disable. Definitioan: Fast precharge pfet pulsing enable/disable.
1 = enable fast precharge pfet pulsing 1 = enable fast precharge pfet pulsing
0 = disable fast precharge pfet pulsing 0 = disable fast precharge pfet pulsing
qcom,precharge-debounce-time-ms - qcom,precharge-debounce-time-ms
usage: optional usage: optional
Value type: <u32> Value type: <u32>
Definitioan: Fast precharge debounce time (in ms). Supported Definitioan: Fast precharge debounce time (in ms). Supported
values are 1, 2, 4, 8. values are 1, 2, 4, 8.
qcom,precharge-pulse-period-us - qcom,precharge-pulse-period-us
usage: optional usage: optional
Value type: <u32> Value type: <u32>
Definitioan: Fast precharge pulse period (in us). Supported Definitioan: Fast precharge pulse period (in us). Supported
values are 3, 6, 9, 12. values are 3, 6, 9, 12.
qcom,precharge-pulse-on-time-us - qcom,precharge-pulse-on-time-us
usage: optional usage: optional
Value type: <u32> Value type: <u32>
Definitioan: Fast precharge pulse on time (in ns). Supported Definitioan: Fast precharge pulse on time (in ns). Supported
@ -154,20 +168,20 @@ qcom,precharge-pulse-on-time-us
Pulse Skip Modulation (PSM) properties: Pulse Skip Modulation (PSM) properties:
-------------------------------------- --------------------------------------
qcom,psm-enable - qcom,psm-enable
Usage: optional Usage: optional
Value type: <u32> Value type: <u32>
Definition: Pulse Skip Modulation mode. Definition: Pulse Skip Modulation mode.
1 - Enable PSM mode 1 - Enable PSM mode
0 - Disable PSM mode 0 - Disable PSM mode
qcom,psm-hys-mv - qcom,psm-hys-mv
Usage: optional Usage: optional
Value type: <u32> Value type: <u32>
Definition: PSM hysterysis voltage (in mV). Definition: PSM hysterysis voltage (in mV).
Supported values are 13mV and 26mV. Supported values are 13mV and 26mV.
qcom,psm-vref-mv - qcom,psm-vref-mv
Usage: optional Usage: optional
Value type: <u32> Value type: <u32>
Definition: Reference voltage(in mV) control for PSM comparator. Definition: Reference voltage(in mV) control for PSM comparator.
@ -177,26 +191,26 @@ qcom,psm-vref-mv
Pulse Frequency Modulation (PFM) properties: Pulse Frequency Modulation (PFM) properties:
------------------------------------------- -------------------------------------------
qcom,pfm-enable - qcom,pfm-enable
Usage: optional Usage: optional
Value type: <u32> Value type: <u32>
Definition: Pulse Frequency Modulation mode. Definition: Pulse Frequency Modulation mode.
1 - Enable PFM mode 1 - Enable PFM mode
0 - Disable PFM mode 0 - Disable PFM mode
qcom,pfm-hys-mv - qcom,pfm-hys-mv
Usage: optional Usage: optional
Value type: <u32> Value type: <u32>
Definition: PFM hysterysis voltage (in mV). Definition: PFM hysterysis voltage (in mV).
Supported values are 13mV and 26mV. Supported values are 13mV and 26mV.
qcom,pfm-curr-limit-ma - qcom,pfm-curr-limit-ma
Usage: optional Usage: optional
Value type: <u32> Value type: <u32>
Definition: PFM current limit (in mA). Definition: PFM current limit (in mA).
Supported values are 130, 200, 270, 340. Supported values are 130, 200, 270, 340.
qcom,pfm-off-time-ns - qcom,pfm-off-time-ns
Usage: optional Usage: optional
Value type: <u32> Value type: <u32>
Definition: NFET off time at PFM (in ns). Definition: NFET off time at PFM (in ns).

View file

@ -17,6 +17,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/notifier.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/spmi.h> #include <linux/spmi.h>
@ -24,6 +25,8 @@
#include <linux/regulator/driver.h> #include <linux/regulator/driver.h>
#include <linux/regulator/machine.h> #include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h> #include <linux/regulator/of_regulator.h>
#include <linux/regulator/qpnp-labibb-regulator.h>
#include <linux/qpnp/qpnp-pbs.h>
#define QPNP_OLEDB_REGULATOR_DRIVER_NAME "qcom,qpnp-oledb-regulator" #define QPNP_OLEDB_REGULATOR_DRIVER_NAME "qcom,qpnp-oledb-regulator"
#define OLEDB_VOUT_STEP_MV 100 #define OLEDB_VOUT_STEP_MV 100
@ -91,6 +94,12 @@
#define OLEDB_ENABLE_NLIMIT_BIT_SHIFT 7 #define OLEDB_ENABLE_NLIMIT_BIT_SHIFT 7
#define OLEDB_NLIMIT_PGM_MASK GENMASK(1, 0) #define OLEDB_NLIMIT_PGM_MASK GENMASK(1, 0)
#define OLEDB_SPARE_CTL 0xE9
#define OLEDB_FORCE_PD_CTL_SPARE_BIT BIT(7)
#define OLEDB_PD_PBS_TRIGGER_BIT BIT(0)
#define OLEDB_SEC_UNLOCK_CODE 0xA5
#define OLEDB_PSM_HYS_CTRL_MIN 13 #define OLEDB_PSM_HYS_CTRL_MIN 13
#define OLEDB_PSM_HYS_CTRL_MAX 26 #define OLEDB_PSM_HYS_CTRL_MAX 26
@ -150,6 +159,9 @@ struct qpnp_oledb {
struct qpnp_oledb_psm_ctl psm_ctl; struct qpnp_oledb_psm_ctl psm_ctl;
struct qpnp_oledb_pfm_ctl pfm_ctl; struct qpnp_oledb_pfm_ctl pfm_ctl;
struct qpnp_oledb_fast_precharge_ctl fast_prechg_ctl; struct qpnp_oledb_fast_precharge_ctl fast_prechg_ctl;
struct notifier_block oledb_nb;
struct mutex bus_lock;
struct device_node *pbs_dev_node;
u32 base; u32 base;
u8 mod_enable; u8 mod_enable;
@ -168,6 +180,7 @@ struct qpnp_oledb {
bool ext_pin_control; bool ext_pin_control;
bool dynamic_ext_pinctl_config; bool dynamic_ext_pinctl_config;
bool pbs_control; bool pbs_control;
bool force_pd_control;
}; };
static const u16 oledb_warmup_dly_ns[] = {6700, 13300, 26700, 53400}; static const u16 oledb_warmup_dly_ns[] = {6700, 13300, 26700, 53400};
@ -184,11 +197,13 @@ static int qpnp_oledb_read(struct qpnp_oledb *oledb, u32 address,
int rc = 0; int rc = 0;
struct platform_device *pdev = oledb->pdev; struct platform_device *pdev = oledb->pdev;
mutex_lock(&oledb->bus_lock);
rc = regmap_bulk_read(oledb->regmap, address, val, count); rc = regmap_bulk_read(oledb->regmap, address, val, count);
if (rc) if (rc)
pr_err("Failed to read address=0x%02x sid=0x%02x rc=%d\n", pr_err("Failed to read address=0x%02x sid=0x%02x rc=%d\n",
address, to_spmi_device(pdev->dev.parent)->usid, rc); address, to_spmi_device(pdev->dev.parent)->usid, rc);
mutex_unlock(&oledb->bus_lock);
return rc; return rc;
} }
@ -197,6 +212,7 @@ static int qpnp_oledb_masked_write(struct qpnp_oledb *oledb,
{ {
int rc; int rc;
mutex_lock(&oledb->bus_lock);
rc = regmap_update_bits(oledb->regmap, address, mask, val); rc = regmap_update_bits(oledb->regmap, address, mask, val);
if (rc < 0) if (rc < 0)
pr_err("Failed to write address 0x%04X, rc = %d\n", pr_err("Failed to write address 0x%04X, rc = %d\n",
@ -205,6 +221,31 @@ static int qpnp_oledb_masked_write(struct qpnp_oledb *oledb,
pr_debug("Wrote 0x%02X to addr 0x%04X\n", pr_debug("Wrote 0x%02X to addr 0x%04X\n",
val, address); val, address);
mutex_unlock(&oledb->bus_lock);
return rc;
}
#define OLEDB_SEC_ACCESS 0xD0
static int qpnp_oledb_sec_masked_write(struct qpnp_oledb *oledb, u16 address,
u8 mask, u8 val)
{
int rc = 0;
u8 sec_val = OLEDB_SEC_UNLOCK_CODE;
u16 sec_reg_addr = (address & 0xFF00) | OLEDB_SEC_ACCESS;
mutex_lock(&oledb->bus_lock);
rc = regmap_write(oledb->regmap, sec_reg_addr, sec_val);
if (rc < 0) {
pr_err("register %x failed rc = %d\n", sec_reg_addr, rc);
goto error;
}
rc = regmap_update_bits(oledb->regmap, address, mask, val);
if (rc < 0)
pr_err("spmi write failed: addr=%03X, rc=%d\n", address, rc);
error:
mutex_unlock(&oledb->bus_lock);
return rc; return rc;
} }
@ -214,6 +255,7 @@ static int qpnp_oledb_write(struct qpnp_oledb *oledb, u16 address, u8 *val,
int rc = 0; int rc = 0;
struct platform_device *pdev = oledb->pdev; struct platform_device *pdev = oledb->pdev;
mutex_lock(&oledb->bus_lock);
rc = regmap_bulk_write(oledb->regmap, address, val, count); rc = regmap_bulk_write(oledb->regmap, address, val, count);
if (rc) if (rc)
pr_err("Failed to write address=0x%02x sid=0x%02x rc=%d\n", pr_err("Failed to write address=0x%02x sid=0x%02x rc=%d\n",
@ -222,7 +264,8 @@ static int qpnp_oledb_write(struct qpnp_oledb *oledb, u16 address, u8 *val,
pr_debug("Wrote 0x%02X to addr 0x%04X\n", pr_debug("Wrote 0x%02X to addr 0x%04X\n",
*val, address); *val, address);
return 0; mutex_unlock(&oledb->bus_lock);
return rc;
} }
static int qpnp_oledb_regulator_enable(struct regulator_dev *rdev) static int qpnp_oledb_regulator_enable(struct regulator_dev *rdev)
@ -285,6 +328,8 @@ static int qpnp_oledb_regulator_enable(struct regulator_dev *rdev)
static int qpnp_oledb_regulator_disable(struct regulator_dev *rdev) static int qpnp_oledb_regulator_disable(struct regulator_dev *rdev)
{ {
int rc = 0; int rc = 0;
u8 trigger_bitmap = OLEDB_PD_PBS_TRIGGER_BIT;
u8 val;
struct qpnp_oledb *oledb = rdev_get_drvdata(rdev); struct qpnp_oledb *oledb = rdev_get_drvdata(rdev);
@ -314,6 +359,27 @@ static int qpnp_oledb_regulator_disable(struct regulator_dev *rdev)
pr_debug("Register-control mode, module disabled\n"); pr_debug("Register-control mode, module disabled\n");
} }
if (oledb->force_pd_control) {
rc = qpnp_oledb_read(oledb, oledb->base + OLEDB_SPARE_CTL,
&val, 1);
if (rc < 0) {
pr_err("Failed to read OLEDB_SPARE_CTL rc=%d\n", rc);
return rc;
}
if (val & OLEDB_FORCE_PD_CTL_SPARE_BIT) {
rc = qpnp_pbs_trigger_event(oledb->pbs_dev_node,
trigger_bitmap);
if (rc < 0) {
pr_err("Failed to trigger the PBS sequence\n");
return rc;
}
pr_debug("PBS event triggered\n");
} else {
pr_debug("OLEDB_SPARE_CTL register bit not set\n");
}
}
oledb->mod_enable = false; oledb->mod_enable = false;
return rc; return rc;
@ -1034,6 +1100,18 @@ static int qpnp_oledb_parse_dt(struct qpnp_oledb *oledb)
oledb->pbs_control = oledb->pbs_control =
of_property_read_bool(of_node, "qcom,pbs-control"); of_property_read_bool(of_node, "qcom,pbs-control");
oledb->force_pd_control =
of_property_read_bool(of_node, "qcom,force-pd-control");
if (oledb->force_pd_control) {
oledb->pbs_dev_node = of_parse_phandle(of_node,
"qcom,pbs-client", 0);
if (!oledb->pbs_dev_node) {
pr_err("Missing qcom,pbs-client property\n");
return -EINVAL;
}
}
oledb->current_voltage = -EINVAL; oledb->current_voltage = -EINVAL;
rc = of_property_read_u32(of_node, "qcom,oledb-init-voltage-mv", rc = of_property_read_u32(of_node, "qcom,oledb-init-voltage-mv",
&oledb->current_voltage); &oledb->current_voltage);
@ -1116,6 +1194,52 @@ static int qpnp_oledb_parse_dt(struct qpnp_oledb *oledb)
return rc; return rc;
} }
static int qpnp_oledb_force_pulldown_config(struct qpnp_oledb *oledb)
{
int rc = 0;
u8 val;
rc = qpnp_oledb_sec_masked_write(oledb, oledb->base +
OLEDB_SPARE_CTL, OLEDB_FORCE_PD_CTL_SPARE_BIT, 0);
if (rc < 0) {
pr_err("Failed to write SPARE_CTL rc=%d\n", rc);
return rc;
}
val = 1;
rc = qpnp_oledb_write(oledb, oledb->base + OLEDB_PD_CTL,
&val, 1);
if (rc < 0) {
pr_err("Failed to write PD_CTL rc=%d\n", rc);
return rc;
}
rc = qpnp_oledb_masked_write(oledb, oledb->base +
OLEDB_SWIRE_CONTROL, OLEDB_EN_SWIRE_PD_UPD_BIT, 0);
if (rc < 0)
pr_err("Failed to write SWIRE_CTL for pbs mode rc=%d\n",
rc);
return rc;
}
static int qpnp_labibb_notifier_cb(struct notifier_block *nb,
unsigned long action, void *data)
{
int rc = 0;
struct qpnp_oledb *oledb = container_of(nb, struct qpnp_oledb,
oledb_nb);
if (action == LAB_VREG_OK) {
/* Disable SWIRE pull down control and enable via spmi mode */
rc = qpnp_oledb_force_pulldown_config(oledb);
if (rc < 0)
return NOTIFY_STOP;
}
return NOTIFY_OK;
}
static int qpnp_oledb_regulator_probe(struct platform_device *pdev) static int qpnp_oledb_regulator_probe(struct platform_device *pdev)
{ {
int rc = 0; int rc = 0;
@ -1143,6 +1267,7 @@ static int qpnp_oledb_regulator_probe(struct platform_device *pdev)
return rc; return rc;
} }
mutex_init(&(oledb->bus_lock));
oledb->base = val; oledb->base = val;
rc = qpnp_oledb_parse_dt(oledb); rc = qpnp_oledb_parse_dt(oledb);
if (rc < 0) { if (rc < 0) {
@ -1156,18 +1281,47 @@ static int qpnp_oledb_regulator_probe(struct platform_device *pdev)
return rc; return rc;
} }
if (oledb->force_pd_control) {
oledb->oledb_nb.notifier_call = qpnp_labibb_notifier_cb;
rc = qpnp_labibb_notifier_register(&oledb->oledb_nb);
if (rc < 0) {
pr_err("Failed to register qpnp_labibb_notifier_cb\n");
return rc;
}
}
rc = qpnp_oledb_register_regulator(oledb); rc = qpnp_oledb_register_regulator(oledb);
if (!rc) if (rc < 0) {
pr_info("OLEDB registered successfully, ext_pin_en=%d mod_en=%d cuurent_voltage=%d mV\n", pr_err("Failed to register regulator rc=%d\n", rc);
goto out;
}
pr_info("OLEDB registered successfully, ext_pin_en=%d mod_en=%d current_voltage=%d mV\n",
oledb->ext_pin_control, oledb->mod_enable, oledb->ext_pin_control, oledb->mod_enable,
oledb->current_voltage); oledb->current_voltage);
return 0;
out:
if (oledb->force_pd_control) {
rc = qpnp_labibb_notifier_unregister(&oledb->oledb_nb);
if (rc < 0)
pr_err("Failed to unregister lab_vreg_ok notifier\n");
}
return rc; return rc;
} }
static int qpnp_oledb_regulator_remove(struct platform_device *pdev) static int qpnp_oledb_regulator_remove(struct platform_device *pdev)
{ {
return 0; int rc = 0;
struct qpnp_oledb *oledb = platform_get_drvdata(pdev);
if (oledb->force_pd_control) {
rc = qpnp_labibb_notifier_unregister(&oledb->oledb_nb);
if (rc < 0)
pr_err("Failed to unregister lab_vreg_ok notifier\n");
}
return rc;
} }
const struct of_device_id qpnp_oledb_regulator_match_table[] = { const struct of_device_id qpnp_oledb_regulator_match_table[] = {