staticint rt9467_get_adc(struct rt9467_chg_data *data, enum rt9467_adc_chan chan, int *val)
{ unsignedint aicr_ua, ichg_ua; int ret;
ret = rt9467_get_adc_raw_data(data, chan, val); if (ret) return ret;
switch (chan) { case RT9467_ADC_VBUS_DIV5:
*val *= 25000; return 0; case RT9467_ADC_VBUS_DIV2:
*val *= 10000; return 0; case RT9467_ADC_VBAT: case RT9467_ADC_VSYS: case RT9467_ADC_REGN:
*val *= 5000; return 0; case RT9467_ADC_TS_BAT:
*val /= 400; return 0; case RT9467_ADC_IBUS: /* UUG MOS turn-on ratio will affect the IBUS adc scale */
ret = rt9467_get_value_from_ranges(data, F_IAICR,
RT9467_RANGE_IAICR, &aicr_ua); if (ret) return ret;
*val *= aicr_ua < 400000 ? 29480 : 50000; return 0; case RT9467_ADC_IBAT: /* PP MOS turn-on ratio will affect the ICHG adc scale */
ret = rt9467_get_value_from_ranges(data, F_ICHG,
RT9467_RANGE_ICHG, &ichg_ua); if (ret) return ret;
/* Trigger AICL function */
ret = regmap_field_write(data->rm_field[F_AICL_MEAS], 1); if (ret) {
dev_err(data->dev, "Failed to set aicl measurement\n"); return ret;
}
reinit_completion(&data->aicl_done);
ret = wait_for_completion_timeout(&data->aicl_done, msecs_to_jiffies(3500)); if (ret == 0) return -ETIMEDOUT;
ret = rt9467_get_value_from_ranges(data, F_IAICR, RT9467_RANGE_IAICR, &aicr_get); if (ret) {
dev_err(data->dev, "Failed to get aicr\n"); return ret;
}
dev_info(data->dev, "aicr get = %d uA\n", aicr_get); return 0;
}
staticint rt9467_psy_set_ieoc(struct rt9467_chg_data *data, int microamp)
{ int ret;
mutex_lock(&data->ichg_ieoc_lock);
ret = rt9467_set_value_from_ranges(data, F_IEOC, RT9467_RANGE_IEOC, microamp); if (ret) goto out;
ret = rt9467_get_value_from_ranges(data, F_IEOC, RT9467_RANGE_IEOC, &data->ieoc_ua); if (ret) goto out;
switch (psp) { case POWER_SUPPLY_PROP_STATUS: return regmap_field_write(data->rm_field[F_CHG_EN], val->intval); case POWER_SUPPLY_PROP_ONLINE: return regmap_field_write(data->rm_field[F_HZ], val->intval); case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: return rt9467_psy_set_ichg(data, val->intval); case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: return rt9467_set_value_from_ranges(data, F_VOREG,
RT9467_RANGE_VOREG, val->intval); case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: if (val->intval == -1) return rt9467_run_aicl(data); else return rt9467_set_value_from_ranges(data, F_IAICR,
RT9467_RANGE_IAICR,
val->intval); case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: return rt9467_set_value_from_ranges(data, F_VMIVR,
RT9467_RANGE_VMIVR, val->intval); case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: return rt9467_set_value_from_ranges(data, F_IPREC,
RT9467_RANGE_IPREC, val->intval); case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: return rt9467_psy_set_ieoc(data, val->intval); default: return -EINVAL;
}
}
staticint rt9467_chg_prop_is_writeable(struct power_supply *psy, enum power_supply_property psp)
{ switch (psp) { case POWER_SUPPLY_PROP_STATUS: case POWER_SUPPLY_PROP_ONLINE: case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: return 1; default: return 0;
}
}
staticint rt9467_mivr_handler(struct rt9467_chg_data *data)
{ unsignedint mivr_act; int ret, ibus_ma;
/* * back-boost workaround * If (mivr_active & ibus < 100mA), toggle cfo bit
*/
ret = regmap_field_read(data->rm_field[F_CHG_MIVR], &mivr_act); if (ret) {
dev_err(data->dev, "Failed to read MIVR stat\n"); return ret;
}
if (!mivr_act) return 0;
ret = rt9467_get_adc(data, RT9467_ADC_IBUS, &ibus_ma); if (ret) {
dev_err(data->dev, "Failed to get IBUS\n"); return ret;
}
if (ibus_ma < 100000) {
ret = regmap_field_write(data->rm_field[F_CFO_EN], 0);
ret |= regmap_field_write(data->rm_field[F_CFO_EN], 1); if (ret)
dev_err(data->dev, "Failed to toggle cfo\n");
}
/* Any i2c communication can kick watchdog timer */
ret = regmap_read(data->regmap, RT9467_REG_DEVICE_ID, &dev_id); if (ret) {
dev_err(data->dev, "Failed to kick wdt (%d)\n", ret); return IRQ_NONE;
}
ret = regmap_field_read(data->rm_field[F_USB_STATUS], &usb_stat);
ret |= regmap_field_read(data->rm_field[F_PWR_RDY], &power_ready); if (ret) return ret;
if (!power_ready)
usb_stat = RT9467_CHG_TYPE_NOVBUS;
mutex_lock(&data->attach_lock);
switch (usb_stat) { case RT9467_CHG_TYPE_NOVBUS:
data->psy_usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN; break; case RT9467_CHG_TYPE_SDP:
data->psy_usb_type = POWER_SUPPLY_USB_TYPE_SDP; break; case RT9467_CHG_TYPE_SDPNSTD:
data->psy_usb_type = POWER_SUPPLY_USB_TYPE_DCP; break; case RT9467_CHG_TYPE_DCP:
data->psy_usb_type = POWER_SUPPLY_USB_TYPE_DCP; break; case RT9467_CHG_TYPE_CDP:
data->psy_usb_type = POWER_SUPPLY_USB_TYPE_CDP; break; case RT9467_CHG_TYPE_UNDER_GOING: default:
psy_changed = false; break;
}
for (i = 0; i < num_chg_irqs; i++) {
virq = regmap_irq_get_virq(data->irq_chip_data, chg_irqs[i].hwirq); if (virq <= 0) return dev_err_probe(dev, -EINVAL, "Failed to get (%s) irq\n",
chg_irqs[i].name);
ret = devm_request_threaded_irq(dev, virq, NULL, chg_irqs[i].handler,
IRQF_ONESHOT, chg_irqs[i].name, data); if (ret) return dev_err_probe(dev, ret, "Failed to request (%s) irq\n",
chg_irqs[i].name);
}
ret = regmap_write(data->regmap, RT9467_REG_CHG_ADC, 0); if (ret) return dev_err_probe(dev, ret, "Failed to reset ADC\n");
ret = rt9467_get_value_from_ranges(data, F_ICHG, RT9467_RANGE_ICHG,
&data->ichg_ua);
ret |= rt9467_get_value_from_ranges(data, F_IEOC, RT9467_RANGE_IEOC,
&data->ieoc_ua); if (ret) return dev_err_probe(dev, ret, "Failed to init ichg/ieoc value\n");
ret = regmap_update_bits(data->regmap, RT9467_REG_CHG_STATC_CTRL,
RT9467_MASK_PWR_RDY | RT9467_MASK_MIVR_STAT, 0); if (ret) return dev_err_probe(dev, ret, "Failed to make statc unmask\n");
/* Select IINLMTSEL to use AICR */
ret = regmap_field_write(data->rm_field[F_IINLMTSEL],
RT9467_IINLMTSEL_AICR); if (ret) return dev_err_probe(dev, ret, "Failed to set iinlmtsel to AICR\n");
/* Wait for AICR Rampping */
msleep(150);
/* Disable hardware ILIM */
ret = regmap_field_write(data->rm_field[F_ILIM_EN], 0); if (ret) return dev_err_probe(dev, ret, "Failed to disable hardware ILIM\n");
/* Set inductor OCP to high level */
ret = regmap_field_write(data->rm_field[F_OCP], 1); if (ret) return dev_err_probe(dev, ret, "Failed to set higher inductor OCP level\n");
/* Set charge termination default enable */
ret = regmap_field_write(data->rm_field[F_TE], 1); if (ret) return dev_err_probe(dev, ret, "Failed to set TE=1\n");
/* Set 12hrs fast charger timer */
ret = regmap_field_write(data->rm_field[F_WT_FC], 4); if (ret) return dev_err_probe(dev, ret, "Failed to set WT_FC\n");
/* Toggle BC12 function */
ret = regmap_field_write(data->rm_field[F_USBCHGEN], 0); if (ret) return dev_err_probe(dev, ret, "Failed to disable BC12\n");
/* Default pull charge enable gpio to make 'CHG_EN' by SW control only */
ceb_gpio = devm_gpiod_get_optional(dev, "charge-enable", GPIOD_OUT_HIGH); if (IS_ERR(ceb_gpio)) return dev_err_probe(dev, PTR_ERR(ceb_gpio), "Failed to config charge enable gpio\n");
data->regmap = devm_regmap_init_i2c(i2c, &rt9467_regmap_config); if (IS_ERR(data->regmap)) return dev_err_probe(dev, PTR_ERR(data->regmap), "Failed to init regmap\n");
ret = devm_regmap_field_bulk_alloc(dev, data->regmap,
data->rm_field, rt9467_chg_fields,
ARRAY_SIZE(rt9467_chg_fields)); if (ret) return dev_err_probe(dev, ret, "Failed to alloc regmap fields\n");
ret = rt9467_check_vendor_info(data); if (ret) return dev_err_probe(dev, ret, "Failed to check vendor info");
ret = rt9467_reset_chip(data); if (ret) return dev_err_probe(dev, ret, "Failed to reset chip\n");
ret = devm_regmap_add_irq_chip(dev, data->regmap, i2c->irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT, 0,
&rt9467_irq_chip, &data->irq_chip_data); if (ret) return dev_err_probe(dev, ret, "Failed to add irq chip\n");
mutex_init(&data->adc_lock);
ret = devm_add_action_or_reset(dev, rt9467_chg_destroy_adc_lock,
&data->adc_lock); if (ret) return dev_err_probe(dev, ret, "Failed to init ADC lock\n");
mutex_init(&data->attach_lock);
ret = devm_add_action_or_reset(dev, rt9467_chg_destroy_attach_lock,
&data->attach_lock); if (ret) return dev_err_probe(dev, ret, "Failed to init attach lock\n");
mutex_init(&data->ichg_ieoc_lock);
ret = devm_add_action_or_reset(dev, rt9467_chg_destroy_ichg_ieoc_lock,
&data->ichg_ieoc_lock); if (ret) return dev_err_probe(dev, ret, "Failed to init ICHG/IEOC lock\n");
init_completion(&data->aicl_done);
ret = devm_add_action_or_reset(dev, rt9467_chg_complete_aicl_done,
&data->aicl_done); if (ret) return dev_err_probe(dev, ret, "Failed to init AICL done completion\n");
ret = rt9467_do_charger_init(data); if (ret) return ret;
ret = rt9467_register_otg_regulator(data); if (ret) return ret;
ret = rt9467_register_psy(data); if (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.