diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/regulator/qpnp-labibb-regulator.c | 2304 |
1 files changed, 1553 insertions, 751 deletions
diff --git a/drivers/regulator/qpnp-labibb-regulator.c b/drivers/regulator/qpnp-labibb-regulator.c index 15ade85f446b..8dbe3080873c 100644 --- a/drivers/regulator/qpnp-labibb-regulator.c +++ b/drivers/regulator/qpnp-labibb-regulator.c @@ -46,6 +46,7 @@ /* LAB register offset definitions */ #define REG_LAB_STATUS1 0x08 +#define REG_LAB_SWIRE_PGM_CTL 0x40 #define REG_LAB_VOLTAGE 0x41 #define REG_LAB_RING_SUPPRESSION_CTL 0x42 #define REG_LAB_LCD_AMOLED_SEL 0x44 @@ -63,16 +64,25 @@ #define REG_LAB_SPARE_CTL 0x60 #define REG_LAB_PFM_CTL 0x62 +/* LAB registers for PM660A */ +#define REG_LAB_VOUT_DEFAULT 0x44 +#define REG_LAB_SW_HIGH_PSRR_CTL 0x70 +#define REG_LAB_LDO_PD_CTL 0x78 +#define REG_LAB_VPH_ENVELOP_CTL 0x7E + /* LAB register bits definitions */ /* REG_LAB_STATUS1 */ #define LAB_STATUS1_VREG_OK_MASK BIT(7) #define LAB_STATUS1_VREG_OK BIT(7) +/* REG_LAB_SWIRE_PGM_CTL */ +#define LAB_EN_SWIRE_PGM_VOUT BIT(7) +#define LAB_EN_SWIRE_PGM_PD BIT(6) + /* REG_LAB_VOLTAGE */ #define LAB_VOLTAGE_OVERRIDE_EN BIT(7) -#define LAB_VOLTAGE_SET_BITS 4 -#define LAB_VOLTAGE_SET_MASK ((1 << LAB_VOLTAGE_SET_BITS) - 1) +#define LAB_VOLTAGE_SET_MASK GENMASK(3, 0) /* REG_LAB_RING_SUPPRESSION_CTL */ #define LAB_RING_SUPPRESSION_CTL_EN BIT(7) @@ -98,34 +108,27 @@ #define LAB_OVERRIDE_CURRENT_MAX_BIT BIT(3) /* REG_LAB_CURRENT_SENSE */ -#define LAB_CURRENT_SENSE_GAIN_BITS 2 -#define LAB_CURRENT_SENSE_GAIN_MASK ((1 << LAB_CURRENT_SENSE_GAIN_BITS) \ - - 1) +#define LAB_CURRENT_SENSE_GAIN_MASK GENMASK(1, 0) /* REG_LAB_PS_CTL */ -#define LAB_PS_CTL_BITS 2 -#define LAB_PS_CTL_MASK ((1 << LAB_PS_CTL_BITS) - 1) +#define LAB_PS_THRESH_MASK GENMASK(1, 0) #define LAB_PS_CTL_EN BIT(7) /* REG_LAB_RDSON_MNGMNT */ #define LAB_RDSON_MNGMNT_NFET_SLEW_EN BIT(5) #define LAB_RDSON_MNGMNT_PFET_SLEW_EN BIT(4) -#define LAB_RDSON_MNGMNT_NFET_BITS 2 -#define LAB_RDSON_MNGMNT_NFET_MASK ((1 << LAB_RDSON_MNGMNT_NFET_BITS) - 1) +#define LAB_RDSON_MNGMNT_NFET_MASK GENMASK(3, 2) #define LAB_RDSON_MNGMNT_NFET_SHIFT 2 -#define LAB_RDSON_MNGMNT_PFET_BITS 2 -#define LAB_RDSON_MNGMNT_PFET_MASK ((1 << LAB_RDSON_MNGMNT_PFET_BITS) - 1) +#define LAB_RDSON_MNGMNT_PFET_MASK GENMASK(1, 0) #define LAB_RDSON_NFET_SW_SIZE_QUARTER 0x0 #define LAB_RDSON_PFET_SW_SIZE_QUARTER 0x0 /* REG_LAB_PRECHARGE_CTL */ -#define LAB_PRECHARGE_CTL_EN BIT(2) -#define LAB_PRECHARGE_CTL_EN_BITS 2 -#define LAB_PRECHARGE_CTL_EN_MASK ((1 << LAB_PRECHARGE_CTL_EN_BITS) - 1) +#define LAB_FAST_PRECHARGE_CTL_EN BIT(2) +#define LAB_MAX_PRECHARGE_TIME_MASK GENMASK(1, 0) /* REG_LAB_SOFT_START_CTL */ -#define LAB_SOFT_START_CTL_BITS 2 -#define LAB_SOFT_START_CTL_MASK ((1 << LAB_SOFT_START_CTL_BITS) - 1) +#define LAB_SOFT_START_CTL_MASK GENMASK(1, 0) /* REG_LAB_SPARE_CTL */ #define LAB_SPARE_TOUCH_WAKE_BIT BIT(3) @@ -134,10 +137,19 @@ /* REG_LAB_PFM_CTL */ #define LAB_PFM_EN_BIT BIT(7) +/* REG_LAB_SW_HIGH_PSRR_CTL */ +#define LAB_EN_SW_HIGH_PSRR_MODE BIT(7) +#define LAB_SW_HIGH_PSRR_REQ BIT(0) + +/* REG_LAB_VPH_ENVELOP_CTL */ +#define LAB_VREF_HIGH_PSRR_SEL_MASK GENMASK(7, 6) +#define LAB_SEL_HW_HIGH_PSRR_SRC_MASK GENMASK(1, 0) +#define LAB_SEL_HW_HIGH_PSRR_SRC_SHIFT 6 + /* IBB register offset definitions */ #define REG_IBB_REVISION4 0x03 #define REG_IBB_STATUS1 0x08 -#define REG_IBB_VOLTAGE 0x41 +#define REG_IBB_VOLTAGE 0x41 #define REG_IBB_RING_SUPPRESSION_CTL 0x42 #define REG_IBB_LCD_AMOLED_SEL 0x44 #define REG_IBB_MODULE_RDY 0x45 @@ -153,9 +165,19 @@ #define REG_IBB_PWRUP_PWRDN_CTL_2 0x59 #define REG_IBB_SOFT_START_CTL 0x5F #define REG_IBB_SWIRE_CTL 0x5A +#define REG_IBB_OUTPUT_SLEW_CTL 0x5D #define REG_IBB_SPARE_CTL 0x60 #define REG_IBB_NLIMIT_DAC 0x61 +/* IBB registers for PM660A */ +#define REG_IBB_DEFAULT_VOLTAGE 0x40 +#define REG_IBB_FLOAT_CTL 0x43 +#define REG_IBB_VREG_OK_CTL 0x55 +#define REG_IBB_VOUT_MIN_MAGNITUDE 0x5C +#define REG_IBB_PFM_CTL 0x62 +#define REG_IBB_SMART_PS_CTL 0x65 +#define REG_IBB_ADAPT_DEAD_TIME 0x67 + /* IBB register bits definition */ /* REG_IBB_STATUS1 */ @@ -164,12 +186,22 @@ /* REG_IBB_VOLTAGE */ #define IBB_VOLTAGE_OVERRIDE_EN BIT(7) -#define IBB_VOLTAGE_SET_BITS 6 -#define IBB_VOLTAGE_SET_MASK ((1 << IBB_VOLTAGE_SET_BITS) - 1) +#define IBB_VOLTAGE_SET_MASK GENMASK(5, 0) + +/* REG_IBB_CLK_DIV */ +#define IBB_CLK_DIV_OVERRIDE_EN BIT(7) +#define IBB_CLK_DIV_MASK GENMASK(3, 0) /* REG_IBB_RING_SUPPRESSION_CTL */ #define IBB_RING_SUPPRESSION_CTL_EN BIT(7) +/* REG_IBB_FLOAT_CTL */ +#define IBB_FLOAT_EN BIT(0) +#define IBB_SMART_FLOAT_EN BIT(7) + +/* REG_IBB_MIN_MAGNITUDE */ +#define IBB_MIN_VOLTAGE_0P8_V BIT(3) + /* REG_IBB_MODULE_RDY */ #define IBB_MODULE_RDY_EN BIT(7) @@ -182,35 +214,47 @@ #define IBB_PD_CTL_HALF_STRENGTH BIT(0) #define IBB_PD_CTL_STRENGTH_MASK BIT(0) #define IBB_PD_CTL_EN BIT(7) +#define IBB_SWIRE_PD_UPD BIT(1) #define IBB_PD_CTL_EN_MASK BIT(7) /* REG_IBB_CURRENT_LIMIT */ -#define IBB_CURRENT_LIMIT_BITS 5 -#define IBB_CURRENT_LIMIT_MASK ((1 << IBB_CURRENT_LIMIT_BITS) - 1) +#define IBB_CURRENT_LIMIT_MASK GENMASK(4, 0) #define IBB_CURRENT_LIMIT_DEBOUNCE_SHIFT 5 +#define IBB_CURRENT_LIMIT_DEBOUNCE_MASK GENMASK(6, 5) #define IBB_CURRENT_LIMIT_EN BIT(7) #define IBB_ILIMIT_COUNT_CYC8 0 #define IBB_CURRENT_MAX_500MA 0xA /* REG_IBB_PS_CTL */ #define IBB_PS_CTL_EN 0x85 -#define IBB_PS_CTL_DISABLE 0x5 + +/* REG_IBB_SMART_PS_CTL */ +#define IBB_SMART_PS_CTL_EN BIT(7) +#define IBB_NUM_SWIRE_PULSE_WAIT 0x5 + +/* REG_IBB_OUTPUT_SLEW_CTL */ +#define IBB_SLEW_CTL_EN BIT(7) +#define IBB_SLEW_RATE_SPEED_FAST_EN BIT(6) +#define IBB_SLEW_RATE_TRANS_TIME_FAST_SHIFT 3 +#define IBB_SLEW_RATE_TRANS_TIME_FAST_MASK GENMASK(5, 3) +#define IBB_SLEW_RATE_TRANS_TIME_SLOW_MASK GENMASK(2, 0) + +/* REG_IBB_VREG_OK_CTL */ +#define IBB_VREG_OK_EN_OVERLOAD_BLANK BIT(7) +#define IBB_VREG_OK_OVERLOAD_DEB_SHIFT 5 +#define IBB_VREG_OK_OVERLOAD_DEB_MASK GENMASK(6, 5) /* REG_IBB_RDSON_MNGMNT */ #define IBB_NFET_SLEW_EN BIT(7) #define IBB_PFET_SLEW_EN BIT(6) #define IBB_OVERRIDE_NFET_SW_SIZE BIT(5) #define IBB_OVERRIDE_PFET_SW_SIZE BIT(2) -#define IBB_NFET_SW_SIZE_BITS 2 -#define IBB_PFET_SW_SIZE_BITS 2 -#define IBB_NFET_SW_SIZE_MASK ((1 << NFET_SW_SIZE_BITS) - 1) -#define IBB_PFET_SW_SIZE_MASK ((1 << PFET_SW_SIZE_BITS) - 1) -#define IBB_NFET_SW_SIZE_SHIFT 3 +#define IBB_NFET_SW_SIZE_MASK GENMASK(3, 2) +#define IBB_PFET_SW_SIZE_MASK GENMASK(1, 0) /* REG_IBB_NONOVERLAP_TIME_1 */ -#define IBB_OVERRIDE_NONOVERLAP BIT(6) -#define IBB_NONOVERLAP_NFET_BITS 3 -#define IBB_NONOVERLAP_NFET_MASK ((1 << IBB_NONOVERLAP_NFET_BITS) - 1) +#define IBB_OVERRIDE_NONOVERLAP BIT(6) +#define IBB_NONOVERLAP_NFET_MASK GENMASK(2, 0) #define IBB_NFET_GATE_DELAY_2 0x3 /* REG_IBB_NONOVERLAP_TIME_2 */ @@ -226,37 +270,41 @@ #define IBB_FAST_STARTUP BIT(3) /* REG_IBB_SWIRE_CTL */ -#define IBB_OUTPUT_VOLTAGE_AT_ONE_PULSE_BITS 6 -#define IBB_OUTPUT_VOLTAGE_AT_ONE_PULSE_MASK \ - ((1 << IBB_OUTPUT_VOLTAGE_AT_ONE_PULSE_BITS) - 1) +#define IBB_SWIRE_VOUT_UPD_EN BIT(6) +#define IBB_OUTPUT_VOLTAGE_AT_ONE_PULSE_MASK GENMASK(5, 0) +#define MAX_OUTPUT_EDGE_VOLTAGE_MV 6300 #define MAX_OUTPUT_PULSE_VOLTAGE_MV 7700 #define MIN_OUTPUT_PULSE_VOLTAGE_MV 1400 #define OUTPUT_VOLTAGE_STEP_MV 100 /* REG_IBB_NLIMIT_DAC */ -#define IBB_NLIMIT_DAC_EN 0x0 -#define IBB_NLIMIT_DAC_DISABLE 0x5 +#define IBB_DEFAULT_NLIMIT_DAC 0x5 + +/* REG_IBB_PFM_CTL */ +#define IBB_PFM_ENABLE BIT(7) +#define IBB_PFM_PEAK_CURRENT_BIT_SHIFT 1 +#define IBB_PFM_PEAK_CURRENT_MASK GENMASK(3, 1) +#define IBB_PFM_HYSTERESIS_BIT_SHIFT 4 +#define IBB_PFM_HYSTERESIS_MASK GENMASK(5, 4) /* REG_IBB_PWRUP_PWRDN_CTL_1 */ #define IBB_PWRUP_PWRDN_CTL_1_DLY1_BITS 2 -#define IBB_PWRUP_PWRDN_CTL_1_DLY1_MASK \ - ((1 << IBB_PWRUP_PWRDN_CTL_1_DLY1_BITS) - 1) +#define IBB_PWRUP_PWRDN_CTL_1_DLY1_MASK GENMASK(5, 4) #define IBB_PWRUP_PWRDN_CTL_1_DLY1_SHIFT 4 -#define IBB_PWRUP_PWRDN_CTL_1_DLY2_BITS 2 -#define IBB_PWRUP_PWRDN_CTL_1_DLY2_MASK \ - ((1 << IBB_PWRUP_PWRDN_CTL_1_DLY2_BITS) - 1) +#define IBB_PWRUP_PWRDN_CTL_1_EN_DLY2 BIT(3) +#define IBB_PWRUP_PWRDN_CTL_1_DLY2_MASK GENMASK(1, 0) #define IBB_PWRUP_PWRDN_CTL_1_LAB_VREG_OK BIT(7) #define IBB_PWRUP_PWRDN_CTL_1_EN_DLY1 BIT(6) #define PWRUP_PWRDN_CTL_1_DISCHARGE_EN BIT(2) /* REG_IBB_PWRUP_PWRDN_CTL_2 */ -#define IBB_DIS_DLY_BITS 2 -#define IBB_DIS_DLY_MASK ((1 << IBB_DIS_DLY_BITS) - 1) +#define IBB_DIS_DLY_MASK GENMASK(1, 0) #define IBB_WAIT_MBG_OK BIT(2) /* Constants */ #define SWIRE_DEFAULT_2ND_CMD_DLY_MS 20 #define SWIRE_DEFAULT_IBB_PS_ENABLE_DLY_MS 200 +#define IBB_HW_DEFAULT_SLEW_RATE 12000 /** * enum qpnp_labibb_mode - working mode of LAB/IBB regulators @@ -285,28 +333,28 @@ enum ibb_mode { IBB_HW_SW_CONTROL, }; -static const int ibb_discharge_resistor_plan[] = { +static const int ibb_discharge_resistor_table[] = { 300, 64, 32, 16, }; -static const int ibb_pwrup_dly_plan[] = { +static const int ibb_pwrup_dly_table[] = { 1000, 2000, 4000, 8000, }; -static const int ibb_pwrdn_dly_plan[] = { +static const int ibb_pwrdn_dly_table[] = { 1000, 2000, 4000, 8000, }; -static const int lab_clk_div_plan[] = { +static const int lab_clk_div_table[] = { 3200, 2740, 2400, @@ -325,7 +373,7 @@ static const int lab_clk_div_plan[] = { 910, }; -static const int ibb_clk_div_plan[] = { +static const int ibb_clk_div_table[] = { 3200, 2740, 2400, @@ -344,7 +392,7 @@ static const int ibb_clk_div_plan[] = { 910, }; -static const int lab_current_limit_plan[] = { +static const int lab_current_limit_table[] = { 200, 400, 600, @@ -355,14 +403,14 @@ static const int lab_current_limit_plan[] = { 1600, }; -static const char * const lab_current_sense_plan[] = { +static const char * const lab_current_sense_table[] = { "0.5x", "1x", "1.5x", "2x" }; -static const int ibb_current_limit_plan[] = { +static const int ibb_current_limit_table[] = { 0, 50, 100, @@ -397,48 +445,105 @@ static const int ibb_current_limit_plan[] = { 1550, }; -static const int ibb_debounce_plan[] = { +static const int ibb_output_slew_ctl_table[] = { + 100, + 200, + 500, + 1000, + 2000, + 10000, + 12000, + 15000 +}; + +static const int ibb_debounce_table[] = { 8, 16, 32, 64, }; -static const int lab_ps_threshold_plan[] = { +static const int ibb_overload_debounce_table[] = { + 1, + 2, + 4, + 8 +}; + +static const int ibb_vreg_ok_deb_table[] = { + 4, + 8, + 16, + 32 +}; + +static const int lab_ps_thresh_table_v1[] = { 20, 30, 40, 50, }; -static const int lab_soft_start_plan[] = { +static const int lab_ps_thresh_table_v2[] = { + 50, + 60, + 70, + 80, +}; + +static const int lab_soft_start_table[] = { 200, 400, 600, 800, }; -static const int lab_rdson_nfet_plan[] = { +static const int lab_rdson_nfet_table[] = { 25, 50, 75, 100, }; -static const int lab_rdson_pfet_plan[] = { +static const int lab_rdson_pfet_table[] = { 25, 50, 75, 100, }; -static const int lab_max_precharge_plan[] = { +static const int lab_max_precharge_table[] = { 200, 300, 400, 500, }; +static const int ibb_pfm_peak_curr_table[] = { + 150, + 200, + 250, + 300, + 350, + 400, + 450, + 500 +}; + +static const int ibb_pfm_hysteresis_table[] = { + 0, + 25, + 50, + 0 +}; + +static const int lab_vref_high_psrr_table[] = { + 350, + 400, + 450, + 500 +}; + struct lab_regulator { struct regulator_desc rdesc; struct regulator_dev *rdev; @@ -471,6 +576,7 @@ struct ibb_regulator { u32 pwrdn_dly; int vreg_enabled; + int num_swire_trans; }; struct qpnp_labibb { @@ -484,12 +590,16 @@ struct qpnp_labibb { u8 ibb_dig_major; struct lab_regulator lab_vreg; struct ibb_regulator ibb_vreg; + const struct ibb_ver_ops *ibb_ver_ops; + const struct lab_ver_ops *lab_ver_ops; + struct mutex bus_mutex; enum qpnp_labibb_mode mode; bool standalone; bool ttw_en; bool in_ttw_mode; bool ibb_settings_saved; bool swire_control; + bool pbs_control; bool ttw_force_lab_on; bool skip_2nd_swire_cmd; bool pfm_enable; @@ -497,6 +607,28 @@ struct qpnp_labibb { u32 swire_ibb_ps_enable_delay; }; +struct ibb_ver_ops { + int (*set_default_voltage)(struct qpnp_labibb *labibb, + bool use_default); + int (*set_voltage)(struct qpnp_labibb *labibb, int min_uV, int max_uV); + int (*sel_mode)(struct qpnp_labibb *labibb, bool is_ibb); + int (*get_mode)(struct qpnp_labibb *labibb); + int (*set_clk_div)(struct qpnp_labibb *labibb, u8 val); + int (*smart_ps_config)(struct qpnp_labibb *labibb, bool enable, + int num_swire_trans, int neg_curr_limit); + int (*soft_start_ctl)(struct qpnp_labibb *labibb, + struct device_node *of_node); + int (*voltage_at_one_pulse)(struct qpnp_labibb *labibb, u32 volt); +}; + +struct lab_ver_ops { + const char *ver_str; + int (*set_default_voltage)(struct qpnp_labibb *labibb, + bool default_pres); + int (*ps_ctl)(struct qpnp_labibb *labibb, + u32 thresh, bool enable); +}; + enum ibb_settings_index { IBB_PD_CTL = 0, IBB_CURRENT_LIMIT, @@ -545,114 +677,722 @@ static struct settings lab_settings[LAB_SETTINGS_MAX] = { SETTING(LAB_RDSON_MNGMNT, false), }; -static int qpnp_labibb_read(struct qpnp_labibb *labibb, u8 *val, u16 address, - int count) +static int +qpnp_labibb_read(struct qpnp_labibb *labibb, u16 address, + u8 *val, int count) { int rc = 0; struct platform_device *pdev = labibb->pdev; - if (address == 0) { - pr_err("address cannot be zero address=0x%02x sid=0x%02x rc=%d\n", - address, to_spmi_device(pdev->dev.parent)->usid, rc); - return -EINVAL; - } - + mutex_lock(&(labibb->bus_mutex)); rc = regmap_bulk_read(labibb->regmap, address, val, count); - if (rc) { + if (rc < 0) pr_err("SPMI read failed address=0x%02x sid=0x%02x rc=%d\n", address, to_spmi_device(pdev->dev.parent)->usid, rc); - return rc; - } - return 0; + mutex_unlock(&(labibb->bus_mutex)); + return rc; } -static int qpnp_labibb_write(struct qpnp_labibb *labibb, u16 address, u8 *val, - int count) +static int +qpnp_labibb_write(struct qpnp_labibb *labibb, u16 address, + u8 *val, int count) { int rc = 0; struct platform_device *pdev = labibb->pdev; + mutex_lock(&(labibb->bus_mutex)); if (address == 0) { pr_err("address cannot be zero address=0x%02x sid=0x%02x rc=%d\n", address, to_spmi_device(pdev->dev.parent)->usid, rc); - return -EINVAL; + rc = -EINVAL; + goto error; } rc = regmap_bulk_write(labibb->regmap, address, val, count); - if (rc) { + if (rc < 0) pr_err("write failed address=0x%02x sid=0x%02x rc=%d\n", address, to_spmi_device(pdev->dev.parent)->usid, rc); - return rc; - } - return 0; +error: + mutex_unlock(&(labibb->bus_mutex)); + return rc; } -static int qpnp_labibb_masked_write(struct qpnp_labibb *labibb, u16 address, - u8 mask, u8 val) +static int +qpnp_labibb_masked_write(struct qpnp_labibb *labibb, u16 address, + u8 mask, u8 val) { - int rc; + int rc = 0; + struct platform_device *pdev = labibb->pdev; + + mutex_lock(&(labibb->bus_mutex)); + if (address == 0) { + pr_err("address cannot be zero address=0x%02x sid=0x%02x\n", + address, to_spmi_device(pdev->dev.parent)->usid); + rc = -EINVAL; + goto error; + } rc = regmap_update_bits(labibb->regmap, address, mask, val); - if (rc) { + if (rc < 0) pr_err("spmi write failed: addr=%03X, rc=%d\n", address, rc); - return rc; - } - return 0; +error: + mutex_unlock(&(labibb->bus_mutex)); + return rc; } static int qpnp_labibb_sec_write(struct qpnp_labibb *labibb, u16 base, - u8 offset, u8 *val, int count) + u8 offset, u8 val) { - int rc; + int rc = 0; u8 sec_val = REG_LAB_IBB_SEC_UNLOCK_CODE; + struct platform_device *pdev = labibb->pdev; - rc = qpnp_labibb_write(labibb, base + REG_LAB_IBB_SEC_ACCESS, &sec_val, - 1); - if (rc) { - pr_err("qpnp_lab_write register %x failed rc = %d\n", + mutex_lock(&(labibb->bus_mutex)); + if (base == 0) { + pr_err("base cannot be zero base=0x%02x sid=0x%02x\n", + base, to_spmi_device(pdev->dev.parent)->usid); + rc = -EINVAL; + goto error; + } + + rc = regmap_write(labibb->regmap, base + REG_LAB_IBB_SEC_ACCESS, + sec_val); + if (rc < 0) { + pr_err("register %x failed rc = %d\n", base + REG_LAB_IBB_SEC_ACCESS, rc); - return rc; + goto error; } - rc = qpnp_labibb_write(labibb, base + offset, val, count); - if (rc) - pr_err("qpnp_labibb_write failed: addr=%03X, rc=%d\n", + rc = regmap_write(labibb->regmap, base + offset, val); + if (rc < 0) + pr_err("failed: addr=%03X, rc=%d\n", base + offset, rc); +error: + mutex_unlock(&(labibb->bus_mutex)); return rc; } static int qpnp_labibb_sec_masked_write(struct qpnp_labibb *labibb, u16 base, u8 offset, u8 mask, u8 val) { - int rc; + int rc = 0; u8 sec_val = REG_LAB_IBB_SEC_UNLOCK_CODE; + struct platform_device *pdev = labibb->pdev; - rc = qpnp_labibb_write(labibb, base + REG_LAB_IBB_SEC_ACCESS, &sec_val, - 1); - if (rc) { - pr_err("qpnp_lab_write register %x failed rc = %d\n", + mutex_lock(&(labibb->bus_mutex)); + if (base == 0) { + pr_err("base cannot be zero base=0x%02x sid=0x%02x\n", + base, to_spmi_device(pdev->dev.parent)->usid); + rc = -EINVAL; + goto error; + } + + rc = regmap_write(labibb->regmap, base + REG_LAB_IBB_SEC_ACCESS, + sec_val); + if (rc < 0) { + pr_err("register %x failed rc = %d\n", base + REG_LAB_IBB_SEC_ACCESS, rc); + goto error; + } + + rc = regmap_update_bits(labibb->regmap, base + offset, mask, val); + if (rc < 0) + pr_err("spmi write failed: addr=%03X, rc=%d\n", base, rc); + +error: + mutex_unlock(&(labibb->bus_mutex)); + return rc; +} + +static int qpnp_ibb_smart_ps_config_v1(struct qpnp_labibb *labibb, bool enable, + int num_swire_trans, int neg_curr_limit) +{ + return 0; +} + +static int qpnp_ibb_smart_ps_config_v2(struct qpnp_labibb *labibb, bool enable, + int num_swire_trans, int neg_curr_limit) +{ + u8 val; + int rc = 0; + + if (enable) { + val = IBB_NUM_SWIRE_PULSE_WAIT; + rc = qpnp_labibb_write(labibb, + labibb->ibb_base + REG_IBB_PS_CTL, &val, 1); + if (rc < 0) { + pr_err("write register %x failed rc = %d\n", + REG_IBB_PS_CTL, rc); + return rc; + } + } + + val = enable ? IBB_SMART_PS_CTL_EN : IBB_NUM_SWIRE_PULSE_WAIT; + if (num_swire_trans) + val |= num_swire_trans; + else + val |= IBB_NUM_SWIRE_PULSE_WAIT; + + rc = qpnp_labibb_write(labibb, + labibb->ibb_base + REG_IBB_SMART_PS_CTL, &val, 1); + if (rc < 0) { + pr_err("write register %x failed rc = %d\n", + REG_IBB_SMART_PS_CTL, rc); return rc; } - rc = qpnp_labibb_masked_write(labibb, base + offset, mask, val); - if (rc) - pr_err("qpnp_lab_write register %x failed rc = %d\n", - base + offset, rc); + val = enable ? (neg_curr_limit ? neg_curr_limit : + IBB_DEFAULT_NLIMIT_DAC) : IBB_DEFAULT_NLIMIT_DAC; + + rc = qpnp_labibb_write(labibb, + labibb->ibb_base + REG_IBB_NLIMIT_DAC, &val, 1); + if (rc < 0) + pr_err("write register %x failed rc = %d\n", + REG_IBB_NLIMIT_DAC, rc); return rc; } +static int qpnp_labibb_sel_mode_v1(struct qpnp_labibb *labibb, bool is_ibb) +{ + int rc = 0; + u8 val; + u16 base; + + val = (labibb->mode == QPNP_LABIBB_LCD_MODE) ? REG_LAB_IBB_LCD_MODE : + REG_LAB_IBB_AMOLED_MODE; + + base = is_ibb ? labibb->ibb_base : labibb->lab_base; + + rc = qpnp_labibb_sec_write(labibb, base, REG_LAB_LCD_AMOLED_SEL, + val); + if (rc < 0) + pr_err("register %x failed rc = %d\n", + REG_LAB_LCD_AMOLED_SEL, rc); + + return rc; +} + +static int qpnp_labibb_sel_mode_v2(struct qpnp_labibb *labibb, bool is_ibb) +{ + return 0; +} + +static int qpnp_ibb_get_mode_v1(struct qpnp_labibb *labibb) +{ + int rc = 0; + u8 val; + + rc = qpnp_labibb_read(labibb, labibb->ibb_base + REG_IBB_LCD_AMOLED_SEL, + &val, 1); + if (rc < 0) + return rc; + + if (val == REG_LAB_IBB_AMOLED_MODE) + labibb->mode = QPNP_LABIBB_AMOLED_MODE; + else + labibb->mode = QPNP_LABIBB_LCD_MODE; + + return 0; +} + +static int qpnp_ibb_get_mode_v2(struct qpnp_labibb *labibb) +{ + labibb->mode = QPNP_LABIBB_AMOLED_MODE; + + return 0; +} + +static int qpnp_ibb_set_clk_div_v1(struct qpnp_labibb *labibb, u8 val) +{ + int rc = 0; + + rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_CLK_DIV, + &val, 1); + + return rc; +} + +static int qpnp_ibb_set_clk_div_v2(struct qpnp_labibb *labibb, u8 val) +{ + int rc = 0; + + val |= IBB_CLK_DIV_OVERRIDE_EN; + rc = qpnp_labibb_masked_write(labibb, labibb->ibb_base + + REG_IBB_CLK_DIV, IBB_CLK_DIV_MASK | + IBB_CLK_DIV_OVERRIDE_EN, val); + + return rc; +} + +static int qpnp_ibb_soft_start_ctl_v1(struct qpnp_labibb *labibb, + struct device_node *of_node) +{ + int rc = 0; + u8 val; + u32 tmp; + + rc = of_property_read_u32(of_node, "qcom,qpnp-ibb-soft-start", + &(labibb->ibb_vreg.soft_start)); + if (rc < 0) { + pr_err("qcom,qpnp-ibb-soft-start is missing, rc = %d\n", + rc); + return rc; + } + + rc = of_property_read_u32(of_node, "qcom,qpnp-ibb-discharge-resistor", + &tmp); + + if (rc < 0) { + pr_err("qcom,qpnp-ibb-discharge-resistor is missing, rc = %d\n", + rc); + return rc; + } + + if (labibb->mode == QPNP_LABIBB_AMOLED_MODE) { + /* + * AMOLED mode needs ibb discharge resistor to be + * configured for 300KOhm + */ + if (tmp < ibb_discharge_resistor_table[0]) + tmp = ibb_discharge_resistor_table[0]; + } + + for (val = 0; val < ARRAY_SIZE(ibb_discharge_resistor_table); val++) + if (ibb_discharge_resistor_table[val] == tmp) + break; + + if (val == ARRAY_SIZE(ibb_discharge_resistor_table)) { + pr_err("Invalid value in qcom,qpnp-ibb-discharge-resistor\n"); + return -EINVAL; + } + + rc = qpnp_labibb_write(labibb, labibb->ibb_base + + REG_IBB_SOFT_START_CTL, &val, 1); + if (rc < 0) + pr_err("write to register %x failed rc = %d\n", + REG_IBB_SOFT_START_CTL, rc); + + return rc; +} + +static int qpnp_ibb_soft_start_ctl_v2(struct qpnp_labibb *labibb, + struct device_node *of_node) +{ + return 0; +} + +static int qpnp_ibb_vreg_ok_ctl(struct qpnp_labibb *labibb, + struct device_node *of_node) +{ + u8 val = 0; + int rc = 0, i = 0; + u32 tmp; + + if (labibb->pmic_rev_id->pmic_subtype != PM660L_SUBTYPE) + return rc; + + val |= IBB_VREG_OK_EN_OVERLOAD_BLANK; + + rc = of_property_read_u32(of_node, + "qcom,qpnp-ibb-overload-debounce", &tmp); + if (rc < 0) { + pr_err("failed to read qcom,qpnp-ibb-overload-debounce rc=%d\n", + rc); + return rc; + } + + for (i = 0; i < ARRAY_SIZE(ibb_overload_debounce_table); i++) + if (ibb_overload_debounce_table[i] == tmp) + break; + + if (i == ARRAY_SIZE(ibb_overload_debounce_table)) { + pr_err("Invalid value in qcom,qpnp-ibb-overload-debounce\n"); + return -EINVAL; + } + val |= i << IBB_VREG_OK_OVERLOAD_DEB_SHIFT; + + rc = of_property_read_u32(of_node, + "qcom,qpnp-ibb-vreg-ok-debounce", &tmp); + if (rc < 0) { + pr_err("failed to read qcom,qpnp-ibb-vreg-ok-debounce rc=%d\n", + rc); + return rc; + } + + for (i = 0; i < ARRAY_SIZE(ibb_vreg_ok_deb_table); i++) + if (ibb_vreg_ok_deb_table[i] == tmp) + break; + + if (i == ARRAY_SIZE(ibb_vreg_ok_deb_table)) { + pr_err("Invalid value in qcom,qpnp-ibb-vreg-ok-debounce\n"); + return -EINVAL; + } + val |= i; + + rc = qpnp_labibb_write(labibb, labibb->ibb_base + + REG_IBB_VREG_OK_CTL, + &val, 1); + if (rc < 0) + pr_err("write to register %x failed rc = %d\n", + REG_IBB_VREG_OK_CTL, rc); + + return rc; +} + +static int qpnp_ibb_set_default_voltage_v1(struct qpnp_labibb *labibb, + bool use_default) +{ + u8 val; + int rc = 0; + + if (!use_default) { + if (labibb->ibb_vreg.curr_volt < labibb->ibb_vreg.min_volt) { + pr_err("qcom,qpnp-ibb-init-voltage %d is less than the the minimum voltage %d", + labibb->ibb_vreg.curr_volt, labibb->ibb_vreg.min_volt); + return -EINVAL; + } + + val = DIV_ROUND_UP(labibb->ibb_vreg.curr_volt - + labibb->ibb_vreg.min_volt, + labibb->ibb_vreg.step_size); + if (val > IBB_VOLTAGE_SET_MASK) { + pr_err("qcom,qpnp-lab-init-voltage %d is larger than the max supported voltage %ld", + labibb->ibb_vreg.curr_volt, + labibb->ibb_vreg.min_volt + + labibb->ibb_vreg.step_size * + IBB_VOLTAGE_SET_MASK); + return -EINVAL; + } + + labibb->ibb_vreg.curr_volt = val * labibb->ibb_vreg.step_size + + labibb->ibb_vreg.min_volt; + val |= IBB_VOLTAGE_OVERRIDE_EN; + } else { + val = 0; + } + + rc = qpnp_labibb_masked_write(labibb, labibb->ibb_base + + REG_IBB_VOLTAGE, IBB_VOLTAGE_SET_MASK | + IBB_VOLTAGE_OVERRIDE_EN, val); + if (rc < 0) + pr_err("write to register %x failed rc = %d\n", REG_IBB_VOLTAGE, + rc); + + return rc; +} + +static int qpnp_ibb_set_default_voltage_v2(struct qpnp_labibb *labibb, + bool use_default) +{ + int rc = 0; + u8 val; + + val = DIV_ROUND_UP(labibb->ibb_vreg.curr_volt, + labibb->ibb_vreg.step_size); + if (val > IBB_VOLTAGE_SET_MASK) { + pr_err("Invalid qcom,qpnp-ibb-init-voltage property %d", + labibb->ibb_vreg.curr_volt); + return -EINVAL; + } + + labibb->ibb_vreg.curr_volt = val * labibb->ibb_vreg.step_size; + + rc = qpnp_labibb_write(labibb, labibb->ibb_base + + REG_IBB_DEFAULT_VOLTAGE, &val, 1); + if (rc < 0) + pr_err("write to register %x failed rc = %d\n", + REG_IBB_DEFAULT_VOLTAGE, rc); + + return rc; +} + +static int qpnp_ibb_set_voltage_v1(struct qpnp_labibb *labibb, + int min_uV, int max_uV) +{ + int rc, new_uV; + u8 val; + + if (min_uV < labibb->ibb_vreg.min_volt) { + pr_err("min_uV %d is less than min_volt %d", min_uV, + labibb->ibb_vreg.min_volt); + return -EINVAL; + } + + val = DIV_ROUND_UP(min_uV - labibb->ibb_vreg.min_volt, + labibb->ibb_vreg.step_size); + new_uV = val * labibb->ibb_vreg.step_size + labibb->ibb_vreg.min_volt; + + if (new_uV > max_uV) { + pr_err("unable to set voltage %d (min:%d max:%d)\n", new_uV, + min_uV, max_uV); + return -EINVAL; + } + + rc = qpnp_labibb_masked_write(labibb, labibb->ibb_base + + REG_IBB_VOLTAGE, + IBB_VOLTAGE_SET_MASK | + IBB_VOLTAGE_OVERRIDE_EN, + val | IBB_VOLTAGE_OVERRIDE_EN); + + if (rc < 0) { + pr_err("write to register %x failed rc = %d\n", REG_IBB_VOLTAGE, + rc); + return rc; + } + + if (new_uV > labibb->ibb_vreg.curr_volt) { + val = DIV_ROUND_UP(new_uV - labibb->ibb_vreg.curr_volt, + labibb->ibb_vreg.step_size); + udelay(val * labibb->ibb_vreg.slew_rate); + } + labibb->ibb_vreg.curr_volt = new_uV; + + return 0; +} + +static int qpnp_ibb_set_voltage_v2(struct qpnp_labibb *labibb, + int min_uV, int max_uV) +{ + int rc, new_uV; + u8 val; + + val = DIV_ROUND_UP(min_uV, labibb->ibb_vreg.step_size); + new_uV = val * labibb->ibb_vreg.step_size; + + if (new_uV > max_uV) { + pr_err("unable to set voltage %d (min:%d max:%d)\n", new_uV, + min_uV, max_uV); + return -EINVAL; + } + + rc = qpnp_labibb_write(labibb, labibb->ibb_base + + REG_IBB_VOLTAGE, &val, 1); + if (rc < 0) { + pr_err("write to register %x failed rc = %d\n", REG_IBB_VOLTAGE, + rc); + return rc; + } + + if (new_uV > labibb->ibb_vreg.curr_volt) { + val = DIV_ROUND_UP(new_uV - labibb->ibb_vreg.curr_volt, + labibb->ibb_vreg.step_size); + udelay(val * labibb->ibb_vreg.slew_rate); + } + labibb->ibb_vreg.curr_volt = new_uV; + + return 0; +} + +static int qpnp_ibb_output_voltage_at_one_pulse_v1(struct qpnp_labibb *labibb, + u32 volt) +{ + int rc = 0; + u8 val; + + /* + * Set the output voltage 100mV lower as the IBB HW module + * counts one pulse less in SWIRE mode. + */ + val = DIV_ROUND_UP((volt - MIN_OUTPUT_PULSE_VOLTAGE_MV), + OUTPUT_VOLTAGE_STEP_MV) - 1; + rc = qpnp_labibb_masked_write(labibb, labibb->ibb_base + + REG_IBB_SWIRE_CTL, + IBB_OUTPUT_VOLTAGE_AT_ONE_PULSE_MASK, + val); + if (rc < 0) + pr_err("write register %x failed rc = %d\n", + REG_IBB_SWIRE_CTL, rc); + + return rc; +} + +static int qpnp_ibb_output_voltage_at_one_pulse_v2(struct qpnp_labibb *labibb, + u32 volt) +{ + int rc = 0; + u8 val; + + val = DIV_ROUND_UP(volt, OUTPUT_VOLTAGE_STEP_MV); + + rc = qpnp_labibb_masked_write(labibb, labibb->ibb_base + + REG_IBB_SWIRE_CTL, + IBB_OUTPUT_VOLTAGE_AT_ONE_PULSE_MASK, + val); + if (rc < 0) + pr_err("qpnp_labiibb_write register %x failed rc = %d\n", + REG_IBB_SWIRE_CTL, rc); + + return rc; +} + +static const struct ibb_ver_ops ibb_ops_v1 = { + .set_default_voltage = qpnp_ibb_set_default_voltage_v1, + .set_voltage = qpnp_ibb_set_voltage_v1, + .sel_mode = qpnp_labibb_sel_mode_v1, + .get_mode = qpnp_ibb_get_mode_v1, + .set_clk_div = qpnp_ibb_set_clk_div_v1, + .smart_ps_config = qpnp_ibb_smart_ps_config_v1, + .soft_start_ctl = qpnp_ibb_soft_start_ctl_v1, + .voltage_at_one_pulse = qpnp_ibb_output_voltage_at_one_pulse_v1, +}; + +static const struct ibb_ver_ops ibb_ops_v2 = { + .set_default_voltage = qpnp_ibb_set_default_voltage_v2, + .set_voltage = qpnp_ibb_set_voltage_v2, + .sel_mode = qpnp_labibb_sel_mode_v2, + .get_mode = qpnp_ibb_get_mode_v2, + .set_clk_div = qpnp_ibb_set_clk_div_v2, + .smart_ps_config = qpnp_ibb_smart_ps_config_v2, + .soft_start_ctl = qpnp_ibb_soft_start_ctl_v2, + .voltage_at_one_pulse = qpnp_ibb_output_voltage_at_one_pulse_v2, +}; + +static int qpnp_lab_set_default_voltage_v1(struct qpnp_labibb *labibb, + bool default_pres) +{ + u8 val; + int rc = 0; + + if (!default_pres) { + if (labibb->lab_vreg.curr_volt < labibb->lab_vreg.min_volt) { + pr_err("qcom,qpnp-lab-init-voltage %d is less than the the minimum voltage %d", + labibb->lab_vreg.curr_volt, + labibb->lab_vreg.min_volt); + return -EINVAL; + } + + val = DIV_ROUND_UP(labibb->lab_vreg.curr_volt - + labibb->lab_vreg.min_volt, + labibb->lab_vreg.step_size); + if (val > LAB_VOLTAGE_SET_MASK) { + pr_err("qcom,qpnp-lab-init-voltage %d is larger than the max supported voltage %ld", + labibb->lab_vreg.curr_volt, + labibb->lab_vreg.min_volt + + labibb->lab_vreg.step_size * + LAB_VOLTAGE_SET_MASK); + return -EINVAL; + } + + labibb->lab_vreg.curr_volt = val * labibb->lab_vreg.step_size + + labibb->lab_vreg.min_volt; + val |= LAB_VOLTAGE_OVERRIDE_EN; + + } else { + val = 0; + } + + rc = qpnp_labibb_masked_write(labibb, labibb->lab_base + + REG_LAB_VOLTAGE, LAB_VOLTAGE_SET_MASK | + LAB_VOLTAGE_OVERRIDE_EN, val); + + if (rc < 0) + pr_err("write to register %x failed rc = %d\n", REG_LAB_VOLTAGE, + rc); + + return rc; +} + +static int qpnp_lab_set_default_voltage_v2(struct qpnp_labibb *labibb, + bool default_pres) +{ + int rc = 0; + u8 val; + + val = DIV_ROUND_UP((labibb->lab_vreg.curr_volt + - labibb->lab_vreg.min_volt), labibb->lab_vreg.step_size); + + rc = qpnp_labibb_write(labibb, labibb->lab_base + + REG_LAB_VOUT_DEFAULT, &val, 1); + if (rc < 0) + pr_err("write to register %x failed rc = %d\n", + REG_LAB_VOUT_DEFAULT, rc); + + return rc; +} + +static int qpnp_lab_ps_ctl_v1(struct qpnp_labibb *labibb, + u32 thresh, bool enable) +{ + int rc = 0; + u8 val; + + if (enable) { + for (val = 0; val < ARRAY_SIZE(lab_ps_thresh_table_v1); val++) + if (lab_ps_thresh_table_v1[val] == thresh) + break; + + if (val == ARRAY_SIZE(lab_ps_thresh_table_v1)) { + pr_err("Invalid value in qcom,qpnp-lab-ps-threshold\n"); + return -EINVAL; + } + + val |= LAB_PS_CTL_EN; + } else { + val = 0; + } + + rc = qpnp_labibb_write(labibb, labibb->lab_base + + REG_LAB_PS_CTL, &val, 1); + + if (rc < 0) + pr_err("write register %x failed rc = %d\n", + REG_LAB_PS_CTL, rc); + + return rc; +} + +static int qpnp_lab_ps_ctl_v2(struct qpnp_labibb *labibb, + u32 thresh, bool enable) +{ + int rc = 0; + u8 val; + + if (enable) { + for (val = 0; val < ARRAY_SIZE(lab_ps_thresh_table_v2); val++) + if (lab_ps_thresh_table_v2[val] == thresh) + break; + + if (val == ARRAY_SIZE(lab_ps_thresh_table_v2)) { + pr_err("Invalid value in qcom,qpnp-lab-ps-threshold\n"); + return -EINVAL; + } + + val |= LAB_PS_CTL_EN; + } else { + val = 0; + } + + rc = qpnp_labibb_write(labibb, labibb->lab_base + + REG_LAB_PS_CTL, &val, 1); + + if (rc < 0) + pr_err("write register %x failed rc = %d\n", + REG_LAB_PS_CTL, rc); + + return rc; +} + +static const struct lab_ver_ops lab_ops_v1 = { + .set_default_voltage = qpnp_lab_set_default_voltage_v1, + .ps_ctl = qpnp_lab_ps_ctl_v1, +}; + +static const struct lab_ver_ops lab_ops_v2 = { + .set_default_voltage = qpnp_lab_set_default_voltage_v2, + .ps_ctl = qpnp_lab_ps_ctl_v2, +}; + static int qpnp_labibb_get_matching_idx(const char *val) { int i; - for (i = 0; i < ARRAY_SIZE(lab_current_sense_plan); i++) - if (!strcmp(lab_current_sense_plan[i], val)) + for (i = 0; i < ARRAY_SIZE(lab_current_sense_table); i++) + if (!strcmp(lab_current_sense_table[i], val)) return i; return -EINVAL; @@ -677,7 +1417,7 @@ static int qpnp_ibb_set_mode(struct qpnp_labibb *labibb, enum ibb_mode mode) rc = qpnp_labibb_masked_write(labibb, labibb->ibb_base + REG_IBB_ENABLE_CTL, IBB_ENABLE_CTL_MASK, val); - if (rc) + if (rc < 0) pr_err("Unable to configure IBB_ENABLE_CTL rc=%d\n", rc); return rc; @@ -688,21 +1428,21 @@ static int qpnp_ibb_ps_config(struct qpnp_labibb *labibb, bool enable) u8 val; int rc; - val = enable ? IBB_PS_CTL_EN : IBB_PS_CTL_DISABLE; + val = enable ? IBB_PS_CTL_EN : IBB_NUM_SWIRE_PULSE_WAIT; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_PS_CTL, - &val, 1); - if (rc) { - pr_err("qpnp_ibb_ps_config write register %x failed rc = %d\n", - REG_IBB_PS_CTL, rc); + &val, 1); + if (rc < 0) { + pr_err("write register %x failed rc = %d\n", + REG_IBB_PS_CTL, rc); return rc; } - val = enable ? IBB_NLIMIT_DAC_EN : IBB_NLIMIT_DAC_DISABLE; + val = enable ? 0 : IBB_DEFAULT_NLIMIT_DAC; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_NLIMIT_DAC, - &val, 1); - if (rc) - pr_err("qpnp_ibb_ps_config write register %x failed rc = %d\n", - REG_IBB_NLIMIT_DAC, rc); + &val, 1); + if (rc < 0) + pr_err("write register %x failed rc = %d\n", + REG_IBB_NLIMIT_DAC, rc); return rc; } @@ -710,7 +1450,7 @@ static int qpnp_lab_dt_init(struct qpnp_labibb *labibb, struct device_node *of_node) { int rc = 0; - u8 i, val; + u8 i, val, mask; u32 tmp; /* @@ -718,234 +1458,242 @@ static int qpnp_lab_dt_init(struct qpnp_labibb *labibb, * GPIO selector. */ if (labibb->pmic_rev_id->pmic_subtype != PMI8998_SUBTYPE) { - if (labibb->mode == QPNP_LABIBB_LCD_MODE) - val = REG_LAB_IBB_LCD_MODE; - else - val = REG_LAB_IBB_AMOLED_MODE; - - rc = qpnp_labibb_sec_write(labibb, labibb->lab_base, - REG_LAB_LCD_AMOLED_SEL, &val, 1); - - if (rc) { - pr_err("qpnp_lab_sec_write register %x failed rc = %d\n", - REG_LAB_LCD_AMOLED_SEL, rc); + rc = labibb->ibb_ver_ops->sel_mode(labibb, 0); + if (rc < 0) return rc; - } } val = 0; - if (of_property_read_bool(of_node, "qcom,qpnp-lab-full-pull-down")) val |= LAB_PD_CTL_STRONG_PULL; if (!of_property_read_bool(of_node, "qcom,qpnp-lab-pull-down-enable")) val |= LAB_PD_CTL_DISABLE_PD; - rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_PD_CTL, - &val, 1); + mask = LAB_PD_CTL_EN_MASK | LAB_PD_CTL_STRENGTH_MASK; + rc = qpnp_labibb_masked_write(labibb, labibb->lab_base + REG_LAB_PD_CTL, + mask, val); - if (rc) { - pr_err("qpnp_lab_dt_init write register %x failed rc = %d\n", + if (rc < 0) { + pr_err("write to register %x failed rc = %d\n", REG_LAB_PD_CTL, rc); return rc; } rc = of_property_read_u32(of_node, - "qcom,qpnp-lab-switching-clock-frequency", &tmp); - if (rc) { - pr_err("get qcom,qpnp-lab-switching-clock-frequency failed rc = %d\n", - rc); - return rc; - } - - for (val = 0; val < ARRAY_SIZE(lab_clk_div_plan); val++) - if (lab_clk_div_plan[val] == tmp) - break; + "qcom,qpnp-lab-switching-clock-frequency", &tmp); + if (!rc) { + for (val = 0; val < ARRAY_SIZE(lab_clk_div_table); val++) + if (lab_clk_div_table[val] == tmp) + break; - if (val == ARRAY_SIZE(lab_clk_div_plan)) { - pr_err("Invalid property in qpnp-lab-switching-clock-frequency\n"); - return -EINVAL; - } + if (val == ARRAY_SIZE(lab_clk_div_table)) { + pr_err("Invalid value in qpnp-lab-switching-clock-frequency\n"); + return -EINVAL; + } - rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_CLK_DIV, - &val, 1); - if (rc) { - pr_err("qpnp_lab_dt_init write register %x failed rc = %d\n", - REG_LAB_CLK_DIV, rc); - return rc; + rc = qpnp_labibb_write(labibb, labibb->lab_base + + REG_LAB_CLK_DIV, &val, 1); + if (rc < 0) { + pr_err("write to register %x failed rc = %d\n", + REG_LAB_CLK_DIV, rc); + return rc; + } } - rc = of_property_read_u32(of_node, - "qcom,qpnp-lab-limit-maximum-current", &tmp); + if (of_property_read_bool(of_node, + "qcom,qpnp-lab-limit-max-current-enable")) { + val = LAB_CURRENT_LIMIT_EN_BIT; - if (rc) { - pr_err("get qcom,qpnp-lab-limit-maximum-current failed rc = %d\n", - rc); - return rc; - } + rc = of_property_read_u32(of_node, + "qcom,qpnp-lab-limit-maximum-current", &tmp); - for (val = 0; val < ARRAY_SIZE(lab_current_limit_plan); val++) - if (lab_current_limit_plan[val] == tmp) - break; + if (rc < 0) { + pr_err("get qcom,qpnp-lab-limit-maximum-current failed rc = %d\n", + rc); + return rc; + } - if (val == ARRAY_SIZE(lab_current_limit_plan)) { - pr_err("Invalid property in qcom,qpnp-lab-limit-maximum-current\n"); - return -EINVAL; - } + for (i = 0; i < ARRAY_SIZE(lab_current_limit_table); i++) + if (lab_current_limit_table[i] == tmp) + break; - if (of_property_read_bool(of_node, - "qcom,qpnp-lab-limit-max-current-enable")) - val |= LAB_CURRENT_LIMIT_EN_BIT; + if (i == ARRAY_SIZE(lab_current_limit_table)) { + pr_err("Invalid value in qcom,qpnp-lab-limit-maximum-current\n"); + return -EINVAL; + } - rc = qpnp_labibb_write(labibb, labibb->lab_base + - REG_LAB_CURRENT_LIMIT, &val, 1); - if (rc) { - pr_err("qpnp_lab_dt_init write register %x failed rc = %d\n", - REG_LAB_CURRENT_LIMIT, rc); - return rc; + val |= i; + rc = qpnp_labibb_write(labibb, labibb->lab_base + + REG_LAB_CURRENT_LIMIT, &val, 1); + if (rc < 0) { + pr_err("write to register %x failed rc = %d\n", + REG_LAB_CURRENT_LIMIT, rc); + return rc; + } } if (of_property_read_bool(of_node, "qcom,qpnp-lab-ring-suppression-enable")) { val = LAB_RING_SUPPRESSION_CTL_EN; rc = qpnp_labibb_write(labibb, labibb->lab_base + - REG_LAB_RING_SUPPRESSION_CTL, - &val, - 1); - if (rc) { - pr_err("qpnp_lab_dt_init write register %x failed rc = %d\n", + REG_LAB_RING_SUPPRESSION_CTL, &val, 1); + if (rc < 0) { + pr_err("write to register %x failed rc = %d\n", REG_LAB_RING_SUPPRESSION_CTL, rc); return rc; } } - rc = of_property_read_u32(of_node, "qcom,qpnp-lab-ps-threshold", &tmp); + if (of_property_read_bool(of_node, "qcom,qpnp-lab-ps-enable")) { - if (rc) { - pr_err("get qcom,qpnp-lab-ps-threshold failed rc = %d\n", - rc); - return rc; + rc = of_property_read_u32(of_node, + "qcom,qpnp-lab-ps-threshold", &tmp); + + if (rc < 0) { + pr_err("get qcom,qpnp-lab-ps-threshold failed rc = %d\n", + rc); + return rc; + } + rc = labibb->lab_ver_ops->ps_ctl(labibb, tmp, true); + if (rc < 0) + return rc; + } else { + rc = labibb->lab_ver_ops->ps_ctl(labibb, tmp, false); + if (rc < 0) + return rc; } - for (val = 0; val < ARRAY_SIZE(lab_ps_threshold_plan); val++) - if (lab_ps_threshold_plan[val] == tmp) - break; + val = 0; + mask = 0; + rc = of_property_read_u32(of_node, "qcom,qpnp-lab-pfet-size", &tmp); + if (!rc) { + for (val = 0; val < ARRAY_SIZE(lab_rdson_pfet_table); val++) + if (tmp == lab_rdson_pfet_table[val]) + break; - if (val == ARRAY_SIZE(lab_ps_threshold_plan)) { - pr_err("Invalid property in qcom,qpnp-lab-ps-threshold\n"); - return -EINVAL; + if (val == ARRAY_SIZE(lab_rdson_pfet_table)) { + pr_err("Invalid value in qcom,qpnp-lab-pfet-size\n"); + return -EINVAL; + } + val |= LAB_RDSON_MNGMNT_PFET_SLEW_EN; + mask |= LAB_RDSON_MNGMNT_PFET_MASK | + LAB_RDSON_MNGMNT_PFET_SLEW_EN; } - if (of_property_read_bool(of_node, "qcom,qpnp-lab-ps-enable")) - val |= LAB_PS_CTL_EN; + rc = of_property_read_u32(of_node, "qcom,qpnp-lab-nfet-size", + &tmp); + if (!rc) { + for (i = 0; i < ARRAY_SIZE(lab_rdson_nfet_table); i++) + if (tmp == lab_rdson_nfet_table[i]) + break; - rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_PS_CTL, - &val, 1); + if (i == ARRAY_SIZE(lab_rdson_nfet_table)) { + pr_err("Invalid value in qcom,qpnp-lab-nfet-size\n"); + return -EINVAL; + } - if (rc) { - pr_err("qpnp_lab_dt_init write register %x failed rc = %d\n", - REG_LAB_PS_CTL, rc); - return rc; + val |= i << LAB_RDSON_MNGMNT_NFET_SHIFT; + val |= LAB_RDSON_MNGMNT_NFET_SLEW_EN; + mask |= LAB_RDSON_MNGMNT_NFET_MASK | + LAB_RDSON_MNGMNT_NFET_SLEW_EN; } - rc = of_property_read_u32(of_node, "qcom,qpnp-lab-pfet-size", &tmp); - - if (rc) { - pr_err("get qcom,qpnp-lab-pfet-size, rc = %d\n", rc); + rc = qpnp_labibb_masked_write(labibb, labibb->lab_base + + REG_LAB_RDSON_MNGMNT, mask, val); + if (rc < 0) { + pr_err("write to register %x failed rc = %d\n", + REG_LAB_RDSON_MNGMNT, rc); return rc; } - for (val = 0; val < ARRAY_SIZE(lab_rdson_pfet_plan); val++) - if (tmp == lab_rdson_pfet_plan[val]) - break; - - if (val == ARRAY_SIZE(lab_rdson_pfet_plan)) { - pr_err("Invalid property in qcom,qpnp-lab-pfet-size\n"); - return -EINVAL; + rc = of_property_read_u32(of_node, "qcom,qpnp-lab-init-voltage", + &(labibb->lab_vreg.curr_volt)); + if (rc < 0) { + pr_err("get qcom,qpnp-lab-init-voltage failed, rc = %d\n", + rc); + return rc; } - rc = of_property_read_u32(of_node, "qcom,qpnp-lab-nfet-size", &tmp); + if (of_property_read_bool(of_node, + "qcom,qpnp-lab-use-default-voltage")) + rc = labibb->lab_ver_ops->set_default_voltage(labibb, true); + else + rc = labibb->lab_ver_ops->set_default_voltage(labibb, false); - if (rc) { - pr_err("get qcom,qpnp-lab-nfet-size, rc = %d\n", rc); + if (rc < 0) return rc; - } - for (i = 0; i < ARRAY_SIZE(lab_rdson_nfet_plan); i++) - if (tmp == lab_rdson_nfet_plan[i]) - break; + if (of_property_read_bool(of_node, + "qcom,qpnp-lab-enable-sw-high-psrr")) { + val = LAB_EN_SW_HIGH_PSRR_MODE; - if (i == ARRAY_SIZE(lab_rdson_nfet_plan)) { - pr_err("Iniid property in qcom,qpnp-lab-nfet-size\n"); - return -EINVAL; + rc = qpnp_labibb_write(labibb, labibb->lab_base + + REG_LAB_SW_HIGH_PSRR_CTL, &val, 1); + if (rc < 0) { + pr_err("write to register %x failed rc = %d\n", + REG_LAB_SW_HIGH_PSRR_CTL, rc); + return rc; + } } - val |= i << LAB_RDSON_MNGMNT_NFET_SHIFT; - val |= (LAB_RDSON_MNGMNT_NFET_SLEW_EN | LAB_RDSON_MNGMNT_PFET_SLEW_EN); - - rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_RDSON_MNGMNT, - &val, 1); - if (rc) { - pr_err("qpnp_lab_dt_init write register %x failed rc = %d\n", - REG_LAB_RDSON_MNGMNT, rc); - return rc; + rc = of_property_read_u32(of_node, + "qcom,qpnp-lab-ldo-pulldown-enable", (u32 *)&val); + if (!rc) { + rc = qpnp_labibb_write(labibb, labibb->lab_base + + REG_LAB_LDO_PD_CTL, &val, 1); + if (rc < 0) { + pr_err("write to register %x failed rc = %d\n", + REG_LAB_LDO_PD_CTL, rc); + return rc; + } } - rc = of_property_read_u32(of_node, "qcom,qpnp-lab-init-voltage", - &(labibb->lab_vreg.curr_volt)); - if (rc) { - pr_err("get qcom,qpnp-lab-init-voltage failed, rc = %d\n", rc); - return rc; - } + rc = of_property_read_u32(of_node, + "qcom,qpnp-lab-high-psrr-src-select", &tmp); + if (!rc) { + val = tmp; - if (!of_property_read_bool(of_node, - "qcom,qpnp-lab-use-default-voltage")) { - if (labibb->lab_vreg.curr_volt < labibb->lab_vreg.min_volt) { - pr_err("Invalid qcom,qpnp-lab-init-voltage property, qcom,qpnp-lab-init-voltage %d is less than the the minimum voltage %d", - labibb->lab_vreg.curr_volt, - labibb->lab_vreg.min_volt); - return -EINVAL; + rc = of_property_read_u32(of_node, + "qcom,qpnp-lab-vref-high-psrr-select", &tmp); + if (rc < 0) { + pr_err("get qcom,qpnp-lab-vref-high-psrr-select failed rc = %d\n", + rc); + return rc; } - val = DIV_ROUND_UP(labibb->lab_vreg.curr_volt - - labibb->lab_vreg.min_volt, - labibb->lab_vreg.step_size); + for (i = 0; i < ARRAY_SIZE(lab_vref_high_psrr_table); i++) + if (lab_vref_high_psrr_table[i] == tmp) + break; - if (val > LAB_VOLTAGE_SET_MASK) { - pr_err("Invalid qcom,qpnp-lab-init-voltage property, qcom,qpnp-lab-init-voltage %d is larger than the max supported voltage %d", - labibb->lab_vreg.curr_volt, - labibb->lab_vreg.min_volt + - labibb->lab_vreg.step_size * - LAB_VOLTAGE_SET_MASK); + if (i == ARRAY_SIZE(lab_vref_high_psrr_table)) { + pr_err("Invalid value in qpnp-lab-vref-high-psrr-selct\n"); return -EINVAL; } + val |= (i << LAB_SEL_HW_HIGH_PSRR_SRC_SHIFT); - labibb->lab_vreg.curr_volt = val * labibb->lab_vreg.step_size + - labibb->lab_vreg.min_volt; - val |= LAB_VOLTAGE_OVERRIDE_EN; - } else { - val = 0; - } - - rc = qpnp_labibb_masked_write(labibb, labibb->lab_base + - REG_LAB_VOLTAGE, - LAB_VOLTAGE_SET_MASK | - LAB_VOLTAGE_OVERRIDE_EN, + rc = qpnp_labibb_masked_write(labibb, labibb->lab_base + + REG_LAB_VPH_ENVELOP_CTL, + LAB_VREF_HIGH_PSRR_SEL_MASK | + LAB_SEL_HW_HIGH_PSRR_SRC_MASK, val); - if (rc) { - pr_err("write to register %x failed rc = %d\n", REG_LAB_VOLTAGE, - rc); - return rc; + if (rc < 0) { + pr_err("write to register %x failed rc = %d\n", + REG_LAB_VPH_ENVELOP_CTL, rc); + return rc; + } } if (labibb->swire_control) { rc = qpnp_ibb_set_mode(labibb, IBB_HW_CONTROL); - if (rc) + if (rc < 0) { pr_err("Unable to set SWIRE_RDY rc=%d\n", rc); + return rc; + } } - return rc; + return 0; } #define LAB_CURRENT_MAX_1600MA 0x7 @@ -1038,14 +1786,14 @@ static int qpnp_labibb_restore_settings(struct qpnp_labibb *labibb) if (ibb_settings[i].sec_access) rc = qpnp_labibb_sec_write(labibb, labibb->ibb_base, ibb_settings[i].address, - &ibb_settings[i].value, 1); + ibb_settings[i].value); else rc = qpnp_labibb_write(labibb, labibb->ibb_base + ibb_settings[i].address, &ibb_settings[i].value, 1); - if (rc) { - pr_err("qpnp_labibb_write register %x failed rc = %d\n", + if (rc < 0) { + pr_err("write to register %x failed rc = %d\n", ibb_settings[i].address, rc); return rc; } @@ -1055,14 +1803,14 @@ static int qpnp_labibb_restore_settings(struct qpnp_labibb *labibb) if (lab_settings[i].sec_access) rc = qpnp_labibb_sec_write(labibb, labibb->lab_base, lab_settings[i].address, - &lab_settings[i].value, 1); + lab_settings[i].value); else rc = qpnp_labibb_write(labibb, labibb->lab_base + lab_settings[i].address, &lab_settings[i].value, 1); - if (rc) { - pr_err("qpnp_labibb_write register %x failed rc = %d\n", + if (rc < 0) { + pr_err("write to register %x failed rc = %d\n", lab_settings[i].address, rc); return rc; } @@ -1076,22 +1824,20 @@ static int qpnp_labibb_save_settings(struct qpnp_labibb *labibb) int rc, i; for (i = 0; i < ARRAY_SIZE(ibb_settings); i++) { - rc = qpnp_labibb_read(labibb, &ibb_settings[i].value, - labibb->ibb_base + - ibb_settings[i].address, 1); - if (rc) { - pr_err("qpnp_labibb_read register %x failed rc = %d\n", + rc = qpnp_labibb_read(labibb, labibb->ibb_base + + ibb_settings[i].address, &ibb_settings[i].value, 1); + if (rc < 0) { + pr_err("read register %x failed rc = %d\n", ibb_settings[i].address, rc); return rc; } } for (i = 0; i < ARRAY_SIZE(lab_settings); i++) { - rc = qpnp_labibb_read(labibb, &lab_settings[i].value, - labibb->lab_base + - lab_settings[i].address, 1); - if (rc) { - pr_err("qpnp_labibb_read register %x failed rc = %d\n", + rc = qpnp_labibb_read(labibb, labibb->lab_base + + lab_settings[i].address, &lab_settings[i].value, 1); + if (rc < 0) { + pr_err("read register %x failed rc = %d\n", lab_settings[i].address, rc); return rc; } @@ -1108,17 +1854,17 @@ static int qpnp_labibb_ttw_enter_ibb_common(struct qpnp_labibb *labibb) val = 0; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_PD_CTL, &val, 1); - if (rc) { - pr_err("qpnp_labibb_read register %x failed rc = %d\n", + if (rc < 0) { + pr_err("read register %x failed rc = %d\n", REG_IBB_PD_CTL, rc); return rc; } val = 0; rc = qpnp_labibb_sec_write(labibb, labibb->ibb_base, - REG_IBB_PWRUP_PWRDN_CTL_1, &val, 1); - if (rc) { - pr_err("qpnp_labibb_write register %x failed rc = %d\n", + REG_IBB_PWRUP_PWRDN_CTL_1, val); + if (rc < 0) { + pr_err("write to register %x failed rc = %d\n", REG_IBB_PWRUP_PWRDN_CTL_1, rc); return rc; } @@ -1127,8 +1873,8 @@ static int qpnp_labibb_ttw_enter_ibb_common(struct qpnp_labibb *labibb) rc = qpnp_labibb_sec_masked_write(labibb, labibb->ibb_base, REG_IBB_PWRUP_PWRDN_CTL_2, IBB_DIS_DLY_MASK | IBB_WAIT_MBG_OK, val); - if (rc) { - pr_err("qpnp_labibb_sec_write register %x failed rc = %d\n", + if (rc < 0) { + pr_err("write to register %x failed rc = %d\n", REG_IBB_PWRUP_PWRDN_CTL_2, rc); return rc; } @@ -1137,8 +1883,8 @@ static int qpnp_labibb_ttw_enter_ibb_common(struct qpnp_labibb *labibb) IBB_OVERRIDE_PFET_SW_SIZE; rc = qpnp_labibb_masked_write(labibb, labibb->ibb_base + REG_IBB_RDSON_MNGMNT, 0xFF, val); - if (rc) { - pr_err("qpnp_labibb_write register %x failed rc = %d\n", + if (rc < 0) { + pr_err("write to register %x failed rc = %d\n", REG_IBB_RDSON_MNGMNT, rc); return rc; } @@ -1146,9 +1892,9 @@ static int qpnp_labibb_ttw_enter_ibb_common(struct qpnp_labibb *labibb) val = IBB_CURRENT_LIMIT_EN | IBB_CURRENT_MAX_500MA | (IBB_ILIMIT_COUNT_CYC8 << IBB_CURRENT_LIMIT_DEBOUNCE_SHIFT); rc = qpnp_labibb_sec_write(labibb, labibb->ibb_base, - REG_IBB_CURRENT_LIMIT, &val, 1); - if (rc) - pr_err("qpnp_labibb_write register %x failed rc = %d\n", + REG_IBB_CURRENT_LIMIT, val); + if (rc < 0) + pr_err("write to register %x failed rc = %d\n", REG_IBB_CURRENT_LIMIT, rc); return rc; @@ -1162,8 +1908,8 @@ static int qpnp_labibb_ttw_enter_ibb_pmi8996(struct qpnp_labibb *labibb) val = IBB_BYPASS_PWRDN_DLY2_BIT | IBB_FAST_STARTUP; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_SPARE_CTL, &val, 1); - if (rc) - pr_err("qpnp_labibb_write register %x failed rc = %d\n", + if (rc < 0) + pr_err("write to register %x failed rc = %d\n", REG_IBB_SPARE_CTL, rc); return rc; @@ -1175,7 +1921,7 @@ static int qpnp_labibb_ttw_enter_ibb_pmi8950(struct qpnp_labibb *labibb) u8 val; rc = qpnp_ibb_ps_config(labibb, true); - if (rc) { + if (rc < 0) { pr_err("Failed to enable ibb_ps_config rc=%d\n", rc); return rc; } @@ -1183,8 +1929,8 @@ static int qpnp_labibb_ttw_enter_ibb_pmi8950(struct qpnp_labibb *labibb) val = IBB_SOFT_START_CHARGING_RESISTOR_16K; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_SOFT_START_CTL, &val, 1); - if (rc) { - pr_err("qpnp_labibb_write register %x failed rc = %d\n", + if (rc < 0) { + pr_err("write to register %x failed rc = %d\n", REG_IBB_SOFT_START_CTL, rc); return rc; } @@ -1192,8 +1938,8 @@ static int qpnp_labibb_ttw_enter_ibb_pmi8950(struct qpnp_labibb *labibb) val = IBB_MODULE_RDY_EN; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_IBB_MODULE_RDY, &val, 1); - if (rc) - pr_err("qpnp_labibb_write register %x failed rc = %d\n", + if (rc < 0) + pr_err("write to register %x failed rc = %d\n", REG_IBB_MODULE_RDY, rc); return rc; @@ -1218,8 +1964,8 @@ static int qpnp_labibb_regulator_ttw_mode_enter(struct qpnp_labibb *labibb) val = LAB_MODULE_RDY_EN; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_MODULE_RDY, &val, 1); - if (rc) { - pr_err("qpnp_labibb_write register %x failed rc = %d\n", + if (rc < 0) { + pr_err("write to register %x failed rc = %d\n", REG_LAB_MODULE_RDY, rc); return rc; } @@ -1228,8 +1974,8 @@ static int qpnp_labibb_regulator_ttw_mode_enter(struct qpnp_labibb *labibb) val = LAB_ENABLE_CTL_EN; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_ENABLE_CTL, &val, 1); - if (rc) { - pr_err("qpnp_labibb_write register %x failed rc = %d\n", + if (rc < 0) { + pr_err("write to register %x failed rc = %d\n", REG_LAB_ENABLE_CTL, rc); return rc; } @@ -1240,15 +1986,15 @@ static int qpnp_labibb_regulator_ttw_mode_enter(struct qpnp_labibb *labibb) LAB_RDSON_PFET_SW_SIZE_QUARTER; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_RDSON_MNGMNT, &val, 1); - if (rc) { - pr_err("qpnp_labibb_write register %x failed rc = %d\n", + if (rc < 0) { + pr_err("write to register %x failed rc = %d\n", REG_LAB_RDSON_MNGMNT, rc); return rc; } rc = qpnp_labibb_masked_write(labibb, labibb->lab_base + REG_LAB_PS_CTL, LAB_PS_CTL_EN, LAB_PS_CTL_EN); - if (rc) { + if (rc < 0) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_PS_CTL, rc); return rc; @@ -1257,7 +2003,7 @@ static int qpnp_labibb_regulator_ttw_mode_enter(struct qpnp_labibb *labibb) val = LAB_PD_CTL_DISABLE_PD; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_PD_CTL, &val, 1); - if (rc) { + if (rc < 0) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_PD_CTL, rc); return rc; @@ -1268,7 +2014,7 @@ static int qpnp_labibb_regulator_ttw_mode_enter(struct qpnp_labibb *labibb) val |= LAB_SPARE_TOUCH_WAKE_BIT; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_SPARE_CTL, &val, 1); - if (rc) { + if (rc < 0) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_SPARE_CTL, rc); return rc; @@ -1277,7 +2023,7 @@ static int qpnp_labibb_regulator_ttw_mode_enter(struct qpnp_labibb *labibb) val = 0; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_SOFT_START_CTL, &val, 1); - if (rc) { + if (rc < 0) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_SOFT_START_CTL, rc); return rc; @@ -1298,13 +2044,13 @@ static int qpnp_labibb_regulator_ttw_mode_enter(struct qpnp_labibb *labibb) rc = qpnp_labibb_ttw_enter_ibb_pmi8950(labibb); break; } - if (rc) { + if (rc < 0) { pr_err("Failed to configure TTW-enter for IBB rc=%d\n", rc); return rc; } rc = qpnp_ibb_set_mode(labibb, IBB_HW_CONTROL); - if (rc) { + if (rc < 0) { pr_err("Unable to set SWIRE_RDY rc = %d\n", rc); return rc; } @@ -1320,7 +2066,7 @@ static int qpnp_labibb_ttw_exit_ibb_common(struct qpnp_labibb *labibb) val = IBB_FASTER_PFET_OFF; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_SPARE_CTL, &val, 1); - if (rc) + if (rc < 0) pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_IBB_SPARE_CTL, rc); @@ -1339,7 +2085,7 @@ static int qpnp_labibb_regulator_ttw_mode_exit(struct qpnp_labibb *labibb) /* Restore the IBB settings back to switch back to normal mode */ rc = qpnp_labibb_restore_settings(labibb); - if (rc) { + if (rc < 0) { pr_err("Error in restoring IBB setttings, rc=%d\n", rc); return rc; } @@ -1348,7 +2094,7 @@ static int qpnp_labibb_regulator_ttw_mode_exit(struct qpnp_labibb *labibb) val = 0; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_ENABLE_CTL, &val, 1); - if (rc) { + if (rc < 0) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_ENABLE_CTL, rc); return rc; @@ -1357,7 +2103,7 @@ static int qpnp_labibb_regulator_ttw_mode_exit(struct qpnp_labibb *labibb) val = LAB_PD_CTL_STRONG_PULL; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_PD_CTL, &val, 1); - if (rc) { + if (rc < 0) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_PD_CTL, rc); return rc; @@ -1366,7 +2112,7 @@ static int qpnp_labibb_regulator_ttw_mode_exit(struct qpnp_labibb *labibb) val = 0; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_SPARE_CTL, &val, 1); - if (rc) { + if (rc < 0) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_SPARE_CTL, rc); return rc; @@ -1380,7 +2126,7 @@ static int qpnp_labibb_regulator_ttw_mode_exit(struct qpnp_labibb *labibb) rc = qpnp_labibb_ttw_exit_ibb_common(labibb); break; } - if (rc) { + if (rc < 0) { pr_err("Failed to configure TTW-exit for IBB rc=%d\n", rc); return rc; } @@ -1418,9 +2164,9 @@ static int qpnp_labibb_regulator_enable(struct qpnp_labibb *labibb) usleep_range(dly, dly + 100); /* after this delay, lab should be enabled */ - rc = qpnp_labibb_read(labibb, &val, - labibb->lab_base + REG_LAB_STATUS1, 1); - if (rc) { + rc = qpnp_labibb_read(labibb, labibb->lab_base + REG_LAB_STATUS1, + &val, 1); + if (rc < 0) { pr_err("read register %x failed rc = %d\n", REG_LAB_STATUS1, rc); goto err_out; @@ -1439,9 +2185,9 @@ static int qpnp_labibb_regulator_enable(struct qpnp_labibb *labibb) dly = labibb->ibb_vreg.soft_start + labibb->ibb_vreg.pwrup_dly; retries = 10; while (retries--) { - rc = qpnp_labibb_read(labibb, &val, - labibb->ibb_base + REG_IBB_STATUS1, 1); - if (rc) { + rc = qpnp_labibb_read(labibb, labibb->ibb_base + + REG_IBB_STATUS1, &val, 1); + if (rc < 0) { pr_err("read register %x failed rc = %d\n", REG_IBB_STATUS1, rc); goto err_out; @@ -1465,7 +2211,7 @@ static int qpnp_labibb_regulator_enable(struct qpnp_labibb *labibb) return 0; err_out: rc = qpnp_ibb_set_mode(labibb, IBB_SW_CONTROL_DIS); - if (rc) { + if (rc < 0) { pr_err("Unable to set IBB_MODULE_EN rc = %d\n", rc); return rc; } @@ -1490,7 +2236,7 @@ static int qpnp_labibb_regulator_disable(struct qpnp_labibb *labibb) */ if (labibb->ttw_en && !labibb->in_ttw_mode) { rc = qpnp_labibb_regulator_ttw_mode_enter(labibb); - if (rc) { + if (rc < 0) { pr_err("Error in entering TTW mode rc = %d\n", rc); return rc; } @@ -1500,7 +2246,7 @@ static int qpnp_labibb_regulator_disable(struct qpnp_labibb *labibb) } rc = qpnp_ibb_set_mode(labibb, IBB_SW_CONTROL_DIS); - if (rc) { + if (rc < 0) { pr_err("Unable to set IBB_MODULE_EN rc = %d\n", rc); return rc; } @@ -1510,9 +2256,9 @@ static int qpnp_labibb_regulator_disable(struct qpnp_labibb *labibb) retries = 2; while (retries--) { usleep_range(dly, dly + 100); - rc = qpnp_labibb_read(labibb, &val, - labibb->ibb_base + REG_IBB_STATUS1, 1); - if (rc) { + rc = qpnp_labibb_read(labibb, labibb->ibb_base + + REG_IBB_STATUS1, &val, 1); + if (rc < 0) { pr_err("read register %x failed rc = %d\n", REG_IBB_STATUS1, rc); return rc; @@ -1553,7 +2299,7 @@ static int qpnp_lab_regulator_enable(struct regulator_dev *rdev) if (labibb->skip_2nd_swire_cmd) { rc = qpnp_ibb_ps_config(labibb, false); - if (rc) { + if (rc < 0) { pr_err("Failed to disable IBB PS rc=%d\n", rc); return rc; } @@ -1567,7 +2313,7 @@ static int qpnp_lab_regulator_enable(struct regulator_dev *rdev) val = LAB_ENABLE_CTL_EN; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_ENABLE_CTL, &val, 1); - if (rc) { + if (rc < 0) { pr_err("qpnp_lab_regulator_enable write register %x failed rc = %d\n", REG_LAB_ENABLE_CTL, rc); return rc; @@ -1575,9 +2321,9 @@ static int qpnp_lab_regulator_enable(struct regulator_dev *rdev) udelay(labibb->lab_vreg.soft_start); - rc = qpnp_labibb_read(labibb, &val, - labibb->lab_base + REG_LAB_STATUS1, 1); - if (rc) { + rc = qpnp_labibb_read(labibb, labibb->lab_base + + REG_LAB_STATUS1, &val, 1); + if (rc < 0) { pr_err("qpnp_lab_regulator_enable read register %x failed rc = %d\n", REG_LAB_STATUS1, rc); return rc; @@ -1608,7 +2354,7 @@ static int qpnp_lab_regulator_disable(struct regulator_dev *rdev) val = 0; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_ENABLE_CTL, &val, 1); - if (rc) { + if (rc < 0) { pr_err("qpnp_lab_regulator_enable write register %x failed rc = %d\n", REG_LAB_ENABLE_CTL, rc); return rc; @@ -1661,7 +2407,7 @@ static int qpnp_lab_regulator_set_voltage(struct regulator_dev *rdev, LAB_VOLTAGE_OVERRIDE_EN, val | LAB_VOLTAGE_OVERRIDE_EN); - if (rc) { + if (rc < 0) { pr_err("write to register %x failed rc = %d\n", REG_LAB_VOLTAGE, rc); return rc; @@ -1684,9 +2430,9 @@ static int qpnp_skip_swire_command(struct qpnp_labibb *labibb) do { /* poll for ibb vreg_ok */ - rc = qpnp_labibb_read(labibb, ®, - labibb->ibb_base + REG_IBB_STATUS1, 1); - if (rc) { + rc = qpnp_labibb_read(labibb, labibb->ibb_base + + REG_IBB_STATUS1, ®, 1); + if (rc < 0) { pr_err("Failed to read ibb_status1 reg rc=%d\n", rc); return rc; } @@ -1705,7 +2451,7 @@ static int qpnp_skip_swire_command(struct qpnp_labibb *labibb) /* move to SW control */ rc = qpnp_ibb_set_mode(labibb, IBB_SW_CONTROL_EN); - if (rc) { + if (rc < 0) { pr_err("Failed switch to IBB_SW_CONTROL rc=%d\n", rc); return rc; } @@ -1720,7 +2466,7 @@ static int qpnp_skip_swire_command(struct qpnp_labibb *labibb) usleep_range(dly, dly + 10); rc = qpnp_ibb_set_mode(labibb, IBB_HW_SW_CONTROL); - if (rc) { + if (rc < 0) { pr_err("Failed switch to IBB_HW_SW_CONTROL rc=%d\n", rc); return rc; } @@ -1730,13 +2476,13 @@ static int qpnp_skip_swire_command(struct qpnp_labibb *labibb) /* Move back to SWIRE control */ rc = qpnp_ibb_set_mode(labibb, IBB_HW_CONTROL); - if (rc) + if (rc < 0) pr_err("Failed switch to IBB_HW_CONTROL rc=%d\n", rc); /* delay before enabling the PS mode */ msleep(labibb->swire_ibb_ps_enable_delay); rc = qpnp_ibb_ps_config(labibb, true); - if (rc) + if (rc < 0) pr_err("Unable to enable IBB PS rc=%d\n", rc); return rc; @@ -1804,7 +2550,7 @@ static int register_qpnp_lab_regulator(struct qpnp_labibb *labibb, struct regulator_init_data *init_data; struct regulator_desc *rdesc = &labibb->lab_vreg.rdesc; struct regulator_config cfg = {}; - u8 val; + u8 val, mask; const char *current_sense_str; bool config_current_sense = false; u32 tmp; @@ -1845,54 +2591,53 @@ static int register_qpnp_lab_regulator(struct qpnp_labibb *labibb, rc = of_property_read_u32(of_node, "qcom,qpnp-lab-soft-start", &(labibb->lab_vreg.soft_start)); - if (rc < 0) { - pr_err("qcom,qpnp-lab-soft-start is missing, rc = %d\n", - rc); - return rc; - } - - for (val = 0; val < ARRAY_SIZE(lab_soft_start_plan); val++) - if (lab_soft_start_plan[val] == labibb->lab_vreg.soft_start) - break; + if (!rc) { + for (val = 0; val < ARRAY_SIZE(lab_soft_start_table); val++) + if (lab_soft_start_table[val] == + labibb->lab_vreg.soft_start) + break; - if (val == ARRAY_SIZE(lab_soft_start_plan)) - val = ARRAY_SIZE(lab_soft_start_plan) - 1; + if (val == ARRAY_SIZE(lab_soft_start_table)) + val = ARRAY_SIZE(lab_soft_start_table) - 1; - rc = qpnp_labibb_write(labibb, labibb->lab_base + + rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_SOFT_START_CTL, &val, 1); - if (rc) { - pr_err("qpnp_labibb_write register %x failed rc = %d\n", - REG_LAB_SOFT_START_CTL, rc); - return rc; - } + if (rc < 0) { + pr_err("qpnp_labibb_write register %x failed rc = %d\n", + REG_LAB_SOFT_START_CTL, rc); + return rc; + } - labibb->lab_vreg.soft_start = lab_soft_start_plan + labibb->lab_vreg.soft_start = lab_soft_start_table [val & LAB_SOFT_START_CTL_MASK]; - - rc = of_property_read_u32(of_node, "qcom,qpnp-lab-max-precharge-time", - &tmp); - if (rc) { - pr_err("get qcom,qpnp-lab-max-precharge-time failed, rc = %d\n", - rc); - return rc; } - for (val = 0; val < ARRAY_SIZE(lab_max_precharge_plan); val++) - if (lab_max_precharge_plan[val] == tmp) - break; + val = 0; + mask = 0; + rc = of_property_read_u32(of_node, + "qcom,qpnp-lab-max-precharge-time", &tmp); + if (!rc) { + for (val = 0; val < ARRAY_SIZE(lab_max_precharge_table); val++) + if (lab_max_precharge_table[val] == tmp) + break; - if (val == ARRAY_SIZE(lab_max_precharge_plan)) { - pr_err("Invalid property in qcom,qpnp-lab-max-precharge-time\n"); - return -EINVAL; + if (val == ARRAY_SIZE(lab_max_precharge_table)) { + pr_err("Invalid value in qcom,qpnp-lab-max-precharge-time\n"); + return -EINVAL; + } + + mask = LAB_MAX_PRECHARGE_TIME_MASK; } if (of_property_read_bool(of_node, - "qcom,qpnp-lab-max-precharge-enable")) - val |= LAB_PRECHARGE_CTL_EN; + "qcom,qpnp-lab-max-precharge-enable")) { + val |= LAB_FAST_PRECHARGE_CTL_EN; + mask |= LAB_FAST_PRECHARGE_CTL_EN; + } - rc = qpnp_labibb_write(labibb, labibb->lab_base + - REG_LAB_PRECHARGE_CTL, &val, 1); - if (rc) { + rc = qpnp_labibb_masked_write(labibb, labibb->lab_base + + REG_LAB_PRECHARGE_CTL, mask, val); + if (rc < 0) { pr_err("qpnp_lab_dt_init write register %x failed rc = %d\n", REG_LAB_PRECHARGE_CTL, rc); return rc; @@ -1930,7 +2675,7 @@ static int register_qpnp_lab_regulator(struct qpnp_labibb *labibb, REG_LAB_CURRENT_SENSE, LAB_CURRENT_SENSE_GAIN_MASK, val); - if (rc) { + if (rc < 0) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_CURRENT_SENSE, rc); return rc; @@ -1939,17 +2684,17 @@ static int register_qpnp_lab_regulator(struct qpnp_labibb *labibb, val = (labibb->standalone) ? 0 : LAB_IBB_EN_RDY_EN; rc = qpnp_labibb_sec_write(labibb, labibb->lab_base, - REG_LAB_IBB_EN_RDY, &val, 1); + REG_LAB_IBB_EN_RDY, val); - if (rc) { + if (rc < 0) { pr_err("qpnp_lab_sec_write register %x failed rc = %d\n", REG_LAB_IBB_EN_RDY, rc); return rc; } - rc = qpnp_labibb_read(labibb, &val, - labibb->ibb_base + REG_IBB_ENABLE_CTL, 1); - if (rc) { + rc = qpnp_labibb_read(labibb, labibb->ibb_base + REG_IBB_ENABLE_CTL, + &val, 1); + if (rc < 0) { pr_err("qpnp_labibb_read register %x failed rc = %d\n", REG_IBB_ENABLE_CTL, rc); return rc; @@ -1958,53 +2703,41 @@ static int register_qpnp_lab_regulator(struct qpnp_labibb *labibb, if (!(val & (IBB_ENABLE_CTL_SWIRE_RDY | IBB_ENABLE_CTL_MODULE_EN))) { /* SWIRE_RDY and IBB_MODULE_EN not enabled */ rc = qpnp_lab_dt_init(labibb, of_node); - if (rc) { + if (rc < 0) { pr_err("qpnp-lab: wrong DT parameter specified: rc = %d\n", rc); return rc; } } else { - rc = qpnp_labibb_read(labibb, &val, - labibb->lab_base + REG_LAB_LCD_AMOLED_SEL, 1); - if (rc) { - pr_err("qpnp_labibb_read register %x failed rc = %d\n", - REG_LAB_LCD_AMOLED_SEL, rc); - return rc; - } - - if (val == REG_LAB_IBB_AMOLED_MODE) - labibb->mode = QPNP_LABIBB_AMOLED_MODE; - else - labibb->mode = QPNP_LABIBB_LCD_MODE; + rc = labibb->ibb_ver_ops->get_mode(labibb); - rc = qpnp_labibb_read(labibb, &val, labibb->lab_base + - REG_LAB_VOLTAGE, 1); - if (rc) { + rc = qpnp_labibb_read(labibb, labibb->lab_base + + REG_LAB_VOLTAGE, &val, 1); + if (rc < 0) { pr_err("qpnp_lab_read read register %x failed rc = %d\n", REG_LAB_VOLTAGE, rc); return rc; } - if (val & LAB_VOLTAGE_OVERRIDE_EN) { - labibb->lab_vreg.curr_volt = + labibb->lab_vreg.curr_volt = (val & LAB_VOLTAGE_SET_MASK) * labibb->lab_vreg.step_size + labibb->lab_vreg.min_volt; - } else if (labibb->mode == QPNP_LABIBB_LCD_MODE) { + if (labibb->mode == QPNP_LABIBB_LCD_MODE) { rc = of_property_read_u32(of_node, "qcom,qpnp-lab-init-lcd-voltage", &(labibb->lab_vreg.curr_volt)); - if (rc) { + if (rc < 0) { pr_err("get qcom,qpnp-lab-init-lcd-voltage failed, rc = %d\n", rc); return rc; } - } else { + } else if (!(val & LAB_VOLTAGE_OVERRIDE_EN)) { rc = of_property_read_u32(of_node, "qcom,qpnp-lab-init-amoled-voltage", &(labibb->lab_vreg.curr_volt)); - if (rc) { + if (rc < 0) { pr_err("get qcom,qpnp-lab-init-amoled-voltage failed, rc = %d\n", rc); return rc; @@ -2027,9 +2760,9 @@ static int register_qpnp_lab_regulator(struct qpnp_labibb *labibb, } } - rc = qpnp_labibb_read(labibb, &val, - labibb->lab_base + REG_LAB_MODULE_RDY, 1); - if (rc) { + rc = qpnp_labibb_read(labibb, labibb->lab_base + REG_LAB_MODULE_RDY, + &val, 1); + if (rc < 0) { pr_err("qpnp_lab_read read register %x failed rc = %d\n", REG_LAB_MODULE_RDY, rc); return rc; @@ -2041,7 +2774,7 @@ static int register_qpnp_lab_regulator(struct qpnp_labibb *labibb, rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_MODULE_RDY, &val, 1); - if (rc) { + if (rc < 0) { pr_err("qpnp_lab_dt_init write register %x failed rc = %d\n", REG_LAB_MODULE_RDY, rc); return rc; @@ -2084,12 +2817,161 @@ static int register_qpnp_lab_regulator(struct qpnp_labibb *labibb, return 0; } +static int qpnp_ibb_pfm_mode_enable(struct qpnp_labibb *labibb, + struct device_node *of_node) +{ + int rc = 0; + u32 i, tmp = 0; + u8 val = IBB_PFM_ENABLE; + + rc = of_property_read_u32(of_node, "qcom,qpnp-ibb-pfm-peak-curr", + &tmp); + if (rc < 0) { + pr_err("qcom,qpnp-ibb-pfm-peak-curr is missing, rc = %d\n", + rc); + return rc; + } + for (i = 0; i < ARRAY_SIZE(ibb_pfm_peak_curr_table); i++) + if (ibb_pfm_peak_curr_table[i] == tmp) + break; + + if (i == ARRAY_SIZE(ibb_pfm_peak_curr_table)) { + pr_err("Invalid value in qcom,qpnp-ibb-pfm-peak-curr\n"); + return -EINVAL; + } + + val |= (i << IBB_PFM_PEAK_CURRENT_BIT_SHIFT); + + rc = of_property_read_u32(of_node, "qcom,qpnp-ibb-pfm-hysteresis", + &tmp); + if (rc < 0) { + pr_err("qcom,qpnp-ibb-pfm-hysteresis is missing, rc = %d\n", + rc); + return rc; + } + + for (i = 0; i < ARRAY_SIZE(ibb_pfm_hysteresis_table); i++) + if (ibb_pfm_hysteresis_table[i] == tmp) + break; + + if (i == ARRAY_SIZE(ibb_pfm_hysteresis_table)) { + pr_err("Invalid value in qcom,qpnp-ibb-pfm-hysteresis\n"); + return -EINVAL; + } + + val |= (i << IBB_PFM_HYSTERESIS_BIT_SHIFT); + + rc = qpnp_labibb_write(labibb, labibb->ibb_base + + REG_IBB_PFM_CTL, &val, 1); + if (rc < 0) + pr_err("qpnp_ibb_pfm_ctl write register %x failed rc = %d\n", + REG_IBB_PFM_CTL, rc); + + return rc; +} + +static int qpnp_labibb_pbs_mode_enable(struct qpnp_labibb *labibb, + struct device_node *of_node) +{ + int rc = 0; + + rc = qpnp_labibb_masked_write(labibb, labibb->ibb_base + + REG_IBB_SWIRE_CTL, + IBB_SWIRE_VOUT_UPD_EN, 0); + if (rc < 0) { + pr_err("qpnp_ibb_swire_ctl write register %x failed rc = %d\n", + REG_IBB_SWIRE_CTL, rc); + return rc; + } + + rc = qpnp_labibb_masked_write(labibb, labibb->ibb_base + + REG_IBB_PD_CTL, IBB_SWIRE_PD_UPD, 0); + if (rc < 0) { + pr_err("qpnp_ibb_pd_ctl write register %x failed rc = %d\n", + REG_IBB_PD_CTL, rc); + return rc; + } + + rc = qpnp_labibb_masked_write(labibb, labibb->lab_base + + REG_LAB_SWIRE_PGM_CTL, LAB_EN_SWIRE_PGM_VOUT | + LAB_EN_SWIRE_PGM_PD, 0); + if (rc < 0) + pr_err("qpnp_lab_swire_pgm_ctl write register %x failed rc = %d\n", + REG_LAB_SWIRE_PGM_CTL, rc); + + return rc; +} + +static int qpnp_ibb_slew_rate_config(struct qpnp_labibb *labibb, + struct device_node *of_node) +{ + int rc = 0; + u32 i, tmp = 0; + u8 val = 0, mask = 0; + + rc = of_property_read_u32(of_node, "qcom,qpnp-ibb-fast-slew-rate", + &tmp); + if (!rc) { + for (i = 0; i < ARRAY_SIZE(ibb_output_slew_ctl_table); i++) + if (ibb_output_slew_ctl_table[i] == tmp) + break; + + if (i == ARRAY_SIZE(ibb_output_slew_ctl_table)) { + pr_err("Invalid value in qcom,qpnp-ibb-fast-slew-rate\n"); + return -EINVAL; + } + + labibb->ibb_vreg.slew_rate = tmp; + val |= (i << IBB_SLEW_RATE_TRANS_TIME_FAST_SHIFT) | + IBB_SLEW_RATE_SPEED_FAST_EN | IBB_SLEW_CTL_EN; + + mask = IBB_SLEW_RATE_SPEED_FAST_EN | + IBB_SLEW_RATE_TRANS_TIME_FAST_MASK | IBB_SLEW_CTL_EN; + } + + rc = of_property_read_u32(of_node, "qcom,qpnp-ibb-slow-slew-rate", + &tmp); + if (!rc) { + for (i = 0; i < ARRAY_SIZE(ibb_output_slew_ctl_table); i++) + if (ibb_output_slew_ctl_table[i] == tmp) + break; + + if (i == ARRAY_SIZE(ibb_output_slew_ctl_table)) { + pr_err("Invalid value in qcom,qpnp-ibb-slow-slew-rate\n"); + return -EINVAL; + } + + labibb->ibb_vreg.slew_rate = tmp; + val |= (i | IBB_SLEW_CTL_EN); + + mask |= IBB_SLEW_RATE_SPEED_FAST_EN | + IBB_SLEW_RATE_TRANS_TIME_SLOW_MASK | IBB_SLEW_CTL_EN; + } + + rc = qpnp_labibb_masked_write(labibb, labibb->ibb_base + + REG_IBB_OUTPUT_SLEW_CTL, + mask, val); + if (rc < 0) + pr_err("qpnp_labibb_write register %x failed rc = %d\n", + REG_IBB_OUTPUT_SLEW_CTL, rc); + + return rc; +} + +static bool qpnp_ibb_poff_ctl_required(struct qpnp_labibb *labibb) +{ + if (labibb->pmic_rev_id->pmic_subtype == PM660L_SUBTYPE) + return false; + + return true; +} + static int qpnp_ibb_dt_init(struct qpnp_labibb *labibb, struct device_node *of_node) { int rc = 0; - u32 i, tmp; - u8 val; + u32 i, tmp = 0; + u8 val, mask; /* * Do not configure LCD_AMOLED_SEL for pmi8998 as it will be done by @@ -2097,180 +2979,166 @@ static int qpnp_ibb_dt_init(struct qpnp_labibb *labibb, * by the bootloader. */ if (labibb->pmic_rev_id->pmic_subtype == PMI8998_SUBTYPE) { - rc = qpnp_labibb_read(labibb, &val, - labibb->ibb_base + REG_IBB_LCD_AMOLED_SEL, 1); + rc = qpnp_labibb_read(labibb, labibb->ibb_base + + REG_IBB_LCD_AMOLED_SEL, &val, 1); if (rc) { pr_err("qpnp_labibb_read register %x failed rc = %d\n", - REG_IBB_LCD_AMOLED_SEL, rc); + REG_IBB_LCD_AMOLED_SEL, rc); return rc; } - if (val == REG_LAB_IBB_AMOLED_MODE) labibb->mode = QPNP_LABIBB_AMOLED_MODE; else labibb->mode = QPNP_LABIBB_LCD_MODE; } else { - if (labibb->mode == QPNP_LABIBB_LCD_MODE) - val = REG_LAB_IBB_LCD_MODE; - else - val = REG_LAB_IBB_AMOLED_MODE; - - rc = qpnp_labibb_sec_write(labibb, labibb->ibb_base, - REG_LAB_LCD_AMOLED_SEL, &val, 1); - if (rc) { + rc = labibb->ibb_ver_ops->sel_mode(labibb, 1); + if (rc < 0) { pr_err("qpnp_labibb_sec_write register %x failed rc = %d\n", REG_IBB_LCD_AMOLED_SEL, rc); return rc; } } - rc = of_property_read_u32(of_node, "qcom,qpnp-ibb-lab-pwrdn-delay", - &tmp); - if (rc < 0) { - pr_err("qcom,qpnp-ibb-lab-pwrdn-delay is missing, rc = %d\n", - rc); - return rc; - } - val = 0; + mask = 0; + rc = of_property_read_u32(of_node, + "qcom,qpnp-ibb-lab-pwrdn-delay", &tmp); + if (!rc) { + for (val = 0; val < ARRAY_SIZE(ibb_pwrdn_dly_table); val++) + if (ibb_pwrdn_dly_table[val] == tmp) + break; - for (val = 0; val < ARRAY_SIZE(ibb_pwrdn_dly_plan); val++) - if (ibb_pwrdn_dly_plan[val] == tmp) - break; + if (val == ARRAY_SIZE(ibb_pwrdn_dly_table)) { + pr_err("Invalid value in qcom,qpnp-ibb-lab-pwrdn-delay\n"); + return -EINVAL; + } - if (val == ARRAY_SIZE(ibb_pwrdn_dly_plan)) { - pr_err("Invalid property in qcom,qpnp-ibb-lab-pwrdn-delay\n"); - return -EINVAL; + labibb->ibb_vreg.pwrdn_dly = tmp; + val |= IBB_PWRUP_PWRDN_CTL_1_EN_DLY2; + mask |= IBB_PWRUP_PWRDN_CTL_1_EN_DLY2; } - labibb->ibb_vreg.pwrdn_dly = tmp; + rc = of_property_read_u32(of_node, + "qcom,qpnp-ibb-lab-pwrup-delay", &tmp); + if (!rc) { + for (i = 0; i < ARRAY_SIZE(ibb_pwrup_dly_table); i++) + if (ibb_pwrup_dly_table[i] == tmp) + break; - rc = of_property_read_u32(of_node, "qcom,qpnp-ibb-lab-pwrup-delay", - &tmp); - if (rc < 0) { - pr_err("qcom,qpnp-ibb-lab-pwrup-delay is missing, rc = %d\n", - rc); - return rc; - } + if (i == ARRAY_SIZE(ibb_pwrup_dly_table)) { + pr_err("Invalid value in qcom,qpnp-ibb-lab-pwrup-delay\n"); + return -EINVAL; + } - for (i = 0; i < ARRAY_SIZE(ibb_pwrup_dly_plan); i++) - if (ibb_pwrup_dly_plan[i] == tmp) - break; + labibb->ibb_vreg.pwrup_dly = tmp; - if (i == ARRAY_SIZE(ibb_pwrup_dly_plan)) { - pr_err("Invalid property in qcom,qpnp-ibb-lab-pwrup-delay\n"); - return -EINVAL; + val |= (i << IBB_PWRUP_PWRDN_CTL_1_DLY1_SHIFT); + val |= (IBB_PWRUP_PWRDN_CTL_1_EN_DLY1 | + IBB_PWRUP_PWRDN_CTL_1_LAB_VREG_OK); + mask |= (IBB_PWRUP_PWRDN_CTL_1_EN_DLY1 | + IBB_PWRUP_PWRDN_CTL_1_DLY1_MASK | + IBB_PWRUP_PWRDN_CTL_1_LAB_VREG_OK); } - labibb->ibb_vreg.pwrup_dly = tmp; - - val |= (i << IBB_PWRUP_PWRDN_CTL_1_DLY1_SHIFT); - - if (of_property_read_bool(of_node, "qcom,qpnp-ibb-en-discharge")) + if (of_property_read_bool(of_node, + "qcom,qpnp-ibb-en-discharge")) { val |= PWRUP_PWRDN_CTL_1_DISCHARGE_EN; + mask |= PWRUP_PWRDN_CTL_1_DISCHARGE_EN; + } - val |= (IBB_PWRUP_PWRDN_CTL_1_EN_DLY1 | - IBB_PWRUP_PWRDN_CTL_1_LAB_VREG_OK); - - rc = qpnp_labibb_sec_write(labibb, labibb->ibb_base, - REG_IBB_PWRUP_PWRDN_CTL_1, - &val, - 1); - if (rc) { + rc = qpnp_labibb_sec_masked_write(labibb, labibb->ibb_base, + REG_IBB_PWRUP_PWRDN_CTL_1, mask, val); + if (rc < 0) { pr_err("qpnp_labibb_sec_write register %x failed rc = %d\n", REG_IBB_PWRUP_PWRDN_CTL_1, rc); return rc; } - val = 0; + if (of_property_read_bool(of_node, "qcom,qpnp-ibb-slew-rate-config")) { + rc = qpnp_ibb_slew_rate_config(labibb, of_node); + if (rc < 0) + return rc; + } + + val = 0; if (!of_property_read_bool(of_node, "qcom,qpnp-ibb-full-pull-down")) - val |= IBB_PD_CTL_HALF_STRENGTH; + val = IBB_PD_CTL_HALF_STRENGTH; if (of_property_read_bool(of_node, "qcom,qpnp-ibb-pull-down-enable")) val |= IBB_PD_CTL_EN; - rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_PD_CTL, - &val, 1); + mask = IBB_PD_CTL_STRENGTH_MASK | IBB_PD_CTL_EN; + rc = qpnp_labibb_masked_write(labibb, + labibb->ibb_base + REG_IBB_PD_CTL, mask, val); - if (rc) { + if (rc < 0) { pr_err("qpnp_lab_dt_init write register %x failed rc = %d\n", REG_IBB_PD_CTL, rc); return rc; } rc = of_property_read_u32(of_node, - "qcom,qpnp-ibb-switching-clock-frequency", &tmp); - if (rc) { - pr_err("get qcom,qpnp-ibb-switching-clock-frequency failed rc = %d\n", - rc); - return rc; - } - - for (val = 0; val < ARRAY_SIZE(ibb_clk_div_plan); val++) - if (ibb_clk_div_plan[val] == tmp) - break; - - if (val == ARRAY_SIZE(ibb_clk_div_plan)) { - pr_err("Invalid property in qpnp-ibb-switching-clock-frequency\n"); - return -EINVAL; - } + "qcom,qpnp-ibb-switching-clock-frequency", &tmp); + if (!rc) { + for (val = 0; val < ARRAY_SIZE(ibb_clk_div_table); val++) + if (ibb_clk_div_table[val] == tmp) + break; - rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_CLK_DIV, - &val, 1); - if (rc) { - pr_err("qpnp_ibb_dt_init write register %x failed rc = %d\n", - REG_IBB_CLK_DIV, rc); - return rc; + if (val == ARRAY_SIZE(ibb_clk_div_table)) { + pr_err("Invalid value in qpnp-ibb-switching-clock-frequency\n"); + return -EINVAL; + } + rc = labibb->ibb_ver_ops->set_clk_div(labibb, val); + if (rc < 0) { + pr_err("qpnp_ibb_dt_init write register %x failed rc = %d\n", + REG_IBB_CLK_DIV, rc); + return rc; + } } + val = 0; + mask = 0; rc = of_property_read_u32(of_node, "qcom,qpnp-ibb-limit-maximum-current", &tmp); + if (!rc) { + for (val = 0; val < ARRAY_SIZE(ibb_current_limit_table); val++) + if (ibb_current_limit_table[val] == tmp) + break; - if (rc) { - pr_err("get qcom,qpnp-ibb-limit-maximum-current failed rc = %d\n", - rc); - return rc; - } - - for (val = 0; val < ARRAY_SIZE(ibb_current_limit_plan); val++) - if (ibb_current_limit_plan[val] == tmp) - break; + if (val == ARRAY_SIZE(ibb_current_limit_table)) { + pr_err("Invalid value in qcom,qpnp-ibb-limit-maximum-current\n"); + return -EINVAL; + } - if (val == ARRAY_SIZE(ibb_current_limit_plan)) { - pr_err("Invalid property in qcom,qpnp-ibb-limit-maximum-current\n"); - return -EINVAL; + mask = IBB_CURRENT_LIMIT_MASK; } - rc = of_property_read_u32(of_node, "qcom,qpnp-ibb-debounce-cycle", - &tmp); - - if (rc) { - pr_err("get qcom,qpnp-ibb-debounce-cycle failed rc = %d\n", - rc); - return rc; - } + rc = of_property_read_u32(of_node, + "qcom,qpnp-ibb-debounce-cycle", &tmp); + if (!rc) { + for (i = 0; i < ARRAY_SIZE(ibb_debounce_table); i++) + if (ibb_debounce_table[i] == tmp) + break; - for (i = 0; i < ARRAY_SIZE(ibb_debounce_plan); i++) - if (ibb_debounce_plan[i] == tmp) - break; + if (i == ARRAY_SIZE(ibb_debounce_table)) { + pr_err("Invalid value in qcom,qpnp-ibb-debounce-cycle\n"); + return -EINVAL; + } - if (i == ARRAY_SIZE(ibb_debounce_plan)) { - pr_err("Invalid property in qcom,qpnp-ibb-debounce-cycle\n"); - return -EINVAL; + val |= (i << IBB_CURRENT_LIMIT_DEBOUNCE_SHIFT); + mask |= IBB_CURRENT_LIMIT_DEBOUNCE_MASK; } - val |= (i << IBB_CURRENT_LIMIT_DEBOUNCE_SHIFT); - if (of_property_read_bool(of_node, - "qcom,qpnp-ibb-limit-max-current-enable")) + "qcom,qpnp-ibb-limit-max-current-enable")) { val |= IBB_CURRENT_LIMIT_EN; + mask |= IBB_CURRENT_LIMIT_EN; + } - rc = qpnp_labibb_sec_write(labibb, labibb->ibb_base, - REG_IBB_CURRENT_LIMIT, - &val, - 1); - if (rc) { + rc = qpnp_labibb_sec_masked_write(labibb, labibb->ibb_base, + REG_IBB_CURRENT_LIMIT, mask, val); + if (rc < 0) { pr_err("qpnp_labibb_sec_write register %x failed rc = %d\n", REG_IBB_CURRENT_LIMIT, rc); return rc; @@ -2283,7 +3151,7 @@ static int qpnp_ibb_dt_init(struct qpnp_labibb *labibb, REG_IBB_RING_SUPPRESSION_CTL, &val, 1); - if (rc) { + if (rc < 0) { pr_err("qpnp_ibb_dt_init write register %x failed rc = %d\n", REG_IBB_RING_SUPPRESSION_CTL, rc); return rc; @@ -2292,67 +3160,60 @@ static int qpnp_ibb_dt_init(struct qpnp_labibb *labibb, if (of_property_read_bool(of_node, "qcom,qpnp-ibb-ps-enable")) { rc = qpnp_ibb_ps_config(labibb, true); - if (rc) { + if (rc < 0) { pr_err("qpnp_ibb_dt_init PS enable failed rc=%d\n", rc); return rc; } } else { rc = qpnp_ibb_ps_config(labibb, false); - if (rc) { + if (rc < 0) { pr_err("qpnp_ibb_dt_init PS disable failed rc=%d\n", rc); return rc; } } + if (of_property_read_bool(of_node, + "qcom,qpnp-ibb-smart-ps-enable")){ + of_property_read_u32(of_node, "qcom,qpnp-ibb-num-swire-trans", + &labibb->ibb_vreg.num_swire_trans); + + of_property_read_u32(of_node, + "qcom,qpnp-ibb-neg-curr-limit", &tmp); + + rc = labibb->ibb_ver_ops->smart_ps_config(labibb, true, + labibb->ibb_vreg.num_swire_trans, tmp); + if (rc < 0) { + pr_err("qpnp_ibb_dt_init smart PS enable failed rc=%d\n", + rc); + return rc; + } + + } + rc = of_property_read_u32(of_node, "qcom,qpnp-ibb-init-voltage", &(labibb->ibb_vreg.curr_volt)); - if (rc) { + if (rc < 0) { pr_err("get qcom,qpnp-ibb-init-voltage failed, rc = %d\n", rc); return rc; } - if (!of_property_read_bool(of_node, - "qcom,qpnp-ibb-use-default-voltage")) { - if (labibb->ibb_vreg.curr_volt < labibb->ibb_vreg.min_volt) { - pr_err("Invalid qcom,qpnp-ibb-init-voltage property, qcom,qpnp-ibb-init-voltage %d is less than the the minimum voltage %d", - labibb->ibb_vreg.curr_volt, - labibb->ibb_vreg.min_volt); - return -EINVAL; - } - - val = DIV_ROUND_UP(labibb->ibb_vreg.curr_volt - - labibb->ibb_vreg.min_volt, - labibb->ibb_vreg.step_size); + if (of_property_read_bool(of_node, + "qcom,qpnp-ibb-use-default-voltage")) + rc = labibb->ibb_ver_ops->set_default_voltage(labibb, true); + else + rc = labibb->ibb_ver_ops->set_default_voltage(labibb, false); - if (val > IBB_VOLTAGE_SET_MASK) { - pr_err("Invalid qcom,qpnp-ibb-init-voltage property, qcom,qpnp-lab-init-voltage %d is larger than the max supported voltage %d", - labibb->ibb_vreg.curr_volt, - labibb->ibb_vreg.min_volt + - labibb->ibb_vreg.step_size * - IBB_VOLTAGE_SET_MASK); - return -EINVAL; - } + if (rc < 0) + return rc; - labibb->ibb_vreg.curr_volt = val * labibb->ibb_vreg.step_size + - labibb->ibb_vreg.min_volt; - val |= IBB_VOLTAGE_OVERRIDE_EN; - } else { - val = 0; + if (of_property_read_bool(of_node, "qcom,qpnp-ibb-overload-blank")) { + rc = qpnp_ibb_vreg_ok_ctl(labibb, of_node); + if (rc < 0) + return rc; } - rc = qpnp_labibb_masked_write(labibb, labibb->ibb_base + - REG_IBB_VOLTAGE, - IBB_VOLTAGE_SET_MASK | - IBB_VOLTAGE_OVERRIDE_EN, - val); - - if (rc) - pr_err("qpnp_ibb_masked_write write register %x failed rc = %d\n", - REG_IBB_VOLTAGE, rc); - - - return rc; + return 0; } static int qpnp_ibb_regulator_enable(struct regulator_dev *rdev) @@ -2367,7 +3228,7 @@ static int qpnp_ibb_regulator_enable(struct regulator_dev *rdev) return qpnp_labibb_regulator_enable(labibb); rc = qpnp_ibb_set_mode(labibb, IBB_SW_CONTROL_EN); - if (rc) { + if (rc < 0) { pr_err("Unable to set IBB_MODULE_EN rc = %d\n", rc); return rc; } @@ -2377,9 +3238,9 @@ static int qpnp_ibb_regulator_enable(struct regulator_dev *rdev) /* Wait for a small period before reading IBB_STATUS1 */ usleep_range(delay, delay + 100); - rc = qpnp_labibb_read(labibb, &val, - labibb->ibb_base + REG_IBB_STATUS1, 1); - if (rc) { + rc = qpnp_labibb_read(labibb, labibb->ibb_base + + REG_IBB_STATUS1, &val, 1); + if (rc < 0) { pr_err("qpnp_ibb_regulator_enable read register %x failed rc = %d\n", REG_IBB_STATUS1, rc); return rc; @@ -2410,7 +3271,7 @@ static int qpnp_ibb_regulator_disable(struct regulator_dev *rdev) return qpnp_labibb_regulator_disable(labibb); rc = qpnp_ibb_set_mode(labibb, IBB_SW_CONTROL_DIS); - if (rc) { + if (rc < 0) { pr_err("Unable to set IBB_MODULE_EN rc = %d\n", rc); return rc; } @@ -2433,51 +3294,18 @@ static int qpnp_ibb_regulator_is_enabled(struct regulator_dev *rdev) static int qpnp_ibb_regulator_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, unsigned *selector) { - int rc, new_uV; - u8 val; + int rc = 0; + struct qpnp_labibb *labibb = rdev_get_drvdata(rdev); if (labibb->swire_control) return 0; - if (min_uV < labibb->ibb_vreg.min_volt) { - pr_err("min_uV %d is less than min_volt %d", min_uV, - labibb->ibb_vreg.min_volt); - return -EINVAL; - } - - val = DIV_ROUND_UP(min_uV - labibb->ibb_vreg.min_volt, - labibb->ibb_vreg.step_size); - new_uV = val * labibb->ibb_vreg.step_size + labibb->ibb_vreg.min_volt; - - if (new_uV > max_uV) { - pr_err("unable to set voltage %d (min:%d max:%d)\n", new_uV, - min_uV, max_uV); - return -EINVAL; - } - - rc = qpnp_labibb_masked_write(labibb, labibb->ibb_base + - REG_IBB_VOLTAGE, - IBB_VOLTAGE_SET_MASK | - IBB_VOLTAGE_OVERRIDE_EN, - val | IBB_VOLTAGE_OVERRIDE_EN); - - if (rc) { - pr_err("write to register %x failed rc = %d\n", REG_IBB_VOLTAGE, - rc); - return rc; - } - - if (new_uV > labibb->ibb_vreg.curr_volt) { - val = DIV_ROUND_UP(new_uV - labibb->ibb_vreg.curr_volt, - labibb->ibb_vreg.step_size); - udelay(val * labibb->ibb_vreg.slew_rate); - } - labibb->ibb_vreg.curr_volt = new_uV; - - return 0; + rc = labibb->ibb_ver_ops->set_voltage(labibb, min_uV, max_uV); + return rc; } + static int qpnp_ibb_regulator_get_voltage(struct regulator_dev *rdev) { struct qpnp_labibb *labibb = rdev_get_drvdata(rdev); @@ -2534,50 +3362,11 @@ static int register_qpnp_ibb_regulator(struct qpnp_labibb *labibb, rc = of_property_read_u32(of_node, "qcom,qpnp-ibb-slew-rate", &(labibb->ibb_vreg.slew_rate)); - if (rc < 0) { - pr_err("qcom,qpnp-ibb-slew-rate is missing, rc = %d\n", - rc); - return rc; - } + if (rc < 0) + labibb->ibb_vreg.slew_rate = IBB_HW_DEFAULT_SLEW_RATE; - rc = of_property_read_u32(of_node, "qcom,qpnp-ibb-soft-start", - &(labibb->ibb_vreg.soft_start)); + rc = labibb->ibb_ver_ops->soft_start_ctl(labibb, of_node); if (rc < 0) { - pr_err("qcom,qpnp-ibb-soft-start is missing, rc = %d\n", - rc); - return rc; - } - - rc = of_property_read_u32(of_node, "qcom,qpnp-ibb-discharge-resistor", - &tmp); - - if (rc < 0) { - pr_err("qcom,qpnp-ibb-discharge-resistor is missing, rc = %d\n", - rc); - return rc; - } - - if (labibb->mode == QPNP_LABIBB_AMOLED_MODE) { - /* - * AMOLED mode needs ibb discharge resistor to be - * configured for 300KOhm - */ - if (tmp < ibb_discharge_resistor_plan[0]) - tmp = ibb_discharge_resistor_plan[0]; - } - - for (val = 0; val < ARRAY_SIZE(ibb_discharge_resistor_plan); val++) - if (ibb_discharge_resistor_plan[val] == tmp) - break; - - if (val == ARRAY_SIZE(ibb_discharge_resistor_plan)) { - pr_err("Invalid property in qcom,qpnp-ibb-discharge-resistor\n"); - return -EINVAL; - } - - rc = qpnp_labibb_write(labibb, labibb->ibb_base + - REG_IBB_SOFT_START_CTL, &val, 1); - if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_IBB_SOFT_START_CTL, rc); return rc; @@ -2585,42 +3374,29 @@ static int register_qpnp_ibb_regulator(struct qpnp_labibb *labibb, if (of_find_property(of_node, "qcom,output-voltage-one-pulse", NULL)) { if (!labibb->swire_control) { - pr_err("Invalid property 'qcom,output-voltage-one-pulse', valid only in SWIRE config\n"); + pr_err("output-voltage-one-pulse valid for SWIRE only\n"); return -EINVAL; } rc = of_property_read_u32(of_node, "qcom,output-voltage-one-pulse", &tmp); - if (rc) { + if (rc < 0) { pr_err("failed to read qcom,output-voltage-one-pulse rc=%d\n", rc); return rc; } if (tmp > MAX_OUTPUT_PULSE_VOLTAGE_MV || - tmp < MIN_OUTPUT_PULSE_VOLTAGE_MV) { + tmp < MIN_OUTPUT_PULSE_VOLTAGE_MV) { pr_err("Invalid one-pulse voltage range %d\n", tmp); return -EINVAL; } - - /* - * Set the output voltage 100mV lower as the IBB HW module - * counts one pulse less in SWIRE mode. - */ - val = DIV_ROUND_UP((tmp - MIN_OUTPUT_PULSE_VOLTAGE_MV), - OUTPUT_VOLTAGE_STEP_MV) - 1; - rc = qpnp_labibb_masked_write(labibb, labibb->ibb_base + - REG_IBB_SWIRE_CTL, - IBB_OUTPUT_VOLTAGE_AT_ONE_PULSE_MASK, - val); - if (rc) { - pr_err("qpnp_labiibb_write register %x failed rc = %d\n", - REG_IBB_SWIRE_CTL, rc); + rc = labibb->ibb_ver_ops->voltage_at_one_pulse(labibb, tmp); + if (rc < 0) return rc; - } } - rc = qpnp_labibb_read(labibb, &ibb_enable_ctl, - labibb->ibb_base + REG_IBB_ENABLE_CTL, 1); - if (rc) { + rc = qpnp_labibb_read(labibb, labibb->ibb_base + REG_IBB_ENABLE_CTL, + &ibb_enable_ctl, 1); + if (rc < 0) { pr_err("qpnp_ibb_read register %x failed rc = %d\n", REG_IBB_ENABLE_CTL, rc); return rc; @@ -2635,47 +3411,40 @@ static int register_qpnp_ibb_regulator(struct qpnp_labibb *labibb, if (ibb_enable_ctl & (IBB_ENABLE_CTL_SWIRE_RDY | IBB_ENABLE_CTL_MODULE_EN)) { - /* SWIRE_RDY or IBB_MODULE_EN enabled */ - rc = qpnp_labibb_read(labibb, &val, - labibb->ibb_base + REG_IBB_LCD_AMOLED_SEL, 1); - if (rc) { + + rc = labibb->ibb_ver_ops->get_mode(labibb); + if (rc < 0) { pr_err("qpnp_labibb_read register %x failed rc = %d\n", REG_IBB_LCD_AMOLED_SEL, rc); return rc; } - - if (val == REG_LAB_IBB_AMOLED_MODE) - labibb->mode = QPNP_LABIBB_AMOLED_MODE; - else - labibb->mode = QPNP_LABIBB_LCD_MODE; - - rc = qpnp_labibb_read(labibb, &val, - labibb->ibb_base + REG_IBB_VOLTAGE, 1); - if (rc) { + rc = qpnp_labibb_read(labibb, labibb->ibb_base + + REG_IBB_VOLTAGE, &val, 1); + if (rc < 0) { pr_err("qpnp_labibb_read read register %x failed rc = %d\n", REG_IBB_VOLTAGE, rc); return rc; } - if (val & IBB_VOLTAGE_OVERRIDE_EN) { - labibb->ibb_vreg.curr_volt = - (val & IBB_VOLTAGE_SET_MASK) * - labibb->ibb_vreg.step_size + - labibb->ibb_vreg.min_volt; - } else if (labibb->mode == QPNP_LABIBB_LCD_MODE) { + labibb->ibb_vreg.curr_volt = + (val & IBB_VOLTAGE_SET_MASK) * + labibb->ibb_vreg.step_size + + labibb->ibb_vreg.min_volt; + + if (labibb->mode == QPNP_LABIBB_LCD_MODE) { rc = of_property_read_u32(of_node, "qcom,qpnp-ibb-init-lcd-voltage", &(labibb->ibb_vreg.curr_volt)); - if (rc) { + if (rc < 0) { pr_err("get qcom,qpnp-ibb-init-lcd-voltage failed, rc = %d\n", rc); return rc; } - } else { + } else if (!(val & IBB_VOLTAGE_OVERRIDE_EN)) { rc = of_property_read_u32(of_node, "qcom,qpnp-ibb-init-amoled-voltage", &(labibb->ibb_vreg.curr_volt)); - if (rc) { + if (rc < 0) { pr_err("get qcom,qpnp-ibb-init-amoled-voltage failed, rc = %d\n", rc); return rc; @@ -2683,40 +3452,41 @@ static int register_qpnp_ibb_regulator(struct qpnp_labibb *labibb, } - rc = qpnp_labibb_read(labibb, &val, labibb->ibb_base + - REG_IBB_PWRUP_PWRDN_CTL_1, 1); - if (rc) { + rc = qpnp_labibb_read(labibb, labibb->ibb_base + + REG_IBB_PWRUP_PWRDN_CTL_1, &val, 1); + if (rc < 0) { pr_err("qpnp_labibb_config_init read register %x failed rc = %d\n", REG_IBB_PWRUP_PWRDN_CTL_1, rc); return rc; } - labibb->ibb_vreg.pwrup_dly = ibb_pwrup_dly_plan[ - (val >> - IBB_PWRUP_PWRDN_CTL_1_DLY1_SHIFT) & - IBB_PWRUP_PWRDN_CTL_1_DLY1_MASK]; - labibb->ibb_vreg.pwrdn_dly = ibb_pwrdn_dly_plan[val & + labibb->ibb_vreg.pwrup_dly = ibb_pwrup_dly_table[ + (val & + IBB_PWRUP_PWRDN_CTL_1_DLY1_MASK)]; + labibb->ibb_vreg.pwrdn_dly = ibb_pwrdn_dly_table[val & IBB_PWRUP_PWRDN_CTL_1_DLY2_MASK]; labibb->ibb_vreg.vreg_enabled = 1; } else { /* SWIRE_RDY and IBB_MODULE_EN not enabled */ rc = qpnp_ibb_dt_init(labibb, of_node); - if (rc) { + if (rc < 0) { pr_err("qpnp-ibb: wrong DT parameter specified: rc = %d\n", rc); return rc; } } - if (labibb->mode == QPNP_LABIBB_AMOLED_MODE) { + if (labibb->mode == QPNP_LABIBB_AMOLED_MODE && + qpnp_ibb_poff_ctl_required(labibb)) { + val = IBB_OVERRIDE_NONOVERLAP | IBB_NFET_GATE_DELAY_2; rc = qpnp_labibb_sec_masked_write(labibb, labibb->ibb_base, REG_IBB_NONOVERLAP_TIME_1, IBB_OVERRIDE_NONOVERLAP | IBB_NONOVERLAP_NFET_MASK, val); - if (rc) { + if (rc < 0) { pr_err("qpnp_labibb_sec_masked_write register %x failed rc = %d\n", REG_IBB_NONOVERLAP_TIME_1, rc); return rc; @@ -2724,9 +3494,9 @@ static int register_qpnp_ibb_regulator(struct qpnp_labibb *labibb, val = IBB_N2P_MUX_SEL; rc = qpnp_labibb_sec_write(labibb, labibb->ibb_base, - REG_IBB_NONOVERLAP_TIME_2, &val, 1); + REG_IBB_NONOVERLAP_TIME_2, val); - if (rc) { + if (rc < 0) { pr_err("qpnp_labibb_sec_write register %x failed rc = %d\n", REG_IBB_NONOVERLAP_TIME_2, rc); return rc; @@ -2734,11 +3504,11 @@ static int register_qpnp_ibb_regulator(struct qpnp_labibb *labibb, val = IBB_FASTER_PFET_OFF; rc = qpnp_labibb_masked_write(labibb, - labibb->ibb_base + REG_IBB_SPARE_CTL, - IBB_POFF_CTL_MASK, val); - if (rc) { - pr_err("qpnp_labibb_masked_write %x failed rc = %d\n", - REG_IBB_SPARE_CTL, rc); + labibb->ibb_base + REG_IBB_SPARE_CTL, + IBB_POFF_CTL_MASK, val); + if (rc < 0) { + pr_err("write to register %x failed rc = %d\n", + REG_IBB_SPARE_CTL, rc); return rc; } } @@ -2746,8 +3516,8 @@ static int register_qpnp_ibb_regulator(struct qpnp_labibb *labibb, if (labibb->standalone) { val = 0; rc = qpnp_labibb_sec_write(labibb, labibb->ibb_base, - REG_IBB_PWRUP_PWRDN_CTL_1, &val, 1); - if (rc) { + REG_IBB_PWRUP_PWRDN_CTL_1, val); + if (rc < 0) { pr_err("qpnp_labibb_sec_write register %x failed rc = %d\n", REG_IBB_PWRUP_PWRDN_CTL_1, rc); return rc; @@ -2756,9 +3526,9 @@ static int register_qpnp_ibb_regulator(struct qpnp_labibb *labibb, labibb->ibb_vreg.pwrdn_dly = 0; } - rc = qpnp_labibb_read(labibb, &val, - labibb->ibb_base + REG_IBB_MODULE_RDY, 1); - if (rc) { + rc = qpnp_labibb_read(labibb, labibb->ibb_base + REG_IBB_MODULE_RDY, + &val, 1); + if (rc < 0) { pr_err("qpnp_ibb_read read register %x failed rc = %d\n", REG_IBB_MODULE_RDY, rc); return rc; @@ -2770,13 +3540,26 @@ static int register_qpnp_ibb_regulator(struct qpnp_labibb *labibb, rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_MODULE_RDY, &val, 1); - if (rc) { + if (rc < 0) { pr_err("qpnp_ibb_dt_init write register %x failed rc = %d\n", REG_IBB_MODULE_RDY, rc); return rc; } } + if (of_property_read_bool(of_node, + "qcom,qpnp-ibb-enable-pfm-mode")) { + rc = qpnp_ibb_pfm_mode_enable(labibb, of_node); + if (rc < 0) + return rc; + } + + if (labibb->pbs_control) { + rc = qpnp_labibb_pbs_mode_enable(labibb, of_node); + if (rc < 0) + return rc; + } + if (init_data->constraints.name) { rdesc->owner = THIS_MODULE; rdesc->type = REGULATOR_VOLTAGE; @@ -2835,9 +3618,9 @@ static int qpnp_labibb_check_ttw_supported(struct qpnp_labibb *labibb) switch (labibb->pmic_rev_id->pmic_subtype) { case PMI8996_SUBTYPE: - rc = qpnp_labibb_read(labibb, &val, - labibb->ibb_base + REG_IBB_REVISION4, 1); - if (rc) { + rc = qpnp_labibb_read(labibb, labibb->ibb_base + + REG_IBB_REVISION4, &val, 1); + if (rc < 0) { pr_err("qpnp_labibb_read register %x failed rc = %d\n", REG_IBB_REVISION4, rc); return rc; @@ -2891,6 +3674,7 @@ static int qpnp_labibb_regulator_probe(struct platform_device *pdev) mutex_init(&(labibb->lab_vreg.lab_mutex)); mutex_init(&(labibb->ibb_vreg.ibb_mutex)); + mutex_init(&(labibb->bus_mutex)); revid_dev_node = of_parse_phandle(labibb->dev->of_node, "qcom,pmic-revid", 0); @@ -2905,21 +3689,33 @@ static int qpnp_labibb_regulator_probe(struct platform_device *pdev) return -EPROBE_DEFER; } - rc = of_property_read_string(labibb->dev->of_node, - "qcom,qpnp-labibb-mode", &mode_name); - if (!rc) { - if (strcmp("lcd", mode_name) == 0) { - labibb->mode = QPNP_LABIBB_LCD_MODE; - } else if (strcmp("amoled", mode_name) == 0) { - labibb->mode = QPNP_LABIBB_AMOLED_MODE; + if (labibb->pmic_rev_id->pmic_subtype == PM660L_SUBTYPE) { + labibb->ibb_ver_ops = &ibb_ops_v2; + labibb->lab_ver_ops = &lab_ops_v2; + } else { + labibb->ibb_ver_ops = &ibb_ops_v1; + labibb->lab_ver_ops = &lab_ops_v1; + } + + if (labibb->pmic_rev_id->pmic_subtype == PM660L_SUBTYPE) { + labibb->mode = QPNP_LABIBB_AMOLED_MODE; + } else { + rc = of_property_read_string(labibb->dev->of_node, + "qcom,qpnp-labibb-mode", &mode_name); + if (!rc) { + if (strcmp("lcd", mode_name) == 0) { + labibb->mode = QPNP_LABIBB_LCD_MODE; + } else if (strcmp("amoled", mode_name) == 0) { + labibb->mode = QPNP_LABIBB_AMOLED_MODE; + } else { + pr_err("Invalid device property in qcom,qpnp-labibb-mode: %s\n", + mode_name); + return -EINVAL; + } } else { - pr_err("Invalid device property in qcom,qpnp-labibb-mode: %s\n", - mode_name); - return -EINVAL; + pr_err("qpnp_labibb: qcom,qpnp-labibb-mode is missing.\n"); + return rc; } - } else { - pr_err("qpnp_labibb: qcom,qpnp-labibb-mode is missing.\n"); - return rc; } labibb->standalone = of_property_read_bool(labibb->dev->of_node, @@ -2937,6 +3733,9 @@ static int qpnp_labibb_regulator_probe(struct platform_device *pdev) labibb->swire_control = of_property_read_bool(labibb->dev->of_node, "qcom,swire-control"); + + labibb->pbs_control = of_property_read_bool(labibb->dev->of_node, + "qcom,pbs-control"); if (labibb->swire_control && labibb->mode != QPNP_LABIBB_AMOLED_MODE) { pr_err("Invalid mode for SWIRE control\n"); return -EINVAL; @@ -2950,14 +3749,14 @@ static int qpnp_labibb_regulator_probe(struct platform_device *pdev) rc = of_property_read_u32(labibb->dev->of_node, "qcom,swire-2nd-cmd-delay", &labibb->swire_2nd_cmd_delay); - if (rc) + if (rc < 0) labibb->swire_2nd_cmd_delay = SWIRE_DEFAULT_2ND_CMD_DLY_MS; rc = of_property_read_u32(labibb->dev->of_node, "qcom,swire-ibb-ps-enable-delay", &labibb->swire_ibb_ps_enable_delay); - if (rc) + if (rc < 0) labibb->swire_ibb_ps_enable_delay = SWIRE_DEFAULT_IBB_PS_ENABLE_DLY_MS; } @@ -2976,16 +3775,16 @@ static int qpnp_labibb_regulator_probe(struct platform_device *pdev) return rc; } - rc = qpnp_labibb_read(labibb, &revision, base + REG_REVISION_2, - 1); - if (rc) { + rc = qpnp_labibb_read(labibb, base + REG_REVISION_2, + &revision, 1); + if (rc < 0) { pr_err("Reading REVISION_2 failed rc=%d\n", rc); goto fail_registration; } - rc = qpnp_labibb_read(labibb, &type, - base + REG_PERPH_TYPE, 1); - if (rc) { + rc = qpnp_labibb_read(labibb, base + REG_PERPH_TYPE, + &type, 1); + if (rc < 0) { pr_err("Peripheral type read failed rc=%d\n", rc); goto fail_registration; } @@ -3001,7 +3800,7 @@ static int qpnp_labibb_regulator_probe(struct platform_device *pdev) goto fail_registration; } rc = register_qpnp_lab_regulator(labibb, child); - if (rc) + if (rc < 0) goto fail_registration; break; @@ -3009,7 +3808,7 @@ static int qpnp_labibb_regulator_probe(struct platform_device *pdev) labibb->ibb_base = base; labibb->ibb_dig_major = revision; rc = register_qpnp_ibb_regulator(labibb, child); - if (rc) + if (rc < 0) goto fail_registration; break; @@ -3023,13 +3822,16 @@ static int qpnp_labibb_regulator_probe(struct platform_device *pdev) if (labibb->ttw_en) { rc = qpnp_labibb_check_ttw_supported(labibb); - if (rc) { + if (rc < 0) { pr_err("pmic revision check failed for TTW rc=%d\n", rc); goto fail_registration; } } dev_set_drvdata(&pdev->dev, labibb); + pr_info("LAB/IBB registered successfully, lab_vreg enable=%d ibb_vreg enable=%d\n", + labibb->lab_vreg.vreg_enabled, + labibb->ibb_vreg.vreg_enabled); return 0; |