/* Chip data */ struct da9121 { struct device *dev; struct delayed_work work; struct da9121_pdata *pdata; struct regmap *regmap; struct regulator_dev *rdev[DA9121_IDX_MAX]; unsignedint persistent[2]; unsignedint passive_delay; int chip_irq; int variant_id; int subvariant_id;
};
/* Define ranges for different variants, enabling translation to/from * registers. Maximums give scope to allow for transients.
*/ struct da9121_range { int val_min; int val_max; int val_stp; int reg_min; int reg_max;
};
struct status_event_data { int buck_id; /* 0=core, 1/2-buck */ int reg_index; /* index for status/event/mask register selection */ int status_bit; /* bit masks... */ int event_bit; int mask_bit; unsignedlong notification; /* Notification for status inception */ char *warn; /* if NULL, notify - otherwise dev_warn this string */
};
#define DA9121_STATUS(id, bank, name, notification, warning) \
{ id, bank, \
DA9121_MASK_SYS_STATUS_##bank##_##name, \
DA9121_MASK_SYS_EVENT_##bank##_E_##name, \
DA9121_MASK_SYS_MASK_##bank##_M_##name, \
notification, warning }
/* For second buck related event bits that are specific to DA9122, DA9220 variants */ #define DA9xxx_STATUS(id, bank, name, notification, warning) \
{ id, bank, \
DA9xxx_MASK_SYS_STATUS_##bank##_##name, \
DA9xxx_MASK_SYS_EVENT_##bank##_E_##name, \
DA9xxx_MASK_SYS_MASK_##bank##_M_##name, \
notification, warning }
/* The status signals that may need servicing, depending on device variant. * After assertion, they persist; so event is notified, the IRQ disabled, * and status polled until clear again and IRQ is reenabled. * * SG/PG1/PG2 should be set when device first powers up and should never * re-occur. When this driver starts, it is expected that these will have * self-cleared for when the IRQs are enabled, so these should never be seen. * If seen, the implication is that the device has reset. * * GPIO0/1/2 are not configured for use by default, so should not be seen.
*/ staticconststruct status_event_data status_event_handling[] = {
DA9xxx_STATUS(0, 0, SG, 0, "Handled E_SG\n"),
DA9121_STATUS(0, 0, TEMP_CRIT, (REGULATOR_EVENT_OVER_TEMP|REGULATOR_EVENT_DISABLE), NULL),
DA9121_STATUS(0, 0, TEMP_WARN, REGULATOR_EVENT_OVER_TEMP, NULL),
DA9121_STATUS(1, 1, PG1, 0, "Handled E_PG1\n"),
DA9121_STATUS(1, 1, OV1, REGULATOR_EVENT_REGULATION_OUT, NULL),
DA9121_STATUS(1, 1, UV1, REGULATOR_EVENT_UNDER_VOLTAGE, NULL),
DA9121_STATUS(1, 1, OC1, REGULATOR_EVENT_OVER_CURRENT, NULL),
DA9xxx_STATUS(2, 1, PG2, 0, "Handled E_PG2\n"),
DA9xxx_STATUS(2, 1, OV2, REGULATOR_EVENT_REGULATION_OUT, NULL),
DA9xxx_STATUS(2, 1, UV2, REGULATOR_EVENT_UNDER_VOLTAGE, NULL),
DA9xxx_STATUS(2, 1, OC2, REGULATOR_EVENT_OVER_CURRENT, NULL),
DA9121_STATUS(0, 2, GPIO0, 0, "Handled E_GPIO0\n"),
DA9121_STATUS(0, 2, GPIO1, 0, "Handled E_GPIO1\n"),
DA9121_STATUS(0, 2, GPIO2, 0, "Handled E_GPIO2\n"),
};
staticint da9121_get_current_limit(struct regulator_dev *rdev)
{ struct da9121 *chip = rdev_get_drvdata(rdev); int id = rdev_get_id(rdev); conststruct da9121_range *range =
variant_parameters[chip->variant_id].current_range; unsignedint val = 0; int ret = 0;
ret = regmap_read(chip->regmap, da9121_current_field[id].reg, &val); if (ret < 0) {
dev_err(chip->dev, "Cannot read BUCK register: %d\n", ret); goto error;
}
if (val < range->reg_min) {
ret = -EACCES; goto error;
}
if (val > range->reg_max) {
ret = -EINVAL; goto error;
}
staticint da9121_ceiling_selector(struct regulator_dev *rdev, int min, int max, unsignedint *selector)
{ struct da9121 *chip = rdev_get_drvdata(rdev); conststruct da9121_range *range =
variant_parameters[chip->variant_id].current_range; unsignedint level; unsignedint i = 0; unsignedint sel = 0; int ret = 0;
if (range->val_min > max || range->val_max < min) {
dev_err(chip->dev, "Requested current out of regulator capability\n");
ret = -EINVAL; goto error;
}
level = range->val_max; for (i = range->reg_max; i >= range->reg_min; i--) { if (level <= max) {
sel = i; break;
}
level -= range->val_stp;
}
if (level < min) {
dev_err(chip->dev, "Best match falls below minimum requested current\n");
ret = -EINVAL; goto error;
}
*selector = sel;
error: return ret;
}
staticint da9121_set_current_limit(struct regulator_dev *rdev, int min_ua, int max_ua)
{ struct da9121 *chip = rdev_get_drvdata(rdev); int id = rdev_get_id(rdev); conststruct da9121_range *range =
variant_parameters[chip->variant_id].current_range; unsignedint sel = 0; int ret = 0;
if (min_ua < range->val_min ||
max_ua > range->val_max) {
ret = -EINVAL; goto error;
}
if (rdev->desc->ops->is_enabled(rdev)) {
ret = -EBUSY; goto error;
}
ret = da9121_ceiling_selector(rdev, min_ua, max_ua, &sel); if (ret < 0) goto error;
ret = regmap_update_bits(chip->regmap,
da9121_current_field[id].reg,
da9121_current_field[id].msk,
(unsignedint)sel); if (ret < 0)
dev_err(chip->dev, "Cannot update BUCK current limit, err: %d\n", ret);
error: return ret;
}
staticunsignedint da9121_map_mode(unsignedint mode)
{ switch (mode) { case DA9121_BUCK_MODE_FORCE_PWM: return REGULATOR_MODE_FAST; case DA9121_BUCK_MODE_FORCE_PWM_SHEDDING: return REGULATOR_MODE_NORMAL; case DA9121_BUCK_MODE_AUTO: return REGULATOR_MODE_IDLE; case DA9121_BUCK_MODE_FORCE_PFM: return REGULATOR_MODE_STANDBY; default: return REGULATOR_MODE_INVALID;
}
}
staticint da9121_buck_set_mode(struct regulator_dev *rdev, unsignedint mode)
{ struct da9121 *chip = rdev_get_drvdata(rdev); int id = rdev_get_id(rdev); unsignedint val;
switch (mode) { case REGULATOR_MODE_FAST:
val = DA9121_BUCK_MODE_FORCE_PWM; break; case REGULATOR_MODE_NORMAL:
val = DA9121_BUCK_MODE_FORCE_PWM_SHEDDING; break; case REGULATOR_MODE_IDLE:
val = DA9121_BUCK_MODE_AUTO; break; case REGULATOR_MODE_STANDBY:
val = DA9121_BUCK_MODE_FORCE_PFM; break; default: return -EINVAL;
}
staticvoid da9121_status_poll_on(struct work_struct *work)
{ struct da9121 *chip = container_of(work, struct da9121, work.work); int status[3] = {0}; int clear[3] = {0}; unsignedlong delay; int i; int ret;
ret = regmap_bulk_read(chip->regmap, DA9121_REG_SYS_STATUS_0, status, 2); if (ret < 0) {
dev_err(chip->dev, "Failed to read STATUS registers: %d\n", ret); goto error;
}
/* Possible events are tested to be within range for the variant, potentially * masked by the IRQ handler (not just warned about), as having been masked, * and the respective state cleared - then flagged to unmask for next IRQ.
*/ for (i = 0; i < ARRAY_SIZE(status_event_handling); i++) { conststruct status_event_data *item = &status_event_handling[i]; int reg_idx = item->reg_index; bool relevant = (item->buck_id <= variant_parameters[chip->variant_id].num_bucks); bool supported = (item->warn == NULL); bool persisting = (chip->persistent[reg_idx] & item->event_bit); bool now_cleared = !(status[reg_idx] & item->status_bit);
static irqreturn_t da9121_irq_handler(int irq, void *data)
{ struct da9121 *chip = data; struct regulator_dev *rdev; int event[3] = {0}; int handled[3] = {0}; int mask[3] = {0}; int ret = IRQ_NONE; int i; int err;
err = regmap_bulk_read(chip->regmap, DA9121_REG_SYS_EVENT_0, event, 3); if (err < 0) {
dev_err(chip->dev, "Failed to read EVENT registers %d\n", err);
ret = IRQ_NONE; goto error;
}
err = regmap_bulk_read(chip->regmap, DA9121_REG_SYS_MASK_0, mask, 3); if (err < 0) {
dev_err(chip->dev, "Failed to read MASK registers: %d\n", ret);
ret = IRQ_NONE; goto error;
}
rdev = chip->rdev[DA9121_IDX_BUCK1];
/* Possible events are tested to be within range for the variant, currently * enabled, and having triggered this IRQ. The event may then be notified, * or a warning given for unexpected events - those from device POR, and * currently unsupported GPIO configurations.
*/ for (i = 0; i < ARRAY_SIZE(status_event_handling); i++) { conststruct status_event_data *item = &status_event_handling[i]; int reg_idx = item->reg_index; bool relevant = (item->buck_id <= variant_parameters[chip->variant_id].num_bucks); bool enabled = !(mask[reg_idx] & item->mask_bit); bool active = (event[reg_idx] & item->event_bit); bool notify = (item->warn == NULL);
if (relevant && enabled && active) { if (notify) {
chip->persistent[reg_idx] |= item->event_bit;
regulator_notifier_call_chain(rdev, item->notification, NULL);
} else {
dev_warn(chip->dev, item->warn);
handled[reg_idx] |= item->event_bit;
ret = IRQ_HANDLED;
}
}
}
for (i = 0; i < 3; i++) { if (event[i] != handled[i]) {
dev_warn(chip->dev, "Unhandled event(s) in bank%d 0x%02x\n", i,
event[i] ^ handled[i]);
}
}
/* Mask the interrupts for persistent events OV, OC, UV, WARN, CRIT */ for (i = 0; i < 2; i++) { if (handled[i]) { unsignedint reg = DA9121_REG_SYS_MASK_0 + i; unsignedint mbit = handled[i];
err = regmap_update_bits(chip->regmap, reg, mbit, mbit); if (err < 0) {
dev_err(chip->dev, "Failed to mask 0x%02x interrupt %d\n",
reg, err);
ret = IRQ_NONE; goto error;
}
}
}
/* clear the events */ if (handled[0] | handled[1] | handled[2]) {
err = regmap_bulk_write(chip->regmap, DA9121_REG_SYS_EVENT_0, handled, 3); if (err < 0) {
dev_err(chip->dev, "Fail to write EVENTs %d\n", err);
ret = IRQ_NONE; goto error;
}
}
staticint da9121_assign_chip_model(struct i2c_client *i2c, struct da9121 *chip)
{ conststruct regmap_config *regmap; int ret = 0;
chip->dev = &i2c->dev;
/* Use configured subtype to select the regulator descriptor index and * register map, common to both consumer and automotive grade variants
*/ switch (chip->subvariant_id) { case DA9121_SUBTYPE_DA9121: case DA9121_SUBTYPE_DA9130:
chip->variant_id = DA9121_TYPE_DA9121_DA9130;
regmap = &da9121_1ch_regmap_config; break; case DA9121_SUBTYPE_DA9217:
chip->variant_id = DA9121_TYPE_DA9217;
regmap = &da9121_1ch_regmap_config; break; case DA9121_SUBTYPE_DA9122: case DA9121_SUBTYPE_DA9131:
chip->variant_id = DA9121_TYPE_DA9122_DA9131;
regmap = &da9121_2ch_regmap_config; break; case DA9121_SUBTYPE_DA9220: case DA9121_SUBTYPE_DA9132:
chip->variant_id = DA9121_TYPE_DA9220_DA9132;
regmap = &da9121_2ch_regmap_config; break; case DA9121_SUBTYPE_DA9141:
chip->variant_id = DA9121_TYPE_DA9141;
regmap = &da9121_1ch_regmap_config; break; case DA9121_SUBTYPE_DA9142:
chip->variant_id = DA9121_TYPE_DA9142;
regmap = &da9121_2ch_regmap_config; break; default: return -EINVAL;
}
/* Set these up for of_regulator_match call which may want .of_map_modes */
da9121_matches[0].desc = local_da9121_regulators[chip->variant_id][0];
da9121_matches[1].desc = local_da9121_regulators[chip->variant_id][1];
chip->regmap = devm_regmap_init_i2c(i2c, regmap); if (IS_ERR(chip->regmap)) {
ret = PTR_ERR(chip->regmap);
dev_err(chip->dev, "Failed to configure a register map: %d\n",
ret); return ret;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.