Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge series "Really implement Qualcomm LAB/IBB regulators" from AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>:

Okay, the title may be a little "aggressive"? However, the qcom-labibb
driver wasn't really .. doing much.
The current form of this driver is only taking care of enabling or
disabling the regulators, which is pretty useless if they were not
pre-set from the bootloader, which sets them only if continuous
splash is enabled.
Moreover, some bootloaders are setting a higher voltage and/or a higher
current limit compared to what's actually required by the attached
hardware (which is, in 99.9% of the cases, a display) and this produces
a higher power consumption, higher heat output and a risk of actually
burning the display if kept up for a very long time: for example, this
is true on at least some Sony Xperia MSM8998 (Yoshino platform) and
especially on some Sony Xperia SDM845 (Tama platform) smartphones.

In any case, the main reason why this change was necessary for us is
that, during the bringup of Sony Xperia MSM8998 phones, we had an issue
with the bootloader not turning on the display and not setting the lab
and ibb regulators before booting the kernel, making it impossible to
powerup the display.

With this said, this patchset enables setting voltage, current limiting,
overcurrent and short-circuit protection.. and others, on the LAB/IBB
regulators.
Each commit in this patch series provides as many informations as
possible about what's going on and testing methodology.

Changes in v4:
- Remove already applied commit
- Add commit to switch to regulator_{list,map}_voltage_linear
which in v3 got squashed in the commit that got removed in v4.

Changes in v3:
- Improved check for PBS disable and short-circuit condition:
during the testing of short-circuit, coincidentally another
register reading zero on the interesting bit was probed,
which didn't trigger a malfunction of the SC logic, but was
also wrong.
After the change, the short-circuit test was re-done in the
same way as described in the commit that is implementing it.
- From Bjorn Andersson review:
- Improved documentation about over-current and short-circuit
protection in the driver
- Improved maintainability of qcom_labibb_sc_recovery_worker()
- Flipped around check for PBS vreg disabled in for loop of
function labibb_sc_err_handler()
- From Mark Brown (forgotten in v2):
- Changed regulator_{list,map}_voltage_linear_range usages to
regulator_{list,map}_voltage_linear (and fixed regulator
descs to reflect the change).

Changes in v2:
- From Mark Brown review:
- Replaced some if branches with switch statements
- Moved irq get and request in probe function
- Changed short conditionals to full ones
- Removed useless check for ocp_irq_requested
- Fixed issues with YAML documentation

AngeloGioacchino Del Regno (7):
regulator: qcom-labibb: Switch voltage ops from linear_range to linear
regulator: qcom-labibb: Implement current limiting
regulator: qcom-labibb: Implement pull-down, softstart, active
discharge
dt-bindings: regulator: qcom-labibb: Document soft start properties
regulator: qcom-labibb: Implement short-circuit and over-current IRQs
dt-bindings: regulator: qcom-labibb: Document SCP/OCP interrupts
arm64: dts: pmi8998: Add the right interrupts for LAB/IBB SCP and OCP

.../regulator/qcom-labibb-regulator.yaml | 30 +-
arch/arm64/boot/dts/qcom/pmi8998.dtsi | 8 +-
drivers/regulator/qcom-labibb-regulator.c | 720 +++++++++++++++++-
3 files changed, 735 insertions(+), 23 deletions(-)

--
2.30.0

+729 -21
+22 -8
Documentation/devicetree/bindings/regulator/qcom-labibb-regulator.yaml
··· 22 22 type: object 23 23 24 24 properties: 25 + qcom,soft-start-us: 26 + $ref: /schemas/types.yaml#/definitions/uint32 27 + description: Regulator soft start time in microseconds. 28 + enum: [200, 400, 600, 800] 29 + default: 200 25 30 26 31 interrupts: 27 - maxItems: 1 32 + minItems: 1 33 + maxItems: 2 28 34 description: 29 - Short-circuit interrupt for lab. 35 + Short-circuit and over-current interrupts for lab. 30 36 31 37 required: 32 38 - interrupts ··· 41 35 type: object 42 36 43 37 properties: 38 + qcom,discharge-resistor-kohms: 39 + $ref: /schemas/types.yaml#/definitions/uint32 40 + description: Discharge resistor value in KiloOhms. 41 + enum: [300, 64, 32, 16] 42 + default: 300 44 43 45 44 interrupts: 46 - maxItems: 1 45 + minItems: 1 46 + maxItems: 2 47 47 description: 48 - Short-circuit interrupt for lab. 48 + Short-circuit and over-current interrupts for ibb. 49 49 50 50 required: 51 51 - interrupts ··· 69 57 compatible = "qcom,pmi8998-lab-ibb"; 70 58 71 59 lab { 72 - interrupts = <0x3 0x0 IRQ_TYPE_EDGE_RISING>; 73 - interrupt-names = "sc-err"; 60 + interrupts = <0x3 0xde 0x1 IRQ_TYPE_EDGE_RISING>, 61 + <0x3 0xde 0x0 IRQ_TYPE_LEVEL_LOW>; 62 + interrupt-names = "sc-err", "ocp"; 74 63 }; 75 64 76 65 ibb { 77 - interrupts = <0x3 0x2 IRQ_TYPE_EDGE_RISING>; 78 - interrupt-names = "sc-err"; 66 + interrupts = <0x3 0xdc 0x2 IRQ_TYPE_EDGE_RISING>, 67 + <0x3 0xdc 0x0 IRQ_TYPE_LEVEL_LOW>; 68 + interrupt-names = "sc-err", "ocp"; 79 69 }; 80 70 }; 81 71
+707 -13
drivers/regulator/qcom-labibb-regulator.c
··· 17 17 18 18 #define PMI8998_LAB_REG_BASE 0xde00 19 19 #define PMI8998_IBB_REG_BASE 0xdc00 20 + #define PMI8998_IBB_LAB_REG_OFFSET 0x200 20 21 21 22 #define REG_LABIBB_STATUS1 0x08 23 + #define LABIBB_STATUS1_SC_BIT BIT(6) 24 + #define LABIBB_STATUS1_VREG_OK_BIT BIT(7) 25 + 26 + #define REG_LABIBB_INT_SET_TYPE 0x11 27 + #define REG_LABIBB_INT_POLARITY_HIGH 0x12 28 + #define REG_LABIBB_INT_POLARITY_LOW 0x13 29 + #define REG_LABIBB_INT_LATCHED_CLR 0x14 30 + #define REG_LABIBB_INT_EN_SET 0x15 31 + #define REG_LABIBB_INT_EN_CLR 0x16 32 + #define LABIBB_INT_VREG_OK BIT(0) 33 + #define LABIBB_INT_VREG_TYPE_LEVEL 0 22 34 23 35 #define REG_LABIBB_VOLTAGE 0x41 24 36 #define LABIBB_VOLTAGE_OVERRIDE_EN BIT(7) ··· 38 26 #define IBB_VOLTAGE_SET_MASK GENMASK(5, 0) 39 27 40 28 #define REG_LABIBB_ENABLE_CTL 0x46 41 - #define LABIBB_STATUS1_VREG_OK_BIT BIT(7) 42 - #define LABIBB_CONTROL_ENABLE BIT(7) 29 + #define LABIBB_CONTROL_ENABLE BIT(7) 30 + 31 + #define REG_LABIBB_PD_CTL 0x47 32 + #define LAB_PD_CTL_MASK GENMASK(1, 0) 33 + #define IBB_PD_CTL_MASK (BIT(0) | BIT(7)) 34 + #define LAB_PD_CTL_STRONG_PULL BIT(0) 35 + #define IBB_PD_CTL_HALF_STRENGTH BIT(0) 36 + #define IBB_PD_CTL_EN BIT(7) 37 + 38 + #define REG_LABIBB_CURRENT_LIMIT 0x4b 39 + #define LAB_CURRENT_LIMIT_MASK GENMASK(2, 0) 40 + #define IBB_CURRENT_LIMIT_MASK GENMASK(4, 0) 41 + #define LAB_CURRENT_LIMIT_OVERRIDE_EN BIT(3) 42 + #define LABIBB_CURRENT_LIMIT_EN BIT(7) 43 + 44 + #define REG_IBB_PWRUP_PWRDN_CTL_1 0x58 45 + #define IBB_CTL_1_DISCHARGE_EN BIT(2) 46 + 47 + #define REG_LABIBB_SOFT_START_CTL 0x5f 48 + #define REG_LABIBB_SEC_ACCESS 0xd0 49 + #define LABIBB_SEC_UNLOCK_CODE 0xa5 43 50 44 51 #define LAB_ENABLE_CTL_MASK BIT(7) 45 52 #define IBB_ENABLE_CTL_MASK (BIT(7) | BIT(6)) ··· 67 36 #define LAB_ENABLE_TIME (LABIBB_OFF_ON_DELAY * 2) 68 37 #define IBB_ENABLE_TIME (LABIBB_OFF_ON_DELAY * 10) 69 38 #define LABIBB_POLL_ENABLED_TIME 1000 39 + #define OCP_RECOVERY_INTERVAL_MS 500 40 + #define SC_RECOVERY_INTERVAL_MS 250 41 + #define LABIBB_MAX_OCP_COUNT 4 42 + #define LABIBB_MAX_SC_COUNT 3 43 + #define LABIBB_MAX_FATAL_COUNT 2 44 + 45 + struct labibb_current_limits { 46 + u32 uA_min; 47 + u32 uA_step; 48 + u8 ovr_val; 49 + }; 70 50 71 51 struct labibb_regulator { 72 52 struct regulator_desc desc; 73 53 struct device *dev; 74 54 struct regmap *regmap; 75 55 struct regulator_dev *rdev; 56 + struct labibb_current_limits uA_limits; 57 + struct delayed_work ocp_recovery_work; 58 + struct delayed_work sc_recovery_work; 76 59 u16 base; 77 60 u8 type; 61 + u8 dischg_sel; 62 + u8 soft_start_sel; 63 + int sc_irq; 64 + int sc_count; 65 + int ocp_irq; 66 + int ocp_irq_count; 67 + int fatal_count; 78 68 }; 79 69 80 70 struct labibb_regulator_data { ··· 105 53 const struct regulator_desc *desc; 106 54 }; 107 55 56 + static int qcom_labibb_ocp_hw_enable(struct regulator_dev *rdev) 57 + { 58 + struct labibb_regulator *vreg = rdev_get_drvdata(rdev); 59 + int ret; 60 + 61 + /* Clear irq latch status to avoid spurious event */ 62 + ret = regmap_update_bits(rdev->regmap, 63 + vreg->base + REG_LABIBB_INT_LATCHED_CLR, 64 + LABIBB_INT_VREG_OK, 1); 65 + if (ret) 66 + return ret; 67 + 68 + /* Enable OCP HW interrupt */ 69 + return regmap_update_bits(rdev->regmap, 70 + vreg->base + REG_LABIBB_INT_EN_SET, 71 + LABIBB_INT_VREG_OK, 1); 72 + } 73 + 74 + static int qcom_labibb_ocp_hw_disable(struct regulator_dev *rdev) 75 + { 76 + struct labibb_regulator *vreg = rdev_get_drvdata(rdev); 77 + 78 + return regmap_update_bits(rdev->regmap, 79 + vreg->base + REG_LABIBB_INT_EN_CLR, 80 + LABIBB_INT_VREG_OK, 1); 81 + } 82 + 83 + /** 84 + * qcom_labibb_check_ocp_status - Check the Over-Current Protection status 85 + * @vreg: Main driver structure 86 + * 87 + * This function checks the STATUS1 register for the VREG_OK bit: if it is 88 + * set, then there is no Over-Current event. 89 + * 90 + * Returns: Zero if there is no over-current, 1 if in over-current or 91 + * negative number for error 92 + */ 93 + static int qcom_labibb_check_ocp_status(struct labibb_regulator *vreg) 94 + { 95 + u32 cur_status; 96 + int ret; 97 + 98 + ret = regmap_read(vreg->rdev->regmap, vreg->base + REG_LABIBB_STATUS1, 99 + &cur_status); 100 + if (ret) 101 + return ret; 102 + 103 + return !(cur_status & LABIBB_STATUS1_VREG_OK_BIT); 104 + } 105 + 106 + /** 107 + * qcom_labibb_ocp_recovery_worker - Handle OCP event 108 + * @work: OCP work structure 109 + * 110 + * This is the worker function to handle the Over Current Protection 111 + * hardware event; This will check if the hardware is still 112 + * signaling an over-current condition and will eventually stop 113 + * the regulator if such condition is still signaled after 114 + * LABIBB_MAX_OCP_COUNT times. 115 + * 116 + * If the driver that is consuming the regulator did not take action 117 + * for the OCP condition, or the hardware did not stabilize, a cut 118 + * of the LAB and IBB regulators will be forced (regulators will be 119 + * disabled). 120 + * 121 + * As last, if the writes to shut down the LAB/IBB regulators fail 122 + * for more than LABIBB_MAX_FATAL_COUNT, then a kernel panic will be 123 + * triggered, as a last resort to protect the hardware from burning; 124 + * this, however, is expected to never happen, but this is kept to 125 + * try to further ensure that we protect the hardware at all costs. 126 + */ 127 + static void qcom_labibb_ocp_recovery_worker(struct work_struct *work) 128 + { 129 + struct labibb_regulator *vreg; 130 + const struct regulator_ops *ops; 131 + int ret; 132 + 133 + vreg = container_of(work, struct labibb_regulator, 134 + ocp_recovery_work.work); 135 + ops = vreg->rdev->desc->ops; 136 + 137 + if (vreg->ocp_irq_count >= LABIBB_MAX_OCP_COUNT) { 138 + /* 139 + * If we tried to disable the regulator multiple times but 140 + * we kept failing, there's only one last hope to save our 141 + * hardware from the death: raise a kernel bug, reboot and 142 + * hope that the bootloader kindly saves us. This, though 143 + * is done only as paranoid checking, because failing the 144 + * regmap write to disable the vreg is almost impossible, 145 + * since we got here after multiple regmap R/W. 146 + */ 147 + BUG_ON(vreg->fatal_count > LABIBB_MAX_FATAL_COUNT); 148 + dev_err(&vreg->rdev->dev, "LABIBB: CRITICAL: Disabling regulator\n"); 149 + 150 + /* Disable the regulator immediately to avoid damage */ 151 + ret = ops->disable(vreg->rdev); 152 + if (ret) { 153 + vreg->fatal_count++; 154 + goto reschedule; 155 + } 156 + enable_irq(vreg->ocp_irq); 157 + vreg->fatal_count = 0; 158 + return; 159 + } 160 + 161 + ret = qcom_labibb_check_ocp_status(vreg); 162 + if (ret != 0) { 163 + vreg->ocp_irq_count++; 164 + goto reschedule; 165 + } 166 + 167 + ret = qcom_labibb_ocp_hw_enable(vreg->rdev); 168 + if (ret) { 169 + /* We cannot trust it without OCP enabled. */ 170 + dev_err(vreg->dev, "Cannot enable OCP IRQ\n"); 171 + vreg->ocp_irq_count++; 172 + goto reschedule; 173 + } 174 + 175 + enable_irq(vreg->ocp_irq); 176 + /* Everything went fine: reset the OCP count! */ 177 + vreg->ocp_irq_count = 0; 178 + return; 179 + 180 + reschedule: 181 + mod_delayed_work(system_wq, &vreg->ocp_recovery_work, 182 + msecs_to_jiffies(OCP_RECOVERY_INTERVAL_MS)); 183 + } 184 + 185 + /** 186 + * qcom_labibb_ocp_isr - Interrupt routine for OverCurrent Protection 187 + * @irq: Interrupt number 188 + * @chip: Main driver structure 189 + * 190 + * Over Current Protection (OCP) will signal to the client driver 191 + * that an over-current event has happened and then will schedule 192 + * a recovery worker. 193 + * 194 + * Disabling and eventually re-enabling the regulator is expected 195 + * to be done by the driver, as some hardware may be triggering an 196 + * over-current condition only at first initialization or it may 197 + * be expected only for a very brief amount of time, after which 198 + * the attached hardware may be expected to stabilize its current 199 + * draw. 200 + * 201 + * Returns: IRQ_HANDLED for success or IRQ_NONE for failure. 202 + */ 203 + static irqreturn_t qcom_labibb_ocp_isr(int irq, void *chip) 204 + { 205 + struct labibb_regulator *vreg = chip; 206 + const struct regulator_ops *ops = vreg->rdev->desc->ops; 207 + int ret; 208 + 209 + /* If the regulator is not enabled, this is a fake event */ 210 + if (!ops->is_enabled(vreg->rdev)) 211 + return 0; 212 + 213 + /* If we tried to recover for too many times it's not getting better */ 214 + if (vreg->ocp_irq_count > LABIBB_MAX_OCP_COUNT) 215 + return IRQ_NONE; 216 + 217 + /* 218 + * If we (unlikely) can't read this register, to prevent hardware 219 + * damage at all costs, we assume that the overcurrent event was 220 + * real; Moreover, if the status register is not signaling OCP, 221 + * it was a spurious event, so it's all ok. 222 + */ 223 + ret = qcom_labibb_check_ocp_status(vreg); 224 + if (ret == 0) { 225 + vreg->ocp_irq_count = 0; 226 + goto end; 227 + } 228 + vreg->ocp_irq_count++; 229 + 230 + /* 231 + * Disable the interrupt temporarily, or it will fire continuously; 232 + * we will re-enable it in the recovery worker function. 233 + */ 234 + disable_irq(irq); 235 + 236 + /* Warn the user for overcurrent */ 237 + dev_warn(vreg->dev, "Over-Current interrupt fired!\n"); 238 + 239 + /* Disable the interrupt to avoid hogging */ 240 + ret = qcom_labibb_ocp_hw_disable(vreg->rdev); 241 + if (ret) 242 + goto end; 243 + 244 + /* Signal overcurrent event to drivers */ 245 + regulator_notifier_call_chain(vreg->rdev, 246 + REGULATOR_EVENT_OVER_CURRENT, NULL); 247 + 248 + end: 249 + /* Schedule the recovery work */ 250 + schedule_delayed_work(&vreg->ocp_recovery_work, 251 + msecs_to_jiffies(OCP_RECOVERY_INTERVAL_MS)); 252 + if (ret) 253 + return IRQ_NONE; 254 + 255 + return IRQ_HANDLED; 256 + } 257 + 258 + static int qcom_labibb_set_ocp(struct regulator_dev *rdev) 259 + { 260 + struct labibb_regulator *vreg = rdev_get_drvdata(rdev); 261 + char *ocp_irq_name; 262 + u32 irq_flags = IRQF_ONESHOT; 263 + int irq_trig_low, ret; 264 + 265 + /* If there is no OCP interrupt, there's nothing to set */ 266 + if (vreg->ocp_irq <= 0) 267 + return -EINVAL; 268 + 269 + ocp_irq_name = devm_kasprintf(vreg->dev, GFP_KERNEL, "%s-over-current", 270 + vreg->desc.name); 271 + if (!ocp_irq_name) 272 + return -ENOMEM; 273 + 274 + /* IRQ polarities - LAB: trigger-low, IBB: trigger-high */ 275 + switch (vreg->type) { 276 + case QCOM_LAB_TYPE: 277 + irq_flags |= IRQF_TRIGGER_LOW; 278 + irq_trig_low = 1; 279 + break; 280 + case QCOM_IBB_TYPE: 281 + irq_flags |= IRQF_TRIGGER_HIGH; 282 + irq_trig_low = 0; 283 + break; 284 + default: 285 + return -EINVAL; 286 + } 287 + 288 + /* Activate OCP HW level interrupt */ 289 + ret = regmap_update_bits(rdev->regmap, 290 + vreg->base + REG_LABIBB_INT_SET_TYPE, 291 + LABIBB_INT_VREG_OK, 292 + LABIBB_INT_VREG_TYPE_LEVEL); 293 + if (ret) 294 + return ret; 295 + 296 + /* Set OCP interrupt polarity */ 297 + ret = regmap_update_bits(rdev->regmap, 298 + vreg->base + REG_LABIBB_INT_POLARITY_HIGH, 299 + LABIBB_INT_VREG_OK, !irq_trig_low); 300 + if (ret) 301 + return ret; 302 + ret = regmap_update_bits(rdev->regmap, 303 + vreg->base + REG_LABIBB_INT_POLARITY_LOW, 304 + LABIBB_INT_VREG_OK, irq_trig_low); 305 + if (ret) 306 + return ret; 307 + 308 + ret = qcom_labibb_ocp_hw_enable(rdev); 309 + if (ret) 310 + return ret; 311 + 312 + return devm_request_threaded_irq(vreg->dev, vreg->ocp_irq, NULL, 313 + qcom_labibb_ocp_isr, irq_flags, 314 + ocp_irq_name, vreg); 315 + } 316 + 317 + /** 318 + * qcom_labibb_check_sc_status - Check the Short Circuit Protection status 319 + * @vreg: Main driver structure 320 + * 321 + * This function checks the STATUS1 register on both LAB and IBB regulators 322 + * for the ShortCircuit bit: if it is set on *any* of them, then we have 323 + * experienced a short-circuit event. 324 + * 325 + * Returns: Zero if there is no short-circuit, 1 if in short-circuit or 326 + * negative number for error 327 + */ 328 + static int qcom_labibb_check_sc_status(struct labibb_regulator *vreg) 329 + { 330 + u32 ibb_status, ibb_reg, lab_status, lab_reg; 331 + int ret; 332 + 333 + /* We have to work on both regulators due to PBS... */ 334 + lab_reg = ibb_reg = vreg->base + REG_LABIBB_STATUS1; 335 + if (vreg->type == QCOM_LAB_TYPE) 336 + ibb_reg -= PMI8998_IBB_LAB_REG_OFFSET; 337 + else 338 + lab_reg += PMI8998_IBB_LAB_REG_OFFSET; 339 + 340 + ret = regmap_read(vreg->rdev->regmap, lab_reg, &lab_status); 341 + if (ret) 342 + return ret; 343 + ret = regmap_read(vreg->rdev->regmap, ibb_reg, &ibb_status); 344 + if (ret) 345 + return ret; 346 + 347 + return !!(lab_status & LABIBB_STATUS1_SC_BIT) || 348 + !!(ibb_status & LABIBB_STATUS1_SC_BIT); 349 + } 350 + 351 + /** 352 + * qcom_labibb_sc_recovery_worker - Handle Short Circuit event 353 + * @work: SC work structure 354 + * 355 + * This is the worker function to handle the Short Circuit Protection 356 + * hardware event; This will check if the hardware is still 357 + * signaling a short-circuit condition and will eventually never 358 + * re-enable the regulator if such condition is still signaled after 359 + * LABIBB_MAX_SC_COUNT times. 360 + * 361 + * If the driver that is consuming the regulator did not take action 362 + * for the SC condition, or the hardware did not stabilize, this 363 + * worker will stop rescheduling, leaving the regulators disabled 364 + * as already done by the Portable Batch System (PBS). 365 + * 366 + * Returns: IRQ_HANDLED for success or IRQ_NONE for failure. 367 + */ 368 + static void qcom_labibb_sc_recovery_worker(struct work_struct *work) 369 + { 370 + struct labibb_regulator *vreg; 371 + const struct regulator_ops *ops; 372 + u32 lab_reg, ibb_reg, lab_val, ibb_val, val; 373 + bool pbs_cut = false; 374 + int i, sc, ret; 375 + 376 + vreg = container_of(work, struct labibb_regulator, 377 + sc_recovery_work.work); 378 + ops = vreg->rdev->desc->ops; 379 + 380 + /* 381 + * If we tried to check the regulator status multiple times but we 382 + * kept failing, then just bail out, as the Portable Batch System 383 + * (PBS) will disable the vregs for us, preventing hardware damage. 384 + */ 385 + if (vreg->fatal_count > LABIBB_MAX_FATAL_COUNT) 386 + return; 387 + 388 + /* Too many short-circuit events. Throw in the towel. */ 389 + if (vreg->sc_count > LABIBB_MAX_SC_COUNT) 390 + return; 391 + 392 + /* 393 + * The Portable Batch System (PBS) automatically disables LAB 394 + * and IBB when a short-circuit event is detected, so we have to 395 + * check and work on both of them at the same time. 396 + */ 397 + lab_reg = ibb_reg = vreg->base + REG_LABIBB_ENABLE_CTL; 398 + if (vreg->type == QCOM_LAB_TYPE) 399 + ibb_reg -= PMI8998_IBB_LAB_REG_OFFSET; 400 + else 401 + lab_reg += PMI8998_IBB_LAB_REG_OFFSET; 402 + 403 + sc = qcom_labibb_check_sc_status(vreg); 404 + if (sc) 405 + goto reschedule; 406 + 407 + for (i = 0; i < LABIBB_MAX_SC_COUNT; i++) { 408 + ret = regmap_read(vreg->regmap, lab_reg, &lab_val); 409 + if (ret) { 410 + vreg->fatal_count++; 411 + goto reschedule; 412 + } 413 + 414 + ret = regmap_read(vreg->regmap, ibb_reg, &ibb_val); 415 + if (ret) { 416 + vreg->fatal_count++; 417 + goto reschedule; 418 + } 419 + val = lab_val & ibb_val; 420 + 421 + if (!(val & LABIBB_CONTROL_ENABLE)) { 422 + pbs_cut = true; 423 + break; 424 + } 425 + usleep_range(5000, 6000); 426 + } 427 + if (pbs_cut) 428 + goto reschedule; 429 + 430 + 431 + /* 432 + * If we have reached this point, we either have successfully 433 + * recovered from the SC condition or we had a spurious SC IRQ, 434 + * which means that we can re-enable the regulators, if they 435 + * have ever been disabled by the PBS. 436 + */ 437 + ret = ops->enable(vreg->rdev); 438 + if (ret) 439 + goto reschedule; 440 + 441 + /* Everything went fine: reset the OCP count! */ 442 + vreg->sc_count = 0; 443 + enable_irq(vreg->sc_irq); 444 + return; 445 + 446 + reschedule: 447 + /* 448 + * Now that we have done basic handling of the short-circuit, 449 + * reschedule this worker in the regular system workqueue, as 450 + * taking action is not truly urgent anymore. 451 + */ 452 + vreg->sc_count++; 453 + mod_delayed_work(system_wq, &vreg->sc_recovery_work, 454 + msecs_to_jiffies(SC_RECOVERY_INTERVAL_MS)); 455 + } 456 + 457 + /** 458 + * qcom_labibb_sc_isr - Interrupt routine for Short Circuit Protection 459 + * @irq: Interrupt number 460 + * @chip: Main driver structure 461 + * 462 + * Short Circuit Protection (SCP) will signal to the client driver 463 + * that a regulation-out event has happened and then will schedule 464 + * a recovery worker. 465 + * 466 + * The LAB and IBB regulators will be automatically disabled by the 467 + * Portable Batch System (PBS) and they will be enabled again by 468 + * the worker function if the hardware stops signaling the short 469 + * circuit event. 470 + * 471 + * Returns: IRQ_HANDLED for success or IRQ_NONE for failure. 472 + */ 473 + static irqreturn_t qcom_labibb_sc_isr(int irq, void *chip) 474 + { 475 + struct labibb_regulator *vreg = chip; 476 + 477 + if (vreg->sc_count > LABIBB_MAX_SC_COUNT) 478 + return IRQ_NONE; 479 + 480 + /* Warn the user for short circuit */ 481 + dev_warn(vreg->dev, "Short-Circuit interrupt fired!\n"); 482 + 483 + /* 484 + * Disable the interrupt temporarily, or it will fire continuously; 485 + * we will re-enable it in the recovery worker function. 486 + */ 487 + disable_irq(irq); 488 + 489 + /* Signal out of regulation event to drivers */ 490 + regulator_notifier_call_chain(vreg->rdev, 491 + REGULATOR_EVENT_REGULATION_OUT, NULL); 492 + 493 + /* Schedule the short-circuit handling as high-priority work */ 494 + mod_delayed_work(system_highpri_wq, &vreg->sc_recovery_work, 495 + msecs_to_jiffies(SC_RECOVERY_INTERVAL_MS)); 496 + return IRQ_HANDLED; 497 + } 498 + 499 + 500 + static int qcom_labibb_set_current_limit(struct regulator_dev *rdev, 501 + int min_uA, int max_uA) 502 + { 503 + struct labibb_regulator *vreg = rdev_get_drvdata(rdev); 504 + struct regulator_desc *desc = &vreg->desc; 505 + struct labibb_current_limits *lim = &vreg->uA_limits; 506 + u32 mask, val; 507 + int i, ret, sel = -1; 508 + 509 + if (min_uA < lim->uA_min || max_uA < lim->uA_min) 510 + return -EINVAL; 511 + 512 + for (i = 0; i < desc->n_current_limits; i++) { 513 + int uA_limit = (lim->uA_step * i) + lim->uA_min; 514 + 515 + if (max_uA >= uA_limit && min_uA <= uA_limit) 516 + sel = i; 517 + } 518 + if (sel < 0) 519 + return -EINVAL; 520 + 521 + /* Current limit setting needs secure access */ 522 + ret = regmap_write(vreg->regmap, vreg->base + REG_LABIBB_SEC_ACCESS, 523 + LABIBB_SEC_UNLOCK_CODE); 524 + if (ret) 525 + return ret; 526 + 527 + mask = desc->csel_mask | lim->ovr_val; 528 + mask |= LABIBB_CURRENT_LIMIT_EN; 529 + val = (u32)sel | lim->ovr_val; 530 + val |= LABIBB_CURRENT_LIMIT_EN; 531 + 532 + return regmap_update_bits(vreg->regmap, desc->csel_reg, mask, val); 533 + } 534 + 535 + static int qcom_labibb_get_current_limit(struct regulator_dev *rdev) 536 + { 537 + struct labibb_regulator *vreg = rdev_get_drvdata(rdev); 538 + struct regulator_desc *desc = &vreg->desc; 539 + struct labibb_current_limits *lim = &vreg->uA_limits; 540 + unsigned int cur_step; 541 + int ret; 542 + 543 + ret = regmap_read(vreg->regmap, desc->csel_reg, &cur_step); 544 + if (ret) 545 + return ret; 546 + cur_step &= desc->csel_mask; 547 + 548 + return (cur_step * lim->uA_step) + lim->uA_min; 549 + } 550 + 551 + static int qcom_labibb_set_soft_start(struct regulator_dev *rdev) 552 + { 553 + struct labibb_regulator *vreg = rdev_get_drvdata(rdev); 554 + u32 val = 0; 555 + 556 + if (vreg->type == QCOM_IBB_TYPE) 557 + val = vreg->dischg_sel; 558 + else 559 + val = vreg->soft_start_sel; 560 + 561 + return regmap_write(rdev->regmap, rdev->desc->soft_start_reg, val); 562 + } 563 + 564 + static int qcom_labibb_get_table_sel(const int *table, int sz, u32 value) 565 + { 566 + int i; 567 + 568 + for (i = 0; i < sz; i++) 569 + if (table[i] == value) 570 + return i; 571 + return -EINVAL; 572 + } 573 + 574 + /* IBB discharge resistor values in KOhms */ 575 + static const int dischg_resistor_values[] = { 300, 64, 32, 16 }; 576 + 577 + /* Soft start time in microseconds */ 578 + static const int soft_start_values[] = { 200, 400, 600, 800 }; 579 + 580 + static int qcom_labibb_of_parse_cb(struct device_node *np, 581 + const struct regulator_desc *desc, 582 + struct regulator_config *config) 583 + { 584 + struct labibb_regulator *vreg = config->driver_data; 585 + u32 dischg_kohms, soft_start_time; 586 + int ret; 587 + 588 + ret = of_property_read_u32(np, "qcom,discharge-resistor-kohms", 589 + &dischg_kohms); 590 + if (ret) 591 + dischg_kohms = 300; 592 + 593 + ret = qcom_labibb_get_table_sel(dischg_resistor_values, 594 + ARRAY_SIZE(dischg_resistor_values), 595 + dischg_kohms); 596 + if (ret < 0) 597 + return ret; 598 + vreg->dischg_sel = (u8)ret; 599 + 600 + ret = of_property_read_u32(np, "qcom,soft-start-us", 601 + &soft_start_time); 602 + if (ret) 603 + soft_start_time = 200; 604 + 605 + ret = qcom_labibb_get_table_sel(soft_start_values, 606 + ARRAY_SIZE(soft_start_values), 607 + soft_start_time); 608 + if (ret < 0) 609 + return ret; 610 + vreg->soft_start_sel = (u8)ret; 611 + 612 + return 0; 613 + } 614 + 108 615 static const struct regulator_ops qcom_labibb_ops = { 109 616 .enable = regulator_enable_regmap, 110 617 .disable = regulator_disable_regmap, 111 618 .is_enabled = regulator_is_enabled_regmap, 112 619 .set_voltage_sel = regulator_set_voltage_sel_regmap, 113 620 .get_voltage_sel = regulator_get_voltage_sel_regmap, 114 - .list_voltage = regulator_list_voltage_linear_range, 115 - .map_voltage = regulator_map_voltage_linear_range, 621 + .list_voltage = regulator_list_voltage_linear, 622 + .map_voltage = regulator_map_voltage_linear, 623 + .set_active_discharge = regulator_set_active_discharge_regmap, 624 + .set_pull_down = regulator_set_pull_down_regmap, 625 + .set_current_limit = qcom_labibb_set_current_limit, 626 + .get_current_limit = qcom_labibb_get_current_limit, 627 + .set_soft_start = qcom_labibb_set_soft_start, 628 + .set_over_current_protection = qcom_labibb_set_ocp, 116 629 }; 117 630 118 631 static const struct regulator_desc pmi8998_lab_desc = { ··· 686 69 .enable_val = LABIBB_CONTROL_ENABLE, 687 70 .enable_time = LAB_ENABLE_TIME, 688 71 .poll_enabled_time = LABIBB_POLL_ENABLED_TIME, 72 + .soft_start_reg = (PMI8998_LAB_REG_BASE + REG_LABIBB_SOFT_START_CTL), 73 + .pull_down_reg = (PMI8998_LAB_REG_BASE + REG_LABIBB_PD_CTL), 74 + .pull_down_mask = LAB_PD_CTL_MASK, 75 + .pull_down_val_on = LAB_PD_CTL_STRONG_PULL, 689 76 .vsel_reg = (PMI8998_LAB_REG_BASE + REG_LABIBB_VOLTAGE), 690 77 .vsel_mask = LAB_VOLTAGE_SET_MASK, 691 78 .apply_reg = (PMI8998_LAB_REG_BASE + REG_LABIBB_VOLTAGE), 692 79 .apply_bit = LABIBB_VOLTAGE_OVERRIDE_EN, 80 + .csel_reg = (PMI8998_LAB_REG_BASE + REG_LABIBB_CURRENT_LIMIT), 81 + .csel_mask = LAB_CURRENT_LIMIT_MASK, 82 + .n_current_limits = 8, 693 83 .off_on_delay = LABIBB_OFF_ON_DELAY, 694 84 .owner = THIS_MODULE, 695 85 .type = REGULATOR_VOLTAGE, 696 - .linear_ranges = (struct linear_range[]) { 697 - REGULATOR_LINEAR_RANGE(4600000, 0, 15, 100000), 698 - }, 699 - .n_linear_ranges = 1, 86 + .min_uV = 4600000, 87 + .uV_step = 100000, 700 88 .n_voltages = 16, 701 89 .ops = &qcom_labibb_ops, 90 + .of_parse_cb = qcom_labibb_of_parse_cb, 702 91 }; 703 92 704 93 static const struct regulator_desc pmi8998_ibb_desc = { ··· 713 90 .enable_val = LABIBB_CONTROL_ENABLE, 714 91 .enable_time = IBB_ENABLE_TIME, 715 92 .poll_enabled_time = LABIBB_POLL_ENABLED_TIME, 93 + .soft_start_reg = (PMI8998_IBB_REG_BASE + REG_LABIBB_SOFT_START_CTL), 94 + .active_discharge_off = 0, 95 + .active_discharge_on = IBB_CTL_1_DISCHARGE_EN, 96 + .active_discharge_mask = IBB_CTL_1_DISCHARGE_EN, 97 + .active_discharge_reg = (PMI8998_IBB_REG_BASE + REG_IBB_PWRUP_PWRDN_CTL_1), 98 + .pull_down_reg = (PMI8998_IBB_REG_BASE + REG_LABIBB_PD_CTL), 99 + .pull_down_mask = IBB_PD_CTL_MASK, 100 + .pull_down_val_on = IBB_PD_CTL_HALF_STRENGTH | IBB_PD_CTL_EN, 716 101 .vsel_reg = (PMI8998_IBB_REG_BASE + REG_LABIBB_VOLTAGE), 717 102 .vsel_mask = IBB_VOLTAGE_SET_MASK, 718 103 .apply_reg = (PMI8998_IBB_REG_BASE + REG_LABIBB_VOLTAGE), 719 104 .apply_bit = LABIBB_VOLTAGE_OVERRIDE_EN, 105 + .csel_reg = (PMI8998_IBB_REG_BASE + REG_LABIBB_CURRENT_LIMIT), 106 + .csel_mask = IBB_CURRENT_LIMIT_MASK, 107 + .n_current_limits = 32, 720 108 .off_on_delay = LABIBB_OFF_ON_DELAY, 721 109 .owner = THIS_MODULE, 722 110 .type = REGULATOR_VOLTAGE, 723 - .linear_ranges = (struct linear_range[]) { 724 - REGULATOR_LINEAR_RANGE(1400000, 0, 63, 100000), 725 - }, 726 - .n_linear_ranges = 1, 111 + .min_uV = 1400000, 112 + .uV_step = 100000, 727 113 .n_voltages = 64, 728 114 .ops = &qcom_labibb_ops, 115 + .of_parse_cb = qcom_labibb_of_parse_cb, 729 116 }; 730 117 731 118 static const struct labibb_regulator_data pmi8998_labibb_data[] = { ··· 755 122 struct labibb_regulator *vreg; 756 123 struct device *dev = &pdev->dev; 757 124 struct regulator_config cfg = {}; 758 - 125 + struct device_node *reg_node; 759 126 const struct of_device_id *match; 760 127 const struct labibb_regulator_data *reg_data; 761 128 struct regmap *reg_regmap; ··· 773 140 return -ENODEV; 774 141 775 142 for (reg_data = match->data; reg_data->name; reg_data++) { 143 + char *sc_irq_name; 144 + int irq = 0; 776 145 777 146 /* Validate if the type of regulator is indeed 778 147 * what's mentioned in DT. ··· 797 162 if (!vreg) 798 163 return -ENOMEM; 799 164 165 + sc_irq_name = devm_kasprintf(dev, GFP_KERNEL, 166 + "%s-short-circuit", 167 + reg_data->name); 168 + if (!sc_irq_name) 169 + return -ENOMEM; 170 + 171 + reg_node = of_get_child_by_name(pdev->dev.of_node, 172 + reg_data->name); 173 + if (!reg_node) 174 + return -EINVAL; 175 + 176 + /* The Short Circuit interrupt is critical */ 177 + irq = of_irq_get_byname(reg_node, "sc-err"); 178 + if (irq <= 0) { 179 + if (irq == 0) 180 + irq = -EINVAL; 181 + 182 + return dev_err_probe(vreg->dev, irq, 183 + "Short-circuit irq not found.\n"); 184 + } 185 + vreg->sc_irq = irq; 186 + 187 + /* OverCurrent Protection IRQ is optional */ 188 + irq = of_irq_get_byname(reg_node, "ocp"); 189 + vreg->ocp_irq = irq; 190 + vreg->ocp_irq_count = 0; 191 + of_node_put(reg_node); 192 + 800 193 vreg->regmap = reg_regmap; 801 194 vreg->dev = dev; 802 195 vreg->base = reg_data->base; 803 196 vreg->type = reg_data->type; 197 + INIT_DELAYED_WORK(&vreg->sc_recovery_work, 198 + qcom_labibb_sc_recovery_worker); 199 + 200 + if (vreg->ocp_irq > 0) 201 + INIT_DELAYED_WORK(&vreg->ocp_recovery_work, 202 + qcom_labibb_ocp_recovery_worker); 203 + 204 + switch (vreg->type) { 205 + case QCOM_LAB_TYPE: 206 + /* LAB Limits: 200-1600mA */ 207 + vreg->uA_limits.uA_min = 200000; 208 + vreg->uA_limits.uA_step = 200000; 209 + vreg->uA_limits.ovr_val = LAB_CURRENT_LIMIT_OVERRIDE_EN; 210 + break; 211 + case QCOM_IBB_TYPE: 212 + /* IBB Limits: 0-1550mA */ 213 + vreg->uA_limits.uA_min = 0; 214 + vreg->uA_limits.uA_step = 50000; 215 + vreg->uA_limits.ovr_val = 0; /* No override bit */ 216 + break; 217 + default: 218 + return -EINVAL; 219 + } 804 220 805 221 memcpy(&vreg->desc, reg_data->desc, sizeof(vreg->desc)); 806 222 vreg->desc.of_match = reg_data->name; ··· 869 183 reg_data->name, ret); 870 184 return PTR_ERR(vreg->rdev); 871 185 } 186 + 187 + ret = devm_request_threaded_irq(vreg->dev, vreg->sc_irq, NULL, 188 + qcom_labibb_sc_isr, 189 + IRQF_ONESHOT | 190 + IRQF_TRIGGER_RISING, 191 + sc_irq_name, vreg); 192 + if (ret) 193 + return ret; 872 194 } 873 195 874 196 return 0;