diff --git a/Documentation/devicetree/bindings/regulator/qpnp-oledb-regulator.txt b/Documentation/devicetree/bindings/regulator/qpnp-oledb-regulator.txt new file mode 100644 index 000000000000..5d80a04c0b88 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/qpnp-oledb-regulator.txt @@ -0,0 +1,230 @@ +QPNP OLEDB (AMOLED AVDD Bias) Regulator + +QPNP OLEDB module provides AVDD voltage bias to the AMOLED display panel. +The supported voltage range is 5V to 8.1V. + +This document describes the bindings for QPNP OLEDB module. + +======================= +Required Node Structure +======================= + +- compatible + Usage: required + Value type: + Definition: should be "qcom,qpnp-oledb-regulator". + +- reg + Usage: required + Value type: + Definition: Base address of the OLEDB SPMI peripheral. + +- label + Usage: required + Value type: + Definition: A string used to describe the bias type(oledb). + +- regulator-name + Usage: required + Value type: + Definition: A string used to describe the regulator. + +- regulator-min-microvolt + Usage: required + Value type: + Definition: Minimum voltage (in uV) supported by the bias (5000000uV). + +- regulator-max-microvolt + Usage: required + Value type: + Definition: Maximum voltage (in uV) supported by the bias (8100000uV). + +- qcom,swire-control + Usage: optional + Value type: + Definition: Enables the voltage programming through SWIRE signal. + + qcom,ext-pin-control + Usage: optional + Value type: + Definition: Configures the OLED module to be enabled by a external pin. + + qcom,dynamic-ext-pinctl-config + Usage: optional + Value type: + Definition: Used to dynamically enable/disable the OLEDB module + using external pin to avoid the glitches on the voltage + rail. This property is applicable only if qcom,ext-pin-ctl + property is specified and it is specific to PM660A. + + qcom,pbs-control + Usage: optional + Value type: + Definition: PMIC PBS logic directly configures the output voltage update + and pull down control. + + qcom,oledb-init-voltage-mv + Usage: optional + Value type: + Definition: Sets the AVDD bias voltage (in mV) when the module is + already enabled. Applicable only if the qcom,swire-control + property is not specified. Supported values are from 5.0V + to 8.1V with a step of 100mV. + +qcom,oledb-default-voltage-mv + Usage: optional + Value type: + Definition: Sets the default AVDD bias voltage (in mV) before module + enable. Supported values are from 5.0V to 8.1V with the + step of 100mV. + +qcom,bias-gen-warmup-delay-ns + Usage: optional + Value type: + Definition: Bias generator warm-up time (ns). Supported values are + 6700, 13300, 267000, 534000. + +qcom,peak-curr-limit-ma + Usage: optional + Value type: + Definition: Peak current limit (in mA). Supported values are 115, 265, + 415, 570, 720, 870, 1020, 1170. + +qcom,pull-down-enable + Usage: optional + Value type: + Definition: Pull down configuration of OLEDB. + 1 - Enable pull-down + 0 - Disable pull-down + +qcom,negative-curr-limit-enable + Usage: optional + Value type: + Definition: negative current limit enable/disable. + 1 = enable negative current limit + 0 = disable negative current limit + +qcom,negative-curr-limit-ma + Usage: optional + Value type: + Definition: Negative current limit (in mA). Supported values are + 170, 300, 420, 550. + +qcom,enable-short-circuit + Usage: optional + Value type: + Definition: Short circuit protection enable/disable. + 1 = enable short circuit protection + 0 = disable short circuit protection + +qcom,short-circuit-dbnc-time + usage: optional + Value type: + Definitioan: Short circuit debounce time (in Fsw). Supported + values are 2, 4, 8, 16. + +Fast precharge properties: +------------------------- + +qcom,fast-precharge-ppulse-enable + usage: optional + Value type: + Definitioan: Fast precharge pfet pulsing enable/disable. + 1 = enable fast precharge pfet pulsing + 0 = disable fast precharge pfet pulsing + +qcom,precharge-debounce-time-ms + usage: optional + Value type: + Definitioan: Fast precharge debounce time (in ms). Supported + values are 1, 2, 4, 8. + +qcom,precharge-pulse-period-us + usage: optional + Value type: + Definitioan: Fast precharge pulse period (in us). Supported + values are 3, 6, 9, 12. + +qcom,precharge-pulse-on-time-us + usage: optional + Value type: + Definitioan: Fast precharge pulse on time (in ns). Supported + values are 1200, 1800, 2400, 3000. + +Pulse Skip Modulation (PSM) properties: +-------------------------------------- + +qcom,psm-enable + Usage: optional + Value type: + Definition: Pulse Skip Modulation mode. + 1 - Enable PSM mode + 0 - Disable PSM mode + +qcom,psm-hys-mv + Usage: optional + Value type: + Definition: PSM hysterysis voltage (in mV). + Supported values are 13mV and 26mV. + +qcom,psm-vref-mv + Usage: optional + Value type: + Definition: Reference voltage(in mV) control for PSM comparator. + Supported values are 440, 510, 580, 650, 715, 780, 850, + and 920. + +Pulse Frequency Modulation (PFM) properties: +------------------------------------------- + +qcom,pfm-enable + Usage: optional + Value type: + Definition: Pulse Frequency Modulation mode. + 1 - Enable PFM mode + 0 - Disable PFM mode + +qcom,pfm-hys-mv + Usage: optional + Value type: + Definition: PFM hysterysis voltage (in mV). + Supported values are 13mV and 26mV. + +qcom,pfm-curr-limit-ma + Usage: optional + Value type: + Definition: PFM current limit (in mA). + Supported values are 130, 200, 270, 340. + +qcom,pfm-off-time-ns + Usage: optional + Value type: + Definition: NFET off time at PFM (in ns). + Supported values are 110, 240, 350, 480. + +======= +Example +======= + +pm660a_oledb: qpnp-oledb@e000 { + compatible = "qcom,qpnp-oledb-regulator"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xe000 0x100>; + + label = "oledb"; + regulator-name = "regulator-oledb"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <8100000>; + + qcom,swire-control; + qcom,ext-pin-control; + + qcom,oledb-default-voltage-mv = <5000>; + qcom,bias-gen-warmup-delay-ns = <6700>; + qcom,pull-down-enable = <1>; + qcom,peak-curr-limit-ma = <570>; + + qcom, enable-psm = <1>; + qcom,psm-hys-mv = <13>; +}; diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index bd2c1a8e7540..8d54ece776e2 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -835,6 +835,15 @@ config REGULATOR_QPNP_LCDB negative voltage bias for the LCD display panel. It also allows configurability for the various bias-voltage parameters. +config REGULATOR_QPNP_OLEDB + depends on SPMI + tristate "Qualcomm Technologies, Inc QPNP OLEDB regulator support" + help + This driver supports the OLEDB(AVDD bias) signal for AMOLED panel in Qualcomm + Technologies, Inc QPNP PMIC. It exposes the OLED voltage configuration + via the regulator framework. The configurable range of this bias is + 5V to 8.1V. + config REGULATOR_SPM bool "SPM regulator driver" depends on SPMI diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index abd116d3d8af..20cf304a4714 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -117,6 +117,7 @@ obj-$(CONFIG_REGULATOR_CPRH_KBSS) += cprh-kbss-regulator.o obj-$(CONFIG_REGULATOR_CPR4_MMSS_LDO) += cpr4-mmss-ldo-regulator.o obj-$(CONFIG_REGULATOR_QPNP_LABIBB) += qpnp-labibb-regulator.o obj-$(CONFIG_REGULATOR_QPNP_LCDB) += qpnp-lcdb-regulator.o +obj-$(CONFIG_REGULATOR_QPNP_OLEDB) += qpnp-oledb-regulator.o obj-$(CONFIG_REGULATOR_STUB) += stub-regulator.o obj-$(CONFIG_REGULATOR_KRYO) += kryo-regulator.o obj-$(CONFIG_REGULATOR_CPR2_GFX) += cpr2-gfx-regulator.o diff --git a/drivers/regulator/qpnp-oledb-regulator.c b/drivers/regulator/qpnp-oledb-regulator.c new file mode 100644 index 000000000000..dd52b74b11b6 --- /dev/null +++ b/drivers/regulator/qpnp-oledb-regulator.c @@ -0,0 +1,1193 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "OLEDB: %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define QPNP_OLEDB_REGULATOR_DRIVER_NAME "qcom,qpnp-oledb-regulator" +#define OLEDB_VOUT_STEP_MV 100 +#define OLEDB_VOUT_MIN_MV 5000 +#define OLEDB_VOUT_MAX_MV 8100 +#define OLEDB_VOUT_HW_DEFAULT 6400 + +#define OLEDB_MODULE_RDY 0x45 +#define OLEDB_MODULE_RDY_BIT BIT(7) + +#define OLEDB_MODULE_ENABLE 0x46 +#define OLEDB_MODULE_ENABLE_BIT BIT(7) + +#define OLEDB_EXT_PIN_CTL 0x47 +#define OLEDB_EXT_PIN_CTL_BIT BIT(7) + +#define OLEDB_SWIRE_CONTROL 0x48 +#define OLEDB_EN_SWIRE_VOUT_UPD_BIT BIT(6) +#define OLEDB_EN_SWIRE_PD_UPD_BIT BIT(7) + +#define OLEDB_VOUT_PGM 0x49 +#define OLEDB_VOUT_PGM_MASK GENMASK(4, 0) + +#define OLEDB_VOUT_DEFAULT 0x4A +#define OLEDB_VOUT_DEFAULT_MASK GENMASK(4, 0) + +#define OLEDB_PD_CTL 0x4B + +#define OLEDB_ILIM_NFET 0x4E +#define OLEDB_ILIMIT_NFET_MASK GENMASK(2, 0) + +#define OLEDB_BIAS_GEN_WARMUP_DELAY 0x52 +#define OLEDB_BIAS_GEN_WARMUP_DELAY_MASK GENMASK(1, 0) + +#define OLEDB_SHORT_PROTECT 0x59 +#define OLEDB_ENABLE_SC_DETECTION_BIT BIT(7) +#define OLEDB_DBNC_SHORT_DETECTION_MASK GENMASK(1, 0) + +#define OLEDB_FAST_PRECHARGE 0x5A +#define OLEDB_FAST_PRECHG_PPULSE_EN_BIT BIT(7) +#define OLEDB_DBNC_PRECHARGE_MASK GENMASK(5, 4) +#define OLEDB_DBNC_PRECHARGE_SHIFT 4 +#define OLEDB_PRECHARGE_PULSE_PERIOD_MASK GENMASK(3, 2) +#define OLEDB_PRECHARGE_PULSE_PERIOD_SHIFT 2 +#define OLEDB_PRECHARGE_PULSE_TON_MASK GENMASK(1, 0) + +#define OLEDB_EN_PSM 0x5B +#define OLEDB_PSM_ENABLE_BIT BIT(7) + +#define OLEDB_PSM_CTL 0x5C +#define OLEDB_PSM_HYSTERYSIS_CTL_BIT BIT(3) +#define OLEDB_PSM_HYSTERYSIS_CTL_BIT_SHIFT 3 +#define OLEDB_VREF_PSM_MASK GENMASK(2, 0) + +#define OLEDB_PFM_CTL 0x5D +#define OLEDB_PFM_ENABLE_BIT BIT(7) +#define OLEDB_PFM_HYSTERYSIS_CTRL_BIT_MASK BIT(4) +#define OLEDB_PFM_HYSTERYSIS_CTL_BIT_SHIFT 4 +#define OLEDB_PFM_CURR_LIMIT_MASK GENMASK(3, 2) +#define OLEDB_PFM_CURR_LIMIT_SHIFT 2 +#define OLEDB_PFM_OFF_TIME_NS_MASK GENMASK(1, 0) + +#define OLEDB_NLIMIT 0x64 +#define OLEDB_ENABLE_NLIMIT_BIT BIT(7) +#define OLEDB_ENABLE_NLIMIT_BIT_SHIFT 7 +#define OLEDB_NLIMIT_PGM_MASK GENMASK(1, 0) + +#define OLEDB_PSM_HYS_CTRL_MIN 13 +#define OLEDB_PSM_HYS_CTRL_MAX 26 + +#define OLEDB_PFM_HYS_CTRL_MIN 13 +#define OLEDB_PFM_HYS_CTRL_MAX 26 + +#define OLEDB_PFM_OFF_TIME_MIN 110 +#define OLEDB_PFM_OFF_TIME_MAX 480 + +#define OLEDB_PRECHG_TIME_MIN 1 +#define OLEDB_PRECHG_TIME_MAX 8 + +#define OLEDB_PRECHG_PULSE_PERIOD_MIN 3 +#define OLEDB_PRECHG_PULSE_PERIOD_MAX 12 + +#define OLEDB_MIN_SC_DBNC_TIME_FSW 2 +#define OLEDB_MAX_SC_DBNC_TIME_FSW 16 + +#define OLEDB_PRECHG_PULSE_ON_TIME_MIN 1200 +#define OLEDB_PRECHG_PULSE_ON_TIME_MAX 3000 + +#define PSM_HYSTERYSIS_MV_TO_VAL(val_mv) ((val_mv/13) - 1) +#define PFM_HYSTERYSIS_MV_TO_VAL(val_mv) ((val_mv/13) - 1) +#define PFM_OFF_TIME_NS_TO_VAL(val_ns) ((val_ns/110) - 1) +#define PRECHG_DEBOUNCE_TIME_MS_TO_VAL(val_ms) ((val_ms/2) - \ + (val_ms/8)) +#define PRECHG_PULSE_PERIOD_US_TO_VAL(val_us) ((val_us/3) - 1) +#define PRECHG_PULSE_ON_TIME_NS_TO_VAL(val_ns) (val_ns/600 - 2) +#define SHORT_CIRCUIT_DEBOUNCE_TIME_TO_VAL(val) ((val/4) - (val/16)) + +struct qpnp_oledb_psm_ctl { + int psm_enable; + int psm_hys_ctl; + int psm_vref; +}; + +struct qpnp_oledb_pfm_ctl { + int pfm_enable; + int pfm_hys_ctl; + int pfm_curr_limit; + int pfm_off_time; +}; + +struct qpnp_oledb_fast_precharge_ctl { + int fast_prechg_ppulse_en; + int prechg_debounce_time; + int prechg_pulse_period; + int prechg_pulse_on_time; +}; + +struct qpnp_oledb { + struct platform_device *pdev; + struct device *dev; + struct regmap *regmap; + struct regulator_desc rdesc; + struct regulator_dev *rdev; + struct qpnp_oledb_psm_ctl psm_ctl; + struct qpnp_oledb_pfm_ctl pfm_ctl; + struct qpnp_oledb_fast_precharge_ctl fast_prechg_ctl; + + u32 base; + int current_voltage; + int default_voltage; + int vout_mv; + int warmup_delay; + int peak_curr_limit; + int pd_ctl; + int negative_curr_limit; + int nlimit_enable; + int sc_en; + int sc_dbnc_time; + bool mod_enable; + bool swire_control; + bool ext_pin_control; + bool ext_pinctl_state; + bool dynamic_ext_pinctl_config; + bool pbs_control; +}; + +static const u16 oledb_warmup_dly_ns[] = {6700, 13300, 26700, 53400}; +static const u16 oledb_peak_curr_limit_ma[] = {115, 265, 415, 570, + 720, 870, 1020, 1170}; +static const u16 oledb_psm_vref_mv[] = {440, 510, 580, 650, 715, + 780, 850, 920}; +static const u16 oledb_pfm_curr_limit_ma[] = {130, 200, 270, 340}; +static const u16 oledb_nlimit_ma[] = {170, 300, 420, 550}; + +static int qpnp_oledb_read(struct qpnp_oledb *oledb, u32 address, + u8 *val, int count) +{ + int rc = 0; + struct platform_device *pdev = oledb->pdev; + + rc = regmap_bulk_read(oledb->regmap, address, val, count); + if (rc) + pr_err("Failed to read address=0x%02x sid=0x%02x rc=%d\n", + address, to_spmi_device(pdev->dev.parent)->usid, rc); + + return rc; +} + +static int qpnp_oledb_masked_write(struct qpnp_oledb *oledb, + u32 address, u8 mask, u8 val) +{ + int rc; + + rc = regmap_update_bits(oledb->regmap, address, mask, val); + if (rc < 0) + pr_err("Failed to write address 0x%04X, rc = %d\n", + address, rc); + else + pr_debug("Wrote 0x%02X to addr 0x%04X\n", + val, address); + + return rc; +} + +static int qpnp_oledb_write(struct qpnp_oledb *oledb, u16 address, u8 *val, + int count) +{ + int rc = 0; + struct platform_device *pdev = oledb->pdev; + + rc = regmap_bulk_write(oledb->regmap, address, val, count); + if (rc) + pr_err("Failed to write address=0x%02x sid=0x%02x rc=%d\n", + address, to_spmi_device(pdev->dev.parent)->usid, rc); + else + pr_debug("Wrote 0x%02X to addr 0x%04X\n", + *val, address); + + return 0; +} + +static int qpnp_oledb_regulator_enable(struct regulator_dev *rdev) +{ + int rc = 0; + u8 val = 0; + + struct qpnp_oledb *oledb = rdev_get_drvdata(rdev); + + if (oledb->ext_pin_control) { + rc = qpnp_oledb_read(oledb, oledb->base + OLEDB_EXT_PIN_CTL, + &val, 1); + if (rc < 0) { + pr_err("Failed to read EXT_PIN_CTL rc=%d\n", rc); + return rc; + } + + /* + * Enable ext-pin-ctl after display-supply is turned on. + * This is to avoid glitches on the external pin. + */ + if (!(val & OLEDB_EXT_PIN_CTL_BIT) && + oledb->dynamic_ext_pinctl_config) { + val = OLEDB_EXT_PIN_CTL_BIT; + rc = qpnp_oledb_write(oledb, oledb->base + + OLEDB_EXT_PIN_CTL, &val, 1); + if (rc < 0) { + pr_err("Failed to write EXT_PIN_CTL rc=%d\n", + rc); + return rc; + } + } + pr_debug("ext-pin-ctrl mode enabled\n"); + } else { + val = OLEDB_MODULE_ENABLE_BIT; + rc = qpnp_oledb_write(oledb, oledb->base + OLEDB_MODULE_ENABLE, + &val, 1); + if (rc < 0) { + pr_err("Failed to write MODULE_ENABLE rc=%d\n", rc); + return rc; + } + + ndelay(oledb->warmup_delay); + pr_debug("register-control mode, module enabled\n"); + } + + oledb->mod_enable = true; + if (oledb->pbs_control) { + rc = qpnp_oledb_masked_write(oledb, oledb->base + + OLEDB_SWIRE_CONTROL, OLEDB_EN_SWIRE_PD_UPD_BIT | + OLEDB_EN_SWIRE_VOUT_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_oledb_regulator_disable(struct regulator_dev *rdev) +{ + int rc = 0; + + struct qpnp_oledb *oledb = rdev_get_drvdata(rdev); + + /* + * Disable ext-pin-ctl after display-supply is turned off. This is to + * avoid glitches on the external pin. + */ + if (oledb->ext_pin_control && oledb->dynamic_ext_pinctl_config) { + rc = qpnp_oledb_masked_write(oledb, oledb->base + + OLEDB_EXT_PIN_CTL, OLEDB_EXT_PIN_CTL_BIT, 0); + if (rc < 0) { + pr_err("Failed to write EXT_PIN_CTL rc=%d\n", rc); + return rc; + } + pr_debug("ext-pin-ctrl mode disabled\n"); + } else { + rc = qpnp_oledb_masked_write(oledb, oledb->base + + OLEDB_MODULE_ENABLE, + OLEDB_MODULE_ENABLE_BIT, 0); + if (rc < 0) { + pr_err("Failed to write MODULE_ENABLE rc=%d\n", rc); + return rc; + } + pr_debug("Register-control mode, module disabled\n"); + } + + oledb->mod_enable = false; + + return rc; +} + +static int qpnp_oledb_regulator_is_enabled(struct regulator_dev *rdev) +{ + struct qpnp_oledb *oledb = rdev_get_drvdata(rdev); + + return oledb->mod_enable; +} + +static int qpnp_oledb_regulator_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV, unsigned *selector) +{ + u8 val; + int rc = 0; + + struct qpnp_oledb *oledb = rdev_get_drvdata(rdev); + + if (oledb->swire_control) + return 0; + + val = DIV_ROUND_UP(min_uV - OLEDB_VOUT_MIN_MV, OLEDB_VOUT_STEP_MV); + + rc = qpnp_oledb_write(oledb, oledb->base + OLEDB_VOUT_PGM, + &val, 1); + if (rc < 0) { + pr_err("Failed to write VOUT_PGM rc=%d\n", rc); + return rc; + } + + oledb->current_voltage = min_uV; + pr_debug("register-control mode, current voltage %d\n", + oledb->current_voltage); + + return 0; +} + +static int qpnp_oledb_regulator_get_voltage(struct regulator_dev *rdev) +{ + struct qpnp_oledb *oledb = rdev_get_drvdata(rdev); + + if (oledb->swire_control) + return 0; + + return oledb->current_voltage; +} + +static struct regulator_ops qpnp_oledb_ops = { + .enable = qpnp_oledb_regulator_enable, + .disable = qpnp_oledb_regulator_disable, + .is_enabled = qpnp_oledb_regulator_is_enabled, + .set_voltage = qpnp_oledb_regulator_set_voltage, + .get_voltage = qpnp_oledb_regulator_get_voltage, +}; + +static int qpnp_oledb_register_regulator(struct qpnp_oledb *oledb) +{ + int rc = 0; + struct platform_device *pdev = oledb->pdev; + struct regulator_init_data *init_data; + struct regulator_desc *rdesc = &oledb->rdesc; + struct regulator_config cfg = {}; + + init_data = of_get_regulator_init_data(&pdev->dev, + pdev->dev.of_node, rdesc); + if (!init_data) { + pr_err("Unable to get OLEDB regulator init data\n"); + return -ENOMEM; + } + + if (init_data->constraints.name) { + rdesc->owner = THIS_MODULE; + rdesc->type = REGULATOR_VOLTAGE; + rdesc->ops = &qpnp_oledb_ops; + rdesc->name = init_data->constraints.name; + + cfg.dev = &pdev->dev; + cfg.init_data = init_data; + cfg.driver_data = oledb; + cfg.of_node = pdev->dev.of_node; + + if (of_get_property(pdev->dev.of_node, "parent-supply", + NULL)) + init_data->supply_regulator = "parent"; + + init_data->constraints.valid_ops_mask + |= REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS; + + oledb->rdev = devm_regulator_register(oledb->dev, rdesc, &cfg); + if (IS_ERR(oledb->rdev)) { + rc = PTR_ERR(oledb->rdev); + oledb->rdev = NULL; + pr_err("Unable to register OLEDB regulator, rc = %d\n", + rc); + return rc; + } + } else { + pr_err("OLEDB regulator name missing\n"); + return -EINVAL; + } + + return 0; +} + +static int qpnp_oledb_get_curr_voltage(struct qpnp_oledb *oledb, + u16 *current_voltage) +{ + int rc = 0; + u8 val; + + if (!(oledb->mod_enable || oledb->ext_pinctl_state)) { + rc = qpnp_oledb_read(oledb, oledb->base + OLEDB_VOUT_DEFAULT, + &val, 1); + if (rc < 0) { + pr_err("Failed to read VOUT_DEFAULT rc=%d\n", rc); + return rc; + } + } else { + rc = qpnp_oledb_read(oledb, oledb->base + + OLEDB_VOUT_PGM, &val, 1); + if (rc < 0) { + pr_err("Failed to read VOUT_PGM rc=%d\n", rc); + return rc; + } + } + + *current_voltage = (val * OLEDB_VOUT_STEP_MV) + OLEDB_VOUT_MIN_MV; + + return rc; +} + +static int qpnp_oledb_init_nlimit(struct qpnp_oledb *oledb) +{ + int rc = 0, i = 0; + u32 val, mask = 0; + + if (oledb->nlimit_enable != -EINVAL) { + val = oledb->nlimit_enable << + OLEDB_ENABLE_NLIMIT_BIT_SHIFT; + mask = OLEDB_ENABLE_NLIMIT_BIT; + if (oledb->negative_curr_limit != -EINVAL) { + for (i = 0; i < ARRAY_SIZE(oledb_nlimit_ma); i++) { + if (oledb->negative_curr_limit == + oledb_nlimit_ma[i]) + break; + } + val |= i; + mask |= OLEDB_NLIMIT_PGM_MASK; + } + rc = qpnp_oledb_masked_write(oledb, oledb->base + + OLEDB_NLIMIT, mask, val); + if (rc < 0) + pr_err("Failed to write NLIMT rc=%d\n", rc); + } + + return rc; +} + +static int qpnp_oledb_init_psm(struct qpnp_oledb *oledb) +{ + int rc = 0, i = 0; + u32 val = 0, mask = 0, temp = 0; + struct qpnp_oledb_psm_ctl *psm_ctl = &oledb->psm_ctl; + + if (psm_ctl->psm_enable == -EINVAL) + return rc; + + if (psm_ctl->psm_enable) { + val = OLEDB_PSM_ENABLE_BIT; + rc = qpnp_oledb_masked_write(oledb, oledb->base + + OLEDB_EN_PSM, OLEDB_PSM_ENABLE_BIT, val); + if (rc < 0) { + pr_err("Failed to write PSM_EN rc=%d\n", rc); + return rc; + } + + val = 0; + if (psm_ctl->psm_vref != -EINVAL) { + for (i = 0; i < ARRAY_SIZE(oledb_psm_vref_mv); i++) { + if (psm_ctl->psm_vref == + oledb_psm_vref_mv[i]) + break; + } + val = i; + mask = OLEDB_VREF_PSM_MASK; + } + + if (psm_ctl->psm_hys_ctl != -EINVAL) { + temp = PSM_HYSTERYSIS_MV_TO_VAL(psm_ctl->psm_hys_ctl); + val |= (temp << OLEDB_PSM_HYSTERYSIS_CTL_BIT_SHIFT); + mask |= OLEDB_PSM_HYSTERYSIS_CTL_BIT; + } + if (val) { + rc = qpnp_oledb_masked_write(oledb, oledb->base + + OLEDB_PSM_CTL, mask, val); + if (rc < 0) + pr_err("Failed to write PSM_CTL rc=%d\n", rc); + } + } else { + rc = qpnp_oledb_masked_write(oledb, oledb->base + + OLEDB_EN_PSM, OLEDB_PSM_ENABLE_BIT, 0); + if (rc < 0) + pr_err("Failed to write PSM_CTL rc=%d\n", rc); + } + + return rc; +} + +static int qpnp_oledb_init_pfm(struct qpnp_oledb *oledb) +{ + int rc = 0, i = 0; + u32 val = 0, temp = 0, mask = 0; + struct qpnp_oledb_pfm_ctl *pfm_ctl = &oledb->pfm_ctl; + + if (pfm_ctl->pfm_enable == -EINVAL) + return rc; + + if (pfm_ctl->pfm_enable) { + mask = val = OLEDB_PFM_ENABLE_BIT; + if (pfm_ctl->pfm_hys_ctl != -EINVAL) { + temp = PFM_HYSTERYSIS_MV_TO_VAL(pfm_ctl->pfm_hys_ctl); + val |= temp << + OLEDB_PFM_HYSTERYSIS_CTL_BIT_SHIFT; + mask |= OLEDB_PFM_HYSTERYSIS_CTRL_BIT_MASK; + } + + if (pfm_ctl->pfm_curr_limit != -EINVAL) { + for (i = 0; i < ARRAY_SIZE(oledb_pfm_curr_limit_ma); + i++) { + if (pfm_ctl->pfm_curr_limit == + oledb_pfm_curr_limit_ma[i]) + break; + } + val |= (i << OLEDB_PFM_CURR_LIMIT_SHIFT); + mask |= OLEDB_PFM_CURR_LIMIT_MASK; + } + + if (pfm_ctl->pfm_off_time != -EINVAL) { + val |= PFM_OFF_TIME_NS_TO_VAL(pfm_ctl->pfm_off_time); + mask |= OLEDB_PFM_OFF_TIME_NS_MASK; + } + + rc = qpnp_oledb_masked_write(oledb, oledb->base + + OLEDB_PFM_CTL, mask, val); + if (rc < 0) + pr_err("Failed to write PFM_CTL rc=%d\n", rc); + } else { + rc = qpnp_oledb_masked_write(oledb, oledb->base + + OLEDB_PFM_CTL, OLEDB_PFM_ENABLE_BIT, 0); + if (rc < 0) + pr_err("Failed to write PFM_CTL rc=%d\n", rc); + } + + return rc; +} + +static int qpnp_oledb_init_fast_precharge(struct qpnp_oledb *oledb) +{ + int rc = 0; + u32 val = 0, temp = 0, mask = 0; + struct qpnp_oledb_fast_precharge_ctl *prechg_ctl = + &oledb->fast_prechg_ctl; + + if (prechg_ctl->fast_prechg_ppulse_en == -EINVAL) + return rc; + + if (prechg_ctl->fast_prechg_ppulse_en) { + mask = val = OLEDB_FAST_PRECHG_PPULSE_EN_BIT; + if (prechg_ctl->prechg_debounce_time != -EINVAL) { + temp = PRECHG_DEBOUNCE_TIME_MS_TO_VAL( + prechg_ctl->prechg_debounce_time); + val |= temp << OLEDB_DBNC_PRECHARGE_SHIFT; + mask |= OLEDB_DBNC_PRECHARGE_MASK; + } + + if (prechg_ctl->prechg_pulse_period != -EINVAL) { + temp = PRECHG_PULSE_PERIOD_US_TO_VAL( + prechg_ctl->prechg_pulse_period); + val |= temp << OLEDB_PRECHARGE_PULSE_PERIOD_SHIFT; + mask |= OLEDB_PRECHARGE_PULSE_PERIOD_MASK; + } + + if (prechg_ctl->prechg_pulse_on_time != -EINVAL) { + val |= PRECHG_PULSE_ON_TIME_NS_TO_VAL( + prechg_ctl->prechg_pulse_on_time); + mask |= OLEDB_PRECHARGE_PULSE_TON_MASK; + } + + rc = qpnp_oledb_masked_write(oledb, oledb->base + + OLEDB_FAST_PRECHARGE, mask, val); + if (rc < 0) + pr_err("Failed to write FAST_PRECHARGE rc=%d\n", rc); + } else { + rc = qpnp_oledb_masked_write(oledb, oledb->base + + OLEDB_FAST_PRECHARGE, + OLEDB_FAST_PRECHG_PPULSE_EN_BIT, 0); + if (rc < 0) + pr_err("Failed to write FAST_PRECHARGE rc=%d\n", rc); + } + + return rc; +} + +static int qpnp_oledb_hw_init(struct qpnp_oledb *oledb) +{ + int rc, i = 0; + u8 val = 0, mask = 0; + u16 current_voltage; + + if (oledb->default_voltage != -EINVAL) { + val = (oledb->default_voltage - OLEDB_VOUT_MIN_MV) / + OLEDB_VOUT_STEP_MV; + rc = qpnp_oledb_write(oledb, oledb->base + + OLEDB_VOUT_DEFAULT, &val, 1); + if (rc < 0) { + pr_err("Failed to write VOUT_DEFAULT rc=%d\n", rc); + return rc; + } + } + + rc = qpnp_oledb_read(oledb, oledb->base + OLEDB_MODULE_ENABLE, + (u8 *)&oledb->mod_enable, 1); + if (rc < 0) { + pr_err("Failed to read MODULE_ENABLE rc=%d\n", rc); + return rc; + } + + rc = qpnp_oledb_read(oledb, oledb->base + OLEDB_EXT_PIN_CTL, + (u8 *)&oledb->ext_pinctl_state, 1); + if (rc < 0) { + pr_err("Failed to read EXT_PIN_CTL rc=%d\n", rc); + return rc; + } + + rc = qpnp_oledb_get_curr_voltage(oledb, ¤t_voltage); + if (rc < 0) + return rc; + + if (!((val & OLEDB_EXT_PIN_CTL_BIT) || oledb->mod_enable)) { + if (oledb->warmup_delay != -EINVAL) { + for (i = 0; i < ARRAY_SIZE(oledb_warmup_dly_ns); i++) { + if (oledb->warmup_delay == + oledb_warmup_dly_ns[i]) + break; + } + val = i; + rc = qpnp_oledb_masked_write(oledb, + oledb->base + OLEDB_BIAS_GEN_WARMUP_DELAY, + OLEDB_BIAS_GEN_WARMUP_DELAY_MASK, val); + if (rc < 0) { + pr_err("Failed to write WARMUP_DELAY rc=%d\n", + rc); + return rc; + } + } else { + rc = qpnp_oledb_read(oledb, oledb->base + + OLEDB_BIAS_GEN_WARMUP_DELAY, + &val, 1); + if (rc < 0) { + pr_err("Failed to read WARMUP_DELAY rc=%d\n", + rc); + return rc; + } + oledb->warmup_delay = oledb_warmup_dly_ns[val]; + } + + if (oledb->peak_curr_limit != -EINVAL) { + for (i = 0; i < ARRAY_SIZE(oledb_peak_curr_limit_ma); + i++) { + if (oledb->peak_curr_limit == + oledb_peak_curr_limit_ma[i]) + break; + } + val = i; + rc = qpnp_oledb_write(oledb, + oledb->base + OLEDB_ILIM_NFET, + &val, 1); + if (rc < 0) { + pr_err("Failed to write ILIM_NEFT rc=%d\n", rc); + return rc; + } + } + + if (oledb->pd_ctl != -EINVAL) { + val = oledb->pd_ctl; + 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; + } + } + + if (oledb->sc_en != -EINVAL) { + val = oledb->sc_en ? OLEDB_ENABLE_SC_DETECTION_BIT : 0; + mask = OLEDB_ENABLE_SC_DETECTION_BIT; + if (oledb->sc_dbnc_time != -EINVAL) { + val |= SHORT_CIRCUIT_DEBOUNCE_TIME_TO_VAL( + oledb->sc_dbnc_time); + mask |= OLEDB_DBNC_PRECHARGE_MASK; + } + + rc = qpnp_oledb_write(oledb, oledb->base + + OLEDB_SHORT_PROTECT, &val, 1); + if (rc < 0) { + pr_err("Failed to write SHORT_PROTECT rc=%d\n", + rc); + return rc; + } + } + + rc = qpnp_oledb_init_nlimit(oledb); + if (rc < 0) + return rc; + + rc = qpnp_oledb_init_psm(oledb); + if (rc < 0) + return rc; + + rc = qpnp_oledb_init_pfm(oledb); + if (rc < 0) + return rc; + + rc = qpnp_oledb_init_fast_precharge(oledb); + if (rc < 0) + return rc; + + if (oledb->swire_control) { + val = OLEDB_EN_SWIRE_PD_UPD_BIT | + OLEDB_EN_SWIRE_VOUT_UPD_BIT; + rc = qpnp_oledb_masked_write(oledb, oledb->base + + OLEDB_SWIRE_CONTROL, OLEDB_EN_SWIRE_PD_UPD_BIT | + OLEDB_EN_SWIRE_VOUT_UPD_BIT, val); + if (rc < 0) + return rc; + } + + rc = qpnp_oledb_read(oledb, oledb->base + OLEDB_MODULE_RDY, + &val, 1); + if (rc < 0) { + pr_err("Failed to read MODULE_RDY rc=%d\n", rc); + return rc; + } + + if (!(val & OLEDB_MODULE_RDY_BIT)) { + val = OLEDB_MODULE_RDY_BIT; + rc = qpnp_oledb_write(oledb, oledb->base + + OLEDB_MODULE_RDY, &val, 1); + if (rc < 0) { + pr_err("Failed to write MODULE_RDY rc=%d\n", + rc); + return rc; + } + } + + if (!oledb->dynamic_ext_pinctl_config) { + if (oledb->ext_pin_control) { + val = OLEDB_EXT_PIN_CTL_BIT; + rc = qpnp_oledb_write(oledb, oledb->base + + OLEDB_EXT_PIN_CTL, &val, 1); + if (rc < 0) { + pr_err("Failed to write EXT_PIN_CTL rc=%d\n", + rc); + return rc; + } + } else { + val = OLEDB_MODULE_ENABLE_BIT; + rc = qpnp_oledb_write(oledb, oledb->base + + OLEDB_MODULE_ENABLE, &val, 1); + if (rc < 0) { + pr_err("Failed to write MODULE_ENABLE rc=%d\n", + rc); + return rc; + } + + ndelay(oledb->warmup_delay); + } + + oledb->mod_enable = true; + if (oledb->pbs_control) { + rc = qpnp_oledb_masked_write(oledb, + oledb->base + OLEDB_SWIRE_CONTROL, + OLEDB_EN_SWIRE_PD_UPD_BIT | + OLEDB_EN_SWIRE_VOUT_UPD_BIT, 0); + if (rc < 0) { + pr_err("Failed to write SWIRE_CTL rc=%d\n", + rc); + return rc; + } + } + } + + oledb->current_voltage = current_voltage; + } else { + /* module is enabled */ + if (oledb->current_voltage == -EINVAL) { + oledb->current_voltage = current_voltage; + } else if (!oledb->swire_control) { + if (oledb->current_voltage < OLEDB_VOUT_MIN_MV) { + pr_err("current_voltage %d is less than min_volt %d\n", + oledb->current_voltage, OLEDB_VOUT_MIN_MV); + return -EINVAL; + } + val = DIV_ROUND_UP(oledb->current_voltage - + OLEDB_VOUT_MIN_MV, OLEDB_VOUT_STEP_MV); + rc = qpnp_oledb_write(oledb, oledb->base + + OLEDB_VOUT_PGM, &val, 1); + if (rc < 0) { + pr_err("Failed to write VOUT_PGM rc=%d\n", + rc); + return rc; + } + } + + oledb->mod_enable = true; + } + + return rc; +} + +static int qpnp_oledb_parse_nlimit(struct qpnp_oledb *oledb) +{ + int rc = 0; + struct device_node *of_node = oledb->dev->of_node; + + oledb->nlimit_enable = -EINVAL; + rc = of_property_read_u32(of_node, "qcom,negative-curr-limit-enable", + &oledb->nlimit_enable); + if (!rc) { + oledb->negative_curr_limit = -EINVAL; + rc = of_property_read_u32(of_node, + "qcom,negative-curr-limit-ma", + &oledb->negative_curr_limit); + if (!rc) { + u16 min_curr_limit = oledb_nlimit_ma[0]; + u16 max_curr_limit = oledb_nlimit_ma[ARRAY_SIZE( + oledb_nlimit_ma) - 1]; + if (oledb->negative_curr_limit < min_curr_limit || + oledb->negative_curr_limit > max_curr_limit) { + pr_err("Invalid value in qcom,negative-curr-limit-ma\n"); + return -EINVAL; + } + } + } + + return 0; +} + +static int qpnp_oledb_parse_psm(struct qpnp_oledb *oledb) +{ + int rc = 0; + struct qpnp_oledb_psm_ctl *psm_ctl = &oledb->psm_ctl; + struct device_node *of_node = oledb->dev->of_node; + + psm_ctl->psm_enable = -EINVAL; + rc = of_property_read_u32(of_node, "qcom,psm-enable", + &psm_ctl->psm_enable); + if (!rc) { + psm_ctl->psm_hys_ctl = -EINVAL; + rc = of_property_read_u32(of_node, "qcom,psm-hys-mv", + &psm_ctl->psm_hys_ctl); + if (!rc) { + if (psm_ctl->psm_hys_ctl < OLEDB_PSM_HYS_CTRL_MIN || + psm_ctl->psm_hys_ctl > OLEDB_PSM_HYS_CTRL_MAX) { + pr_err("Invalid value in qcom,psm-hys-mv\n"); + return -EINVAL; + } + } + + psm_ctl->psm_vref = -EINVAL; + rc = of_property_read_u32(of_node, "qcom,psm-vref-mv", + &psm_ctl->psm_vref); + if (!rc) { + u16 min_vref = oledb_psm_vref_mv[0]; + u16 max_vref = oledb_psm_vref_mv[ARRAY_SIZE( + oledb_psm_vref_mv) - 1]; + if (psm_ctl->psm_vref < min_vref || + psm_ctl->psm_vref > max_vref) { + pr_err("Invalid value in qcom,psm-vref-mv\n"); + return -EINVAL; + } + } + } + + return 0; +} + +static int qpnp_oledb_parse_pfm(struct qpnp_oledb *oledb) +{ + int rc = 0; + struct qpnp_oledb_pfm_ctl *pfm_ctl = &oledb->pfm_ctl; + struct device_node *of_node = oledb->dev->of_node; + + pfm_ctl->pfm_enable = -EINVAL; + rc = of_property_read_u32(of_node, "qcom,pfm-enable", + &pfm_ctl->pfm_enable); + if (!rc) { + pfm_ctl->pfm_hys_ctl = -EINVAL; + rc = of_property_read_u32(of_node, "qcom,pfm-hys-mv", + &pfm_ctl->pfm_hys_ctl); + if (!rc) { + if (pfm_ctl->pfm_hys_ctl < OLEDB_PFM_HYS_CTRL_MIN || + pfm_ctl->pfm_hys_ctl > OLEDB_PFM_HYS_CTRL_MAX) { + pr_err("Invalid value in qcom,pfm-hys-mv\n"); + return -EINVAL; + } + } + + pfm_ctl->pfm_curr_limit = -EINVAL; + rc = of_property_read_u32(of_node, + "qcom,pfm-curr-limit-ma", &pfm_ctl->pfm_curr_limit); + if (!rc) { + u16 min_limit = oledb_pfm_curr_limit_ma[0]; + u16 max_limit = oledb_pfm_curr_limit_ma[ARRAY_SIZE( + oledb_pfm_curr_limit_ma) - 1]; + if (pfm_ctl->pfm_curr_limit < min_limit || + pfm_ctl->pfm_curr_limit > max_limit) { + pr_err("Invalid value in qcom,pfm-curr-limit-ma\n"); + return -EINVAL; + } + } + + pfm_ctl->pfm_off_time = -EINVAL; + rc = of_property_read_u32(of_node, "qcom,pfm-off-time-ns", + &pfm_ctl->pfm_off_time); + if (!rc) { + if (pfm_ctl->pfm_off_time < OLEDB_PFM_OFF_TIME_MIN || + pfm_ctl->pfm_off_time > OLEDB_PFM_OFF_TIME_MAX) { + pr_err("Invalid value in qcom,pfm-off-time-ns\n"); + return -EINVAL; + } + } + } + + return 0; +} + +static int qpnp_oledb_parse_fast_precharge(struct qpnp_oledb *oledb) +{ + int rc = 0; + struct device_node *of_node = oledb->dev->of_node; + struct qpnp_oledb_fast_precharge_ctl *fast_prechg = + &oledb->fast_prechg_ctl; + + fast_prechg->fast_prechg_ppulse_en = -EINVAL; + rc = of_property_read_u32(of_node, "qcom,fast-precharge-ppulse-enable", + &fast_prechg->fast_prechg_ppulse_en); + if (!rc) { + fast_prechg->prechg_debounce_time = -EINVAL; + rc = of_property_read_u32(of_node, + "qcom,precharge-debounce-time-ms", + &fast_prechg->prechg_debounce_time); + if (!rc) { + int dbnc_time = fast_prechg->prechg_debounce_time; + + if (dbnc_time < OLEDB_PRECHG_TIME_MIN || dbnc_time > + OLEDB_PRECHG_TIME_MAX) { + pr_err("Invalid value in qcom,precharge-debounce-time-ms\n"); + return -EINVAL; + } + } + + fast_prechg->prechg_pulse_period = -EINVAL; + rc = of_property_read_u32(of_node, + "qcom,precharge-pulse-period-us", + &fast_prechg->prechg_pulse_period); + if (!rc) { + int pulse_period = fast_prechg->prechg_pulse_period; + + if (pulse_period < OLEDB_PRECHG_PULSE_PERIOD_MIN || + pulse_period > OLEDB_PRECHG_PULSE_PERIOD_MAX) { + pr_err("Invalid value in qcom,precharge-pulse-period-us\n"); + return -EINVAL; + } + } + + fast_prechg->prechg_pulse_on_time = -EINVAL; + rc = of_property_read_u32(of_node, + "qcom,precharge-pulse-on-time-ns", + &fast_prechg->prechg_pulse_on_time); + if (!rc) { + int pulse_on_time = fast_prechg->prechg_pulse_on_time; + + if (pulse_on_time < OLEDB_PRECHG_PULSE_ON_TIME_MIN || + pulse_on_time > OLEDB_PRECHG_PULSE_ON_TIME_MAX) { + pr_err("Invalid value in qcom,precharge-pulse-on-time-ns\n"); + return -EINVAL; + } + } + } + + return 0; +} + +static int qpnp_oledb_parse_dt(struct qpnp_oledb *oledb) +{ + int rc = 0; + struct device_node *of_node = oledb->dev->of_node; + + oledb->swire_control = + of_property_read_bool(of_node, "qcom,swire-control"); + + oledb->ext_pin_control = + of_property_read_bool(of_node, "qcom,ext-pin-control"); + + if (oledb->ext_pin_control) + oledb->dynamic_ext_pinctl_config = + of_property_read_bool(of_node, + "qcom,dynamic-ext-pinctl-config"); + oledb->pbs_control = + of_property_read_bool(of_node, "qcom,pbs-control"); + + oledb->current_voltage = -EINVAL; + rc = of_property_read_u32(of_node, "qcom,oledb-init-voltage-mv", + &oledb->current_voltage); + if (!rc && (oledb->current_voltage < OLEDB_VOUT_MIN_MV || + oledb->current_voltage > OLEDB_VOUT_MAX_MV)) { + pr_err("Invalid value in qcom,oledb-init-voltage-mv\n"); + return -EINVAL; + } + + oledb->default_voltage = -EINVAL; + rc = of_property_read_u32(of_node, "qcom,oledb-default-voltage-mv", + &oledb->default_voltage); + if (!rc && (oledb->default_voltage < OLEDB_VOUT_MIN_MV || + oledb->default_voltage > OLEDB_VOUT_MAX_MV)) { + pr_err("Invalid value in qcom,oledb-default-voltage-mv\n"); + return -EINVAL; + } + + oledb->warmup_delay = -EINVAL; + rc = of_property_read_u32(of_node, "qcom,bias-gen-warmup-delay-ns", + &oledb->warmup_delay); + if (!rc) { + u16 min_delay = oledb_warmup_dly_ns[0]; + u16 max_delay = oledb_warmup_dly_ns[ARRAY_SIZE( + oledb_warmup_dly_ns) - 1]; + if (oledb->warmup_delay < min_delay || + oledb->warmup_delay > max_delay) { + pr_err("Invalid value in qcom,bias-gen-warmup-delay-ns\n"); + return -EINVAL; + } + } + + oledb->peak_curr_limit = -EINVAL; + rc = of_property_read_u32(of_node, "qcom,peak-curr-limit-ma", + &oledb->peak_curr_limit); + if (!rc) { + u16 min_limit = oledb_peak_curr_limit_ma[0]; + u16 max_limit = oledb_peak_curr_limit_ma[ARRAY_SIZE( + oledb_peak_curr_limit_ma) - 1]; + if (oledb->peak_curr_limit < min_limit || + oledb->peak_curr_limit > max_limit) { + pr_err("Invalid value in qcom,peak-curr-limit-ma\n"); + return -EINVAL; + } + } + + oledb->pd_ctl = -EINVAL; + of_property_read_u32(of_node, "qcom,pull-down-enable", &oledb->pd_ctl); + + oledb->sc_en = -EINVAL; + rc = of_property_read_u32(of_node, "qcom,enable-short-circuit", + &oledb->sc_en); + if (!rc) { + oledb->sc_dbnc_time = -EINVAL; + rc = of_property_read_u32(of_node, + "qcom,short-circuit-dbnc-time", &oledb->sc_dbnc_time); + if (!rc) { + if (oledb->sc_dbnc_time < OLEDB_MIN_SC_DBNC_TIME_FSW || + oledb->sc_dbnc_time > OLEDB_MAX_SC_DBNC_TIME_FSW) { + pr_err("Invalid value in qcom,short-circuit-dbnc-time\n"); + return -EINVAL; + } + } + } + + rc = qpnp_oledb_parse_nlimit(oledb); + if (rc < 0) + return rc; + + rc = qpnp_oledb_parse_psm(oledb); + if (rc < 0) + return rc; + + rc = qpnp_oledb_parse_pfm(oledb); + if (rc < 0) + return rc; + + rc = qpnp_oledb_parse_fast_precharge(oledb); + + return rc; +} + +static int qpnp_oledb_regulator_probe(struct platform_device *pdev) +{ + int rc = 0; + u32 val; + struct qpnp_oledb *oledb; + struct device_node *of_node = pdev->dev.of_node; + + oledb = devm_kzalloc(&pdev->dev, + sizeof(struct qpnp_oledb), GFP_KERNEL); + if (!oledb) + return -ENOMEM; + + oledb->pdev = pdev; + oledb->dev = &pdev->dev; + oledb->regmap = dev_get_regmap(pdev->dev.parent, NULL); + dev_set_drvdata(&pdev->dev, oledb); + if (!oledb->regmap) { + pr_err("Couldn't get parent's regmap\n"); + return -EINVAL; + } + + rc = of_property_read_u32(of_node, "reg", &val); + if (rc < 0) { + pr_err("Couldn't find reg in node, rc = %d\n", rc); + return rc; + } + + oledb->base = val; + rc = qpnp_oledb_parse_dt(oledb); + if (rc < 0) { + pr_err("Failed to parse common OLEDB device tree\n"); + return rc; + } + + rc = qpnp_oledb_hw_init(oledb); + if (rc < 0) { + pr_err("Failed to initialize OLEDB, rc=%d\n", rc); + return rc; + } + + rc = qpnp_oledb_register_regulator(oledb); + if (!rc) + pr_info("OLEDB registered successfully, ext_pin_en=%d mod_en=%d cuurent_voltage=%d mV\n", + oledb->ext_pin_control, oledb->mod_enable, + oledb->current_voltage); + + return rc; +} + +static int qpnp_oledb_regulator_remove(struct platform_device *pdev) +{ + return 0; +} + +const struct of_device_id qpnp_oledb_regulator_match_table[] = { + { .compatible = QPNP_OLEDB_REGULATOR_DRIVER_NAME,}, + { }, +}; + +static struct platform_driver qpnp_oledb_regulator_driver = { + .driver = { + .name = QPNP_OLEDB_REGULATOR_DRIVER_NAME, + .of_match_table = qpnp_oledb_regulator_match_table, + }, + .probe = qpnp_oledb_regulator_probe, + .remove = qpnp_oledb_regulator_remove, +}; + +static int __init qpnp_oledb_regulator_init(void) +{ + return platform_driver_register(&qpnp_oledb_regulator_driver); +} +arch_initcall(qpnp_oledb_regulator_init); + +static void __exit qpnp_oledb_regulator_exit(void) +{ + platform_driver_unregister(&qpnp_oledb_regulator_driver); +} +module_exit(qpnp_oledb_regulator_exit); + +MODULE_DESCRIPTION("QPNP OLEDB driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("qpnp-oledb-regulator");