// SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "PM8008: %s: " fmt, __func__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define pm8008_err(reg, message, ...) \ pr_err("%s: " message, (reg)->rdesc.name, ##__VA_ARGS__) #define pm8008_debug(reg, message, ...) \ pr_debug("%s: " message, (reg)->rdesc.name, ##__VA_ARGS__) #define STARTUP_DELAY_USEC 20 #define VSET_STEP_SIZE_MV 1 #define VSET_STEP_MV 8 #define VSET_STEP_UV (VSET_STEP_MV * 1000) #define MISC_BASE 0x900 #define MISC_CHIP_ENABLE_REG (MISC_BASE + 0x50) #define CHIP_ENABLE_BIT BIT(0) #define MISC_SHUTDOWN_CTRL_REG (MISC_BASE + 0x59) #define IGNORE_LDO_OCP_SHUTDOWN BIT(3) #define LDO_ENABLE_REG(base) (base + 0x46) #define ENABLE_BIT BIT(7) #define LDO_STATUS1_REG(base) (base + 0x08) #define VREG_OCP_BIT BIT(5) #define VREG_READY_BIT BIT(7) #define MODE_STATE_MASK GENMASK(1, 0) #define MODE_STATE_NPM 3 #define MODE_STATE_LPM 2 #define MODE_STATE_BYPASS 0 #define LDO_VSET_LB_REG(base) (base + 0x40) #define LDO_MODE_CTL1_REG(base) (base + 0x45) #define MODE_PRIMARY_MASK GENMASK(2, 0) #define LDO_MODE_NPM 7 #define LDO_MODE_LPM 4 #define FORCED_BYPASS 2 #define LDO_OCP_CTL1_REG(base) (base + 0x88) #define VREG_OCP_STATUS_CLR BIT(1) #define LDO_OCP_BROADCAST_EN_BIT BIT(2) #define LDO_STEPPER_CTL_REG(base) (base + 0x3b) #define STEP_RATE_MASK GENMASK(1, 0) #define LDO_PD_CTL_REG(base) (base + 0xA0) #define STRONG_PD_EN_BIT BIT(7) #define PM8008_MAX_LDO 7 struct pm8008_chip { struct device *dev; struct regmap *regmap; struct regulator_dev *rdev; struct regulator_desc rdesc; struct mutex lock; int ocp_irq; unsigned int internal_enable_count; bool framework_enabled; bool aggr_enabled; bool suspended; }; struct regulator_data { char *name; char *supply_name; int min_uv; int max_uv; int hpm_min_load_ua; int min_dropout_uv; }; struct pm8008_regulator { struct device *dev; struct regmap *regmap; struct regulator_desc rdesc; struct regulator_dev *rdev; struct regulator *en_supply; struct device_node *of_node; struct pm8008_chip *chip; struct notifier_block nb; u16 base; int hpm_min_load_ua; int step_rate; bool enable_ocp_broadcast; bool chip_enabled; int mode; int uv; }; static struct regulator_data reg_data[PM8008_MAX_LDO] = { /* name parent min_uv max_uv hpm_load headroom_uv */ {"l1", "vdd_l1_l2", 528000, 1504000, 30000, 225000}, {"l2", "vdd_l1_l2", 528000, 1504000, 30000, 225000}, {"l3", "vdd_l3_l4", 1504000, 3400000, 10000, 200000}, {"l4", "vdd_l3_l4", 1504000, 3400000, 10000, 200000}, {"l5", "vdd_l5", 1504000, 3400000, 10000, 300000}, {"l6", "vdd_l6", 1504000, 3400000, 10000, 300000}, {"l7", "vdd_l7", 1504000, 3400000, 10000, 300000}, }; /* common functions */ static int pm8008_read(struct regmap *regmap, u16 reg, u8 *val, int count) { int rc; rc = regmap_bulk_read(regmap, reg, val, count); if (rc < 0) pr_err("failed to read 0x%04x\n", reg); return rc; } static int pm8008_write(struct regmap *regmap, u16 reg, u8 *val, int count) { int rc; pr_debug("Writing 0x%02x to 0x%04x\n", val, reg); rc = regmap_bulk_write(regmap, reg, val, count); if (rc < 0) pr_err("failed to write 0x%04x\n", reg); return rc; } static int pm8008_masked_write(struct regmap *regmap, u16 reg, u8 mask, u8 val) { int rc; pr_debug("Writing 0x%02x to 0x%04x with mask 0x%02x\n", val, reg, mask); rc = regmap_update_bits(regmap, reg, mask, val); if (rc < 0) pr_err("failed to write 0x%02x to 0x%04x with mask 0x%02x\n", val, reg, mask); return rc; } static int pm8008_chip_aggregate(struct pm8008_chip *chip) { bool enable; int rc; lockdep_assert_held_once(&chip->lock); enable = chip->framework_enabled || chip->internal_enable_count; if (enable == chip->aggr_enabled) return 0; rc = pm8008_masked_write(chip->regmap, MISC_CHIP_ENABLE_REG, CHIP_ENABLE_BIT, enable ? CHIP_ENABLE_BIT : 0); if (rc < 0) { pm8008_err(chip, "failed to %s chip rc=%d\n", enable ? "enable" : "disable", rc); return rc; } chip->aggr_enabled = enable; pm8008_debug(chip, "chip %s\n", enable ? "enabled" : "disabled"); return 0; } static int pm8008_chip_internal_enable(struct pm8008_regulator *pm8008_reg) { struct pm8008_chip *chip = pm8008_reg->chip; int rc; if (pm8008_reg->chip_enabled) return 0; mutex_lock(&pm8008_reg->chip->lock); chip->internal_enable_count++; rc = pm8008_chip_aggregate(chip); if (rc < 0) { chip->internal_enable_count--; goto done; } pm8008_reg->chip_enabled = true; done: mutex_unlock(&pm8008_reg->chip->lock); return rc; } static int pm8008_chip_internal_disable(struct pm8008_regulator *pm8008_reg) { struct pm8008_chip *chip = pm8008_reg->chip; int rc; if (!pm8008_reg->chip_enabled) return 0; mutex_lock(&pm8008_reg->chip->lock); if (chip->internal_enable_count == 0) { pm8008_err(chip, "unbalanced disable\n"); rc = -EINVAL; goto done; } chip->internal_enable_count--; rc = pm8008_chip_aggregate(chip); if (rc < 0) { chip->internal_enable_count++; goto done; } pm8008_reg->chip_enabled = false; done: mutex_unlock(&pm8008_reg->chip->lock); return rc; } /* PM8008 LDO Regulator callbacks */ static int pm8008_regulator_get_voltage(struct regulator_dev *rdev) { struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev); u8 vset_raw[2]; int rc; if (pm8008_reg->chip->suspended) return pm8008_reg->uv; rc = pm8008_read(pm8008_reg->regmap, LDO_VSET_LB_REG(pm8008_reg->base), vset_raw, 2); if (rc < 0) { pm8008_err(pm8008_reg, "failed to read regulator voltage rc=%d\n", rc); return rc; } pm8008_debug(pm8008_reg, "VSET read [%x][%x]\n", vset_raw[1], vset_raw[0]); return (vset_raw[1] << 8 | vset_raw[0]) * 1000; } static int _pm8008_regulator_is_enabled(struct pm8008_regulator *pm8008_reg) { int rc; u8 reg; rc = pm8008_read(pm8008_reg->regmap, LDO_ENABLE_REG(pm8008_reg->base), ®, 1); if (rc < 0) { pm8008_err(pm8008_reg, "failed to read enable reg rc=%d\n", rc); return rc; } return !!(reg & ENABLE_BIT); } static int pm8008_regulator_is_enabled(struct regulator_dev *rdev) { struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev); if (pm8008_reg->chip->suspended) return pm8008_reg->chip_enabled; return _pm8008_regulator_is_enabled(pm8008_reg); } static int pm8008_regulator_enable(struct regulator_dev *rdev) { struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev); int rc, rc2, current_uv, delay_us, delay_ms, retry_count = 10; u8 reg; if (pm8008_reg->chip->suspended) { if (pm8008_reg->chip_enabled) return 0; return -EPERM; } current_uv = pm8008_regulator_get_voltage(rdev); if (current_uv < 0) { pm8008_err(pm8008_reg, "failed to get current voltage rc=%d\n", current_uv); return current_uv; } rc = pm8008_chip_internal_enable(pm8008_reg); if (rc < 0) { pm8008_err(pm8008_reg, "failed to enable chip rc=%d\n", rc); return rc; } rc = pm8008_masked_write(pm8008_reg->regmap, LDO_ENABLE_REG(pm8008_reg->base), ENABLE_BIT, ENABLE_BIT); if (rc < 0) { pm8008_err(pm8008_reg, "failed to enable regulator rc=%d\n", rc); goto remove_en; } /* * Wait for the VREG_READY status bit to be set using a timeout delay * calculated from the current commanded voltage. */ delay_us = STARTUP_DELAY_USEC + DIV_ROUND_UP(current_uv, pm8008_reg->step_rate); delay_ms = DIV_ROUND_UP(delay_us, 1000); /* Retry 10 times for VREG_READY before bailing out */ while (retry_count--) { if (delay_ms > 20) msleep(delay_ms); else usleep_range(delay_us, delay_us + 100); rc = pm8008_read(pm8008_reg->regmap, LDO_STATUS1_REG(pm8008_reg->base), ®, 1); if (rc < 0) { pm8008_err(pm8008_reg, "failed to read regulator status rc=%d\n", rc); goto disable_ldo; } if (reg & VREG_READY_BIT) { pm8008_debug(pm8008_reg, "regulator enabled\n"); return 0; } } pm8008_err(pm8008_reg, "failed to enable regulator, VREG_READY not set\n"); rc = -ETIME; disable_ldo: pm8008_masked_write(pm8008_reg->regmap, LDO_ENABLE_REG(pm8008_reg->base), ENABLE_BIT, 0); remove_en: rc2 = pm8008_chip_internal_disable(pm8008_reg); if (rc2 < 0) pm8008_err(pm8008_reg, "failed to disable chip rc=%d\n", rc2); return rc; } static int pm8008_regulator_disable(struct regulator_dev *rdev) { struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev); int rc; if (pm8008_reg->chip->suspended) { if (!pm8008_reg->chip_enabled) return 0; return -EPERM; } rc = pm8008_masked_write(pm8008_reg->regmap, LDO_ENABLE_REG(pm8008_reg->base), ENABLE_BIT, 0); if (rc < 0) { pm8008_err(pm8008_reg, "failed to disable regulator rc=%d\n", rc); return rc; } /* remove vote from chip enable regulator */ rc = pm8008_chip_internal_disable(pm8008_reg); if (rc < 0) { pm8008_err(pm8008_reg, "failed to disable chip rc=%d\n", rc); return rc; } pm8008_debug(pm8008_reg, "regulator disabled\n"); return 0; } static int pm8008_write_voltage(struct pm8008_regulator *pm8008_reg, int min_uv, int max_uv) { int rc = 0, mv; u8 vset_raw[2]; mv = DIV_ROUND_UP(min_uv, 1000); if (mv * 1000 > max_uv) { pm8008_err(pm8008_reg, "requested voltage above maximum limit\n"); return -EINVAL; } /* * Each LSB of regulator is 1mV and the voltage setpoint * should be multiple of 8mV(step). */ mv = DIV_ROUND_UP(DIV_ROUND_UP(mv, VSET_STEP_MV) * VSET_STEP_MV, VSET_STEP_SIZE_MV); vset_raw[0] = mv & 0xff; vset_raw[1] = (mv & 0xff00) >> 8; rc = pm8008_write(pm8008_reg->regmap, LDO_VSET_LB_REG(pm8008_reg->base), vset_raw, 2); if (rc < 0) { pm8008_err(pm8008_reg, "failed to write voltage rc=%d\n", rc); return rc; } pm8008_reg->uv = mv * 1000; pm8008_debug(pm8008_reg, "VSET=[%x][%x]\n", vset_raw[1], vset_raw[0]); return 0; } static int pm8008_regulator_set_voltage_time(struct regulator_dev *rdev, int old_uV, int new_uv) { struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev); return DIV_ROUND_UP(abs(new_uv - old_uV), pm8008_reg->step_rate); } static int pm8008_regulator_set_voltage(struct regulator_dev *rdev, int min_uv, int max_uv, unsigned int *selector) { struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev); int rc; if (pm8008_reg->chip->suspended) { if (min_uv <= pm8008_reg->uv && pm8008_reg->uv <= max_uv) return 0; return -EPERM; } rc = pm8008_write_voltage(pm8008_reg, min_uv, max_uv); if (rc < 0) return rc; *selector = DIV_ROUND_UP(min_uv - pm8008_reg->rdesc.min_uV, VSET_STEP_UV); pm8008_debug(pm8008_reg, "voltage set to %d\n", min_uv); return 0; } static int pm8008_regulator_set_mode(struct regulator_dev *rdev, unsigned int mode) { struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev); int rc; u8 val = LDO_MODE_LPM; if (pm8008_reg->chip->suspended) { if (mode == pm8008_reg->mode) return 0; return -EPERM; } if (mode == REGULATOR_MODE_NORMAL) val = LDO_MODE_NPM; else if (mode == REGULATOR_MODE_IDLE) val = LDO_MODE_LPM; rc = pm8008_masked_write(pm8008_reg->regmap, LDO_MODE_CTL1_REG(pm8008_reg->base), MODE_PRIMARY_MASK, val); if (!rc) { pm8008_debug(pm8008_reg, "mode set to %d\n", val); pm8008_reg->mode = mode; } return rc; } static unsigned int pm8008_regulator_get_mode(struct regulator_dev *rdev) { struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev); int rc; u8 reg; if (pm8008_reg->chip->suspended) return pm8008_reg->mode; rc = pm8008_read(pm8008_reg->regmap, LDO_STATUS1_REG(pm8008_reg->base), ®, 1); if (rc < 0) { pm8008_err(pm8008_reg, "failed to get mode rc=%d\n", rc); return rc; } return ((reg & MODE_STATE_MASK) == MODE_STATE_NPM) ? REGULATOR_MODE_NORMAL : REGULATOR_MODE_IDLE; } static int pm8008_regulator_set_load(struct regulator_dev *rdev, int load_uA) { struct pm8008_regulator *pm8008_reg = rdev_get_drvdata(rdev); int mode; if (load_uA >= pm8008_reg->hpm_min_load_ua) mode = REGULATOR_MODE_NORMAL; else mode = REGULATOR_MODE_IDLE; return pm8008_regulator_set_mode(rdev, mode); } static struct regulator_ops pm8008_regulator_ops = { .enable = pm8008_regulator_enable, .disable = pm8008_regulator_disable, .is_enabled = pm8008_regulator_is_enabled, .set_voltage = pm8008_regulator_set_voltage, .get_voltage = pm8008_regulator_get_voltage, .list_voltage = regulator_list_voltage_linear, .set_mode = pm8008_regulator_set_mode, .get_mode = pm8008_regulator_get_mode, .set_load = pm8008_regulator_set_load, .set_voltage_time = pm8008_regulator_set_voltage_time, }; static int pm8008_ldo_cb(struct notifier_block *nb, ulong event, void *data) { struct pm8008_regulator *pm8008_reg = container_of(nb, struct pm8008_regulator, nb); u8 val; int rc; if (event != REGULATOR_EVENT_OVER_CURRENT) return NOTIFY_OK; rc = pm8008_read(pm8008_reg->regmap, LDO_STATUS1_REG(pm8008_reg->base), &val, 1); if (rc < 0) { pm8008_err(pm8008_reg, "failed to read regulator status rc=%d\n", rc); goto error; } if (!(val & VREG_OCP_BIT)) return NOTIFY_OK; pr_err("OCP triggered on %s\n", pm8008_reg->rdesc.name); /* * Toggle the OCP_STATUS_CLR bit to re-arm the OCP status for * the next OCP event */ rc = pm8008_masked_write(pm8008_reg->regmap, LDO_OCP_CTL1_REG(pm8008_reg->base), VREG_OCP_STATUS_CLR, VREG_OCP_STATUS_CLR); if (rc < 0) { pm8008_err(pm8008_reg, "failed to write OCP_STATUS_CLR rc=%d\n", rc); goto error; } rc = pm8008_masked_write(pm8008_reg->regmap, LDO_OCP_CTL1_REG(pm8008_reg->base), VREG_OCP_STATUS_CLR, 0); if (rc < 0) { pm8008_err(pm8008_reg, "failed to write OCP_STATUS_CLR rc=%d\n", rc); goto error; } /* Notify the consumers about the OCP event */ regulator_lock(pm8008_reg->rdev); regulator_notifier_call_chain(pm8008_reg->rdev, REGULATOR_EVENT_OVER_CURRENT, NULL); regulator_unlock(pm8008_reg->rdev); error: return NOTIFY_OK; } static int pm8008_register_ldo(struct pm8008_regulator *pm8008_reg, const char *name) { struct regulator_config reg_config = {}; struct regulator_init_data *init_data; struct device *dev = pm8008_reg->dev; struct device_node *reg_node = pm8008_reg->of_node; int rc, i, init_voltage, is_enabled; u32 base = 0; u8 reg; /* get regulator data */ for (i = 0; i < PM8008_MAX_LDO; i++) if (strstr(name, reg_data[i].name)) break; if (i == PM8008_MAX_LDO) { pr_err("Invalid regulator name %s\n", name); return -EINVAL; } rc = of_property_read_u32(reg_node, "reg", &base); if (rc < 0) { pr_err("%s: failed to get regulator base rc=%d\n", name, rc); return rc; } pm8008_reg->base = base; pm8008_reg->hpm_min_load_ua = reg_data[i].hpm_min_load_ua; of_property_read_u32(reg_node, "qcom,hpm-min-load", &pm8008_reg->hpm_min_load_ua); init_voltage = -EINVAL; of_property_read_u32(reg_node, "qcom,init-voltage", &init_voltage); if (of_property_read_bool(reg_node, "qcom,strong-pd")) { rc = pm8008_masked_write(pm8008_reg->regmap, LDO_PD_CTL_REG(pm8008_reg->base), STRONG_PD_EN_BIT, STRONG_PD_EN_BIT); if (rc < 0) { pr_err("%s: failed to configure pull down rc=%d\n", name, rc); return rc; } } if (pm8008_reg->enable_ocp_broadcast) { rc = pm8008_masked_write(pm8008_reg->regmap, LDO_OCP_CTL1_REG(pm8008_reg->base), LDO_OCP_BROADCAST_EN_BIT, LDO_OCP_BROADCAST_EN_BIT); if (rc < 0) { pr_err("%s: failed to configure ocp broadcast rc=%d\n", name, rc); return rc; } } /* get slew rate */ rc = pm8008_read(pm8008_reg->regmap, LDO_STEPPER_CTL_REG(pm8008_reg->base), ®, 1); if (rc < 0) { pr_err("%s: failed to read step rate configuration rc=%d\n", name, rc); return rc; } pm8008_reg->step_rate = 38400 >> (reg & STEP_RATE_MASK); init_data = of_get_regulator_init_data(dev, reg_node, &pm8008_reg->rdesc); if (init_data == NULL) { pr_err("%s: failed to get regulator data\n", name); return -ENODATA; } if (!init_data->constraints.name) { pr_err("%s: regulator name missing\n", name); return -EINVAL; } /* configure the initial voltage for the regulator */ if (init_voltage > 0) { rc = pm8008_write_voltage(pm8008_reg, init_voltage, init_data->constraints.max_uV); if (rc < 0) pr_err("%s: failed to set initial voltage rc=%d\n", name, rc); } init_data->constraints.input_uV = init_data->constraints.max_uV; init_data->constraints.valid_ops_mask |= REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_DRMS; reg_config.dev = dev; reg_config.init_data = init_data; reg_config.driver_data = pm8008_reg; reg_config.of_node = reg_node; pm8008_reg->rdesc.type = REGULATOR_VOLTAGE; pm8008_reg->rdesc.ops = &pm8008_regulator_ops; pm8008_reg->rdesc.name = init_data->constraints.name; pm8008_reg->rdesc.supply_name = reg_data[i].supply_name; pm8008_reg->rdesc.uV_step = VSET_STEP_UV; pm8008_reg->rdesc.min_uV = reg_data[i].min_uv; pm8008_reg->rdesc.n_voltages = ((reg_data[i].max_uv - reg_data[i].min_uv) / pm8008_reg->rdesc.uV_step) + 1; pm8008_reg->rdesc.min_dropout_uV = reg_data[i].min_dropout_uv; of_property_read_u32(reg_node, "qcom,min-dropout-voltage", &pm8008_reg->rdesc.min_dropout_uV); is_enabled = _pm8008_regulator_is_enabled(pm8008_reg); if (is_enabled < 0) { return is_enabled; } else if (is_enabled) { rc = pm8008_chip_internal_enable(pm8008_reg); if (rc) return rc; } pm8008_reg->rdev = devm_regulator_register(dev, &pm8008_reg->rdesc, ®_config); if (IS_ERR(pm8008_reg->rdev)) { rc = PTR_ERR(pm8008_reg->rdev); pr_err("%s: failed to register regulator rc=%d\n", pm8008_reg->rdesc.name, rc); return rc; } pm8008_reg->uv = pm8008_regulator_get_voltage(pm8008_reg->rdev); pm8008_reg->mode = pm8008_regulator_get_mode(pm8008_reg->rdev); if (pm8008_reg->enable_ocp_broadcast) { pm8008_reg->nb.notifier_call = pm8008_ldo_cb; rc = devm_regulator_register_notifier(pm8008_reg->en_supply, &pm8008_reg->nb); if (rc < 0) { pr_err("Failed to register a regulator notifier rc=%d\n", rc); return rc; } } pr_debug("%s regulator registered\n", name); return 0; } /* PMIC probe and helper function */ static int pm8008_parse_regulator(struct regmap *regmap, struct device *dev) { int rc = 0; const char *name; struct device_node *child; struct pm8008_regulator *pm8008_reg; struct regulator *en_supply; struct pm8008_chip *chip; bool ocp; ocp = of_property_read_bool(dev->of_node, "qcom,enable-ocp-broadcast"); en_supply = devm_regulator_get(dev, "pm8008_en"); if (IS_ERR(en_supply)) { rc = PTR_ERR(en_supply); dev_err(dev, "failed to get pm8008_en supply\n"); return rc; } chip = regulator_get_drvdata(en_supply); if (!chip) { dev_err(dev, "failed to get pm8008_en supply data\n"); return -ENODATA; } /* parse each subnode and register regulator for regulator child */ for_each_available_child_of_node(dev->of_node, child) { pm8008_reg = devm_kzalloc(dev, sizeof(*pm8008_reg), GFP_KERNEL); if (!pm8008_reg) return -ENOMEM; pm8008_reg->regmap = regmap; pm8008_reg->of_node = child; pm8008_reg->dev = dev; pm8008_reg->enable_ocp_broadcast = ocp; pm8008_reg->en_supply = en_supply; pm8008_reg->chip = chip; rc = of_property_read_string(child, "regulator-name", &name); if (rc) continue; rc = pm8008_register_ldo(pm8008_reg, name); if (rc < 0) { pr_err("failed to register regulator %s rc=%d\n", name, rc); return rc; } } return 0; } static int pm8008_regulator_probe(struct platform_device *pdev) { int rc = 0; struct regmap *regmap; regmap = dev_get_regmap(pdev->dev.parent, NULL); if (!regmap) { pr_err("parent regmap is missing\n"); return -EINVAL; } rc = pm8008_parse_regulator(regmap, &pdev->dev); if (rc < 0) { pr_err("failed to parse device tree rc=%d\n", rc); return rc; } return 0; } /* PM8008 chip enable regulator callbacks */ static int pm8008_chip_enable(struct regulator_dev *rdev) { struct pm8008_chip *chip = rdev_get_drvdata(rdev); int rc; if (chip->suspended) { if (chip->framework_enabled) return 0; return -EPERM; } mutex_lock(&chip->lock); chip->framework_enabled = true; rc = pm8008_chip_aggregate(chip); if (rc < 0) chip->framework_enabled = false; mutex_unlock(&chip->lock); return rc; } static int pm8008_chip_disable(struct regulator_dev *rdev) { struct pm8008_chip *chip = rdev_get_drvdata(rdev); int rc; if (chip->suspended) { if (!chip->framework_enabled) return 0; return -EPERM; } mutex_lock(&chip->lock); chip->framework_enabled = false; rc = pm8008_chip_aggregate(chip); if (rc < 0) chip->framework_enabled = true; mutex_unlock(&chip->lock); return rc; } static int pm8008_chip_is_enabled(struct regulator_dev *rdev) { struct pm8008_chip *chip = rdev_get_drvdata(rdev); return chip->framework_enabled; } static struct regulator_ops pm8008_chip_ops = { .enable = pm8008_chip_enable, .disable = pm8008_chip_disable, .is_enabled = pm8008_chip_is_enabled, }; static int _pm8008_chip_is_enabled(struct pm8008_chip *chip) { int rc; u8 reg; rc = pm8008_read(chip->regmap, MISC_CHIP_ENABLE_REG, ®, 1); if (rc < 0) { pm8008_err(chip, "failed to get chip state rc=%d\n", rc); return rc; } return !!(reg & CHIP_ENABLE_BIT); } static int pm8008_chip_init_regulator(struct pm8008_chip *chip) { struct regulator_config cfg = {}; int rc = 0; cfg.dev = chip->dev; cfg.driver_data = chip; chip->rdesc.type = REGULATOR_VOLTAGE; chip->rdesc.ops = &pm8008_chip_ops; chip->rdesc.of_match = "qcom,pm8008-chip-en"; chip->rdesc.name = "qcom,pm8008-chip-en"; /* * Cache the physical hardware state in framework_enabled and * aggr_enabled so that the regulator is automatically disabled if no * framework or internal enable requests are made. */ rc = _pm8008_chip_is_enabled(chip); if (rc < 0) return rc; chip->framework_enabled = rc; chip->aggr_enabled = chip->framework_enabled; chip->rdev = devm_regulator_register(chip->dev, &chip->rdesc, &cfg); if (IS_ERR(chip->rdev)) { rc = PTR_ERR(chip->rdev); chip->rdev = NULL; return rc; } return 0; } static irqreturn_t pm8008_ocp_irq(int irq, void *_chip) { struct pm8008_chip *chip = _chip; regulator_lock(chip->rdev); regulator_notifier_call_chain(chip->rdev, REGULATOR_EVENT_OVER_CURRENT, NULL); regulator_unlock(chip->rdev); return IRQ_HANDLED; } static int pm8008_chip_probe(struct platform_device *pdev) { int rc = 0; struct pm8008_chip *chip; chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; chip->regmap = dev_get_regmap(pdev->dev.parent, NULL); if (!chip->regmap) { pr_err("parent regmap is missing\n"); return -EINVAL; } chip->dev = &pdev->dev; mutex_init(&chip->lock); /* Register chip enable regulator */ rc = pm8008_chip_init_regulator(chip); if (rc < 0) { pr_err("Failed to register chip enable regulator rc=%d\n", rc); return rc; } chip->ocp_irq = of_irq_get_byname(chip->dev->of_node, "ocp"); if (chip->ocp_irq < 0) { pr_debug("Failed to get pm8008-ocp-irq\n"); } else { rc = devm_request_threaded_irq(chip->dev, chip->ocp_irq, NULL, pm8008_ocp_irq, IRQF_ONESHOT, "ocp", chip); if (rc < 0) { pr_err("Failed to request 'pm8008-ocp-irq' rc=%d\n", rc); return rc; } /* Ignore PMIC shutdown for LDO OCP event */ rc = pm8008_masked_write(chip->regmap, MISC_SHUTDOWN_CTRL_REG, IGNORE_LDO_OCP_SHUTDOWN, IGNORE_LDO_OCP_SHUTDOWN); if (rc < 0) { pr_err("Failed to write MISC_SHUTDOWN register rc=%d\n", rc); return rc; } } platform_set_drvdata(pdev, chip); pr_debug("PM8008 chip registered\n"); return 0; } static int pm8008_chip_remove(struct platform_device *pdev) { struct pm8008_chip *chip = platform_get_drvdata(pdev); int rc; rc = pm8008_masked_write(chip->regmap, MISC_CHIP_ENABLE_REG, CHIP_ENABLE_BIT, 0); if (rc < 0) pr_err("failed to disable chip rc=%d\n", rc); return 0; } #ifdef CONFIG_PM_SLEEP static int pm8008_chip_suspend(struct device *dev) { struct pm8008_chip *chip = dev_get_drvdata(dev); chip->suspended = true; return 0; } static int pm8008_chip_resume(struct device *dev) { struct pm8008_chip *chip = dev_get_drvdata(dev); chip->suspended = false; return 0; } #endif static const struct of_device_id pm8008_regulator_match_table[] = { { .compatible = "qcom,pm8008-regulator", }, { }, }; static struct platform_driver pm8008_regulator_driver = { .driver = { .name = "qcom,pm8008-regulator", .of_match_table = pm8008_regulator_match_table, }, .probe = pm8008_regulator_probe, }; static const struct of_device_id pm8008_chip_match_table[] = { { .compatible = "qcom,pm8008-chip", }, { }, }; static const struct dev_pm_ops pm8008_chip_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(pm8008_chip_suspend, pm8008_chip_resume) }; static struct platform_driver pm8008_chip_driver = { .driver = { .name = "qcom,pm8008-chip", .pm = &pm8008_chip_pm_ops, .of_match_table = pm8008_chip_match_table, }, .probe = pm8008_chip_probe, .remove = pm8008_chip_remove, }; static int __init pm8008_regulator_init(void) { int rc; rc = platform_driver_register(&pm8008_chip_driver); if (rc) return rc; return platform_driver_register(&pm8008_regulator_driver); } module_init(pm8008_regulator_init); static void __exit pm8008_regulator_exit(void) { platform_driver_unregister(&pm8008_regulator_driver); platform_driver_unregister(&pm8008_chip_driver); } module_exit(pm8008_regulator_exit); MODULE_DESCRIPTION("QPNP PM8008 PMIC Regulator Driver"); MODULE_LICENSE("GPL v2");