955 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2022 Richtek Technology Corp.4 *5 * Author: ChiaEn Wu <chiaen_wu@richtek.com>6 */7 8#include <linux/bitfield.h>9#include <linux/bits.h>10#include <linux/devm-helpers.h>11#include <linux/gpio/consumer.h>12#include <linux/iio/consumer.h>13#include <linux/init.h>14#include <linux/interrupt.h>15#include <linux/kernel.h>16#include <linux/linear_range.h>17#include <linux/module.h>18#include <linux/of.h>19#include <linux/platform_device.h>20#include <linux/power_supply.h>21#include <linux/regmap.h>22#include <linux/regulator/driver.h>23#include <linux/workqueue.h>24 25#define MT6370_REG_CHG_CTRL1 0x11126#define MT6370_REG_CHG_CTRL2 0x11227#define MT6370_REG_CHG_CTRL3 0x11328#define MT6370_REG_CHG_CTRL4 0x11429#define MT6370_REG_CHG_CTRL5 0x11530#define MT6370_REG_CHG_CTRL6 0x11631#define MT6370_REG_CHG_CTRL7 0x11732#define MT6370_REG_CHG_CTRL8 0x11833#define MT6370_REG_CHG_CTRL9 0x11934#define MT6370_REG_CHG_CTRL10 0x11A35#define MT6370_REG_DEVICE_TYPE 0x12236#define MT6370_REG_USB_STATUS1 0x12737#define MT6370_REG_CHG_STAT 0x14A38#define MT6370_REG_FLED_EN 0x17E39#define MT6370_REG_CHG_STAT1 0X1D040#define MT6370_REG_OVPCTRL_STAT 0x1D841 42#define MT6370_VOBST_MASK GENMASK(7, 2)43#define MT6370_OTG_PIN_EN_MASK BIT(1)44#define MT6370_OPA_MODE_MASK BIT(0)45#define MT6370_OTG_OC_MASK GENMASK(2, 0)46 47#define MT6370_MIVR_IBUS_TH_100_mA 10000048#define MT6370_ADC_CHAN_IBUS 549#define MT6370_ADC_CHAN_MAX 950 51enum mt6370_chg_reg_field {52 /* MT6370_REG_CHG_CTRL2 */53 F_IINLMTSEL, F_CFO_EN, F_CHG_EN,54 /* MT6370_REG_CHG_CTRL3 */55 F_IAICR, F_AICR_EN, F_ILIM_EN,56 /* MT6370_REG_CHG_CTRL4 */57 F_VOREG,58 /* MT6370_REG_CHG_CTRL6 */59 F_VMIVR,60 /* MT6370_REG_CHG_CTRL7 */61 F_ICHG,62 /* MT6370_REG_CHG_CTRL8 */63 F_IPREC,64 /* MT6370_REG_CHG_CTRL9 */65 F_IEOC,66 /* MT6370_REG_DEVICE_TYPE */67 F_USBCHGEN,68 /* MT6370_REG_USB_STATUS1 */69 F_USB_STAT, F_CHGDET,70 /* MT6370_REG_CHG_STAT */71 F_CHG_STAT, F_BOOST_STAT, F_VBAT_LVL,72 /* MT6370_REG_FLED_EN */73 F_FL_STROBE,74 /* MT6370_REG_CHG_STAT1 */75 F_CHG_MIVR_STAT,76 /* MT6370_REG_OVPCTRL_STAT */77 F_UVP_D_STAT,78 F_MAX79};80 81enum mt6370_irq {82 MT6370_IRQ_ATTACH_I = 0,83 MT6370_IRQ_UVP_D_EVT,84 MT6370_IRQ_MIVR,85 MT6370_IRQ_MAX86};87 88struct mt6370_priv {89 struct device *dev;90 struct iio_channel *iio_adcs;91 struct mutex attach_lock;92 struct power_supply *psy;93 struct regmap *regmap;94 struct regmap_field *rmap_fields[F_MAX];95 struct regulator_dev *rdev;96 struct workqueue_struct *wq;97 struct work_struct bc12_work;98 struct delayed_work mivr_dwork;99 unsigned int irq_nums[MT6370_IRQ_MAX];100 int attach;101 int psy_usb_type;102 bool pwr_rdy;103};104 105enum mt6370_usb_status {106 MT6370_USB_STAT_NO_VBUS = 0,107 MT6370_USB_STAT_VBUS_FLOW_IS_UNDER_GOING,108 MT6370_USB_STAT_SDP,109 MT6370_USB_STAT_SDP_NSTD,110 MT6370_USB_STAT_DCP,111 MT6370_USB_STAT_CDP,112 MT6370_USB_STAT_MAX113};114 115struct mt6370_chg_field {116 const char *name;117 const struct linear_range *range;118 struct reg_field field;119};120 121enum {122 MT6370_RANGE_F_IAICR = 0,123 MT6370_RANGE_F_VOREG,124 MT6370_RANGE_F_VMIVR,125 MT6370_RANGE_F_ICHG,126 MT6370_RANGE_F_IPREC,127 MT6370_RANGE_F_IEOC,128 MT6370_RANGE_F_MAX129};130 131static const struct linear_range mt6370_chg_ranges[MT6370_RANGE_F_MAX] = {132 LINEAR_RANGE_IDX(MT6370_RANGE_F_IAICR, 100000, 0x0, 0x3F, 50000),133 LINEAR_RANGE_IDX(MT6370_RANGE_F_VOREG, 3900000, 0x0, 0x51, 10000),134 LINEAR_RANGE_IDX(MT6370_RANGE_F_VMIVR, 3900000, 0x0, 0x5F, 100000),135 LINEAR_RANGE_IDX(MT6370_RANGE_F_ICHG, 900000, 0x08, 0x31, 100000),136 LINEAR_RANGE_IDX(MT6370_RANGE_F_IPREC, 100000, 0x0, 0x0F, 50000),137 LINEAR_RANGE_IDX(MT6370_RANGE_F_IEOC, 100000, 0x0, 0x0F, 50000),138};139 140#define MT6370_CHG_FIELD(_fd, _reg, _lsb, _msb) \141[_fd] = { \142 .name = #_fd, \143 .range = NULL, \144 .field = REG_FIELD(_reg, _lsb, _msb), \145}146 147#define MT6370_CHG_FIELD_RANGE(_fd, _reg, _lsb, _msb) \148[_fd] = { \149 .name = #_fd, \150 .range = &mt6370_chg_ranges[MT6370_RANGE_##_fd], \151 .field = REG_FIELD(_reg, _lsb, _msb), \152}153 154static const struct mt6370_chg_field mt6370_chg_fields[F_MAX] = {155 MT6370_CHG_FIELD(F_IINLMTSEL, MT6370_REG_CHG_CTRL2, 2, 3),156 MT6370_CHG_FIELD(F_CFO_EN, MT6370_REG_CHG_CTRL2, 1, 1),157 MT6370_CHG_FIELD(F_CHG_EN, MT6370_REG_CHG_CTRL2, 0, 0),158 MT6370_CHG_FIELD_RANGE(F_IAICR, MT6370_REG_CHG_CTRL3, 2, 7),159 MT6370_CHG_FIELD(F_AICR_EN, MT6370_REG_CHG_CTRL3, 1, 1),160 MT6370_CHG_FIELD(F_ILIM_EN, MT6370_REG_CHG_CTRL3, 0, 0),161 MT6370_CHG_FIELD_RANGE(F_VOREG, MT6370_REG_CHG_CTRL4, 1, 7),162 MT6370_CHG_FIELD_RANGE(F_VMIVR, MT6370_REG_CHG_CTRL6, 1, 7),163 MT6370_CHG_FIELD_RANGE(F_ICHG, MT6370_REG_CHG_CTRL7, 2, 7),164 MT6370_CHG_FIELD_RANGE(F_IPREC, MT6370_REG_CHG_CTRL8, 0, 3),165 MT6370_CHG_FIELD_RANGE(F_IEOC, MT6370_REG_CHG_CTRL9, 4, 7),166 MT6370_CHG_FIELD(F_USBCHGEN, MT6370_REG_DEVICE_TYPE, 7, 7),167 MT6370_CHG_FIELD(F_USB_STAT, MT6370_REG_USB_STATUS1, 4, 6),168 MT6370_CHG_FIELD(F_CHGDET, MT6370_REG_USB_STATUS1, 3, 3),169 MT6370_CHG_FIELD(F_CHG_STAT, MT6370_REG_CHG_STAT, 6, 7),170 MT6370_CHG_FIELD(F_BOOST_STAT, MT6370_REG_CHG_STAT, 3, 3),171 MT6370_CHG_FIELD(F_VBAT_LVL, MT6370_REG_CHG_STAT, 5, 5),172 MT6370_CHG_FIELD(F_FL_STROBE, MT6370_REG_FLED_EN, 2, 2),173 MT6370_CHG_FIELD(F_CHG_MIVR_STAT, MT6370_REG_CHG_STAT1, 6, 6),174 MT6370_CHG_FIELD(F_UVP_D_STAT, MT6370_REG_OVPCTRL_STAT, 4, 4),175};176 177static inline int mt6370_chg_field_get(struct mt6370_priv *priv,178 enum mt6370_chg_reg_field fd,179 unsigned int *val)180{181 int ret;182 unsigned int reg_val;183 184 ret = regmap_field_read(priv->rmap_fields[fd], ®_val);185 if (ret)186 return ret;187 188 if (mt6370_chg_fields[fd].range)189 return linear_range_get_value(mt6370_chg_fields[fd].range,190 reg_val, val);191 192 *val = reg_val;193 return 0;194}195 196static inline int mt6370_chg_field_set(struct mt6370_priv *priv,197 enum mt6370_chg_reg_field fd,198 unsigned int val)199{200 int ret;201 bool f;202 const struct linear_range *r;203 204 if (mt6370_chg_fields[fd].range) {205 r = mt6370_chg_fields[fd].range;206 207 if (fd == F_VMIVR) {208 ret = linear_range_get_selector_high(r, val, &val, &f);209 if (ret)210 val = r->max_sel;211 } else {212 linear_range_get_selector_within(r, val, &val);213 }214 }215 216 return regmap_field_write(priv->rmap_fields[fd], val);217}218 219enum {220 MT6370_CHG_STAT_READY = 0,221 MT6370_CHG_STAT_CHARGE_IN_PROGRESS,222 MT6370_CHG_STAT_DONE,223 MT6370_CHG_STAT_FAULT,224 MT6370_CHG_STAT_MAX225};226 227enum {228 MT6370_ATTACH_STAT_DETACH = 0,229 MT6370_ATTACH_STAT_ATTACH_WAIT_FOR_BC12,230 MT6370_ATTACH_STAT_ATTACH_BC12_DONE,231 MT6370_ATTACH_STAT_ATTACH_MAX232};233 234static int mt6370_chg_otg_of_parse_cb(struct device_node *of,235 const struct regulator_desc *rdesc,236 struct regulator_config *rcfg)237{238 struct mt6370_priv *priv = rcfg->driver_data;239 240 rcfg->ena_gpiod = fwnode_gpiod_get_index(of_fwnode_handle(of),241 "enable", 0, GPIOD_OUT_LOW |242 GPIOD_FLAGS_BIT_NONEXCLUSIVE,243 rdesc->name);244 if (IS_ERR(rcfg->ena_gpiod)) {245 rcfg->ena_gpiod = NULL;246 return 0;247 }248 249 return regmap_update_bits(priv->regmap, MT6370_REG_CHG_CTRL1,250 MT6370_OTG_PIN_EN_MASK,251 MT6370_OTG_PIN_EN_MASK);252}253 254static void mt6370_chg_bc12_work_func(struct work_struct *work)255{256 struct mt6370_priv *priv = container_of(work, struct mt6370_priv,257 bc12_work);258 int ret;259 bool rpt_psy = false;260 unsigned int attach, usb_stat;261 262 mutex_lock(&priv->attach_lock);263 attach = priv->attach;264 265 switch (attach) {266 case MT6370_ATTACH_STAT_DETACH:267 usb_stat = 0;268 break;269 case MT6370_ATTACH_STAT_ATTACH_WAIT_FOR_BC12:270 ret = mt6370_chg_field_set(priv, F_USBCHGEN, attach);271 if (ret)272 dev_err(priv->dev, "Failed to enable USB CHG EN\n");273 goto bc12_work_func_out;274 case MT6370_ATTACH_STAT_ATTACH_BC12_DONE:275 ret = mt6370_chg_field_get(priv, F_USB_STAT, &usb_stat);276 if (ret) {277 dev_err(priv->dev, "Failed to get USB status\n");278 goto bc12_work_func_out;279 }280 break;281 default:282 dev_err(priv->dev, "Invalid attach state\n");283 goto bc12_work_func_out;284 }285 286 rpt_psy = true;287 288 switch (usb_stat) {289 case MT6370_USB_STAT_SDP:290 case MT6370_USB_STAT_SDP_NSTD:291 priv->psy_usb_type = POWER_SUPPLY_USB_TYPE_SDP;292 break;293 case MT6370_USB_STAT_DCP:294 priv->psy_usb_type = POWER_SUPPLY_USB_TYPE_DCP;295 break;296 case MT6370_USB_STAT_CDP:297 priv->psy_usb_type = POWER_SUPPLY_USB_TYPE_CDP;298 break;299 case MT6370_USB_STAT_NO_VBUS:300 case MT6370_USB_STAT_VBUS_FLOW_IS_UNDER_GOING:301 default:302 priv->psy_usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN;303 break;304 }305 306bc12_work_func_out:307 mutex_unlock(&priv->attach_lock);308 309 if (rpt_psy)310 power_supply_changed(priv->psy);311}312 313static int mt6370_chg_toggle_cfo(struct mt6370_priv *priv)314{315 int ret;316 unsigned int fl_strobe;317 318 /* check if flash led in strobe mode */319 ret = mt6370_chg_field_get(priv, F_FL_STROBE, &fl_strobe);320 if (ret) {321 dev_err(priv->dev, "Failed to get FL_STROBE_EN\n");322 return ret;323 }324 325 if (fl_strobe) {326 dev_err(priv->dev, "Flash led is still in strobe mode\n");327 return -EINVAL;328 }329 330 /* cfo off */331 ret = mt6370_chg_field_set(priv, F_CFO_EN, 0);332 if (ret) {333 dev_err(priv->dev, "Failed to disable CFO_EN\n");334 return ret;335 }336 337 /* cfo on */338 ret = mt6370_chg_field_set(priv, F_CFO_EN, 1);339 if (ret)340 dev_err(priv->dev, "Failed to enable CFO_EN\n");341 342 return ret;343}344 345static int mt6370_chg_read_adc_chan(struct mt6370_priv *priv, unsigned int chan,346 int *val)347{348 int ret;349 350 if (chan >= MT6370_ADC_CHAN_MAX)351 return -EINVAL;352 353 ret = iio_read_channel_processed(&priv->iio_adcs[chan], val);354 if (ret)355 dev_err(priv->dev, "Failed to read ADC\n");356 357 return ret;358}359 360static void mt6370_chg_mivr_dwork_func(struct work_struct *work)361{362 struct mt6370_priv *priv = container_of(work, struct mt6370_priv,363 mivr_dwork.work);364 int ret;365 unsigned int mivr_stat, ibus;366 367 ret = mt6370_chg_field_get(priv, F_CHG_MIVR_STAT, &mivr_stat);368 if (ret) {369 dev_err(priv->dev, "Failed to get mivr state\n");370 goto mivr_handler_out;371 }372 373 if (!mivr_stat)374 goto mivr_handler_out;375 376 ret = mt6370_chg_read_adc_chan(priv, MT6370_ADC_CHAN_IBUS, &ibus);377 if (ret) {378 dev_err(priv->dev, "Failed to get ibus\n");379 goto mivr_handler_out;380 }381 382 if (ibus < MT6370_MIVR_IBUS_TH_100_mA) {383 ret = mt6370_chg_toggle_cfo(priv);384 if (ret)385 dev_err(priv->dev, "Failed to toggle cfo\n");386 }387 388mivr_handler_out:389 enable_irq(priv->irq_nums[MT6370_IRQ_MIVR]);390 pm_relax(priv->dev);391}392 393static void mt6370_chg_pwr_rdy_check(struct mt6370_priv *priv)394{395 int ret;396 unsigned int opposite_pwr_rdy, otg_en;397 union power_supply_propval val;398 399 /* Check in OTG mode or not */400 ret = mt6370_chg_field_get(priv, F_BOOST_STAT, &otg_en);401 if (ret) {402 dev_err(priv->dev, "Failed to get OTG state\n");403 return;404 }405 406 if (otg_en)407 return;408 409 ret = mt6370_chg_field_get(priv, F_UVP_D_STAT, &opposite_pwr_rdy);410 if (ret) {411 dev_err(priv->dev, "Failed to get opposite power ready state\n");412 return;413 }414 415 val.intval = opposite_pwr_rdy ?416 MT6370_ATTACH_STAT_DETACH :417 MT6370_ATTACH_STAT_ATTACH_WAIT_FOR_BC12;418 419 ret = power_supply_set_property(priv->psy, POWER_SUPPLY_PROP_ONLINE,420 &val);421 if (ret)422 dev_err(priv->dev, "Failed to start attach/detach flow\n");423}424 425static int mt6370_chg_get_online(struct mt6370_priv *priv,426 union power_supply_propval *val)427{428 mutex_lock(&priv->attach_lock);429 val->intval = !!priv->attach;430 mutex_unlock(&priv->attach_lock);431 432 return 0;433}434 435static int mt6370_chg_get_status(struct mt6370_priv *priv,436 union power_supply_propval *val)437{438 int ret;439 unsigned int chg_stat;440 union power_supply_propval online;441 442 ret = power_supply_get_property(priv->psy, POWER_SUPPLY_PROP_ONLINE,443 &online);444 if (ret) {445 dev_err(priv->dev, "Failed to get online status\n");446 return ret;447 }448 449 if (!online.intval) {450 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;451 return 0;452 }453 454 ret = mt6370_chg_field_get(priv, F_CHG_STAT, &chg_stat);455 if (ret)456 return ret;457 458 switch (chg_stat) {459 case MT6370_CHG_STAT_READY:460 case MT6370_CHG_STAT_FAULT:461 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;462 return ret;463 case MT6370_CHG_STAT_CHARGE_IN_PROGRESS:464 val->intval = POWER_SUPPLY_STATUS_CHARGING;465 return ret;466 case MT6370_CHG_STAT_DONE:467 val->intval = POWER_SUPPLY_STATUS_FULL;468 return ret;469 default:470 val->intval = POWER_SUPPLY_STATUS_UNKNOWN;471 return ret;472 }473}474 475static int mt6370_chg_get_charge_type(struct mt6370_priv *priv,476 union power_supply_propval *val)477{478 int type, ret;479 unsigned int chg_stat, vbat_lvl;480 481 ret = mt6370_chg_field_get(priv, F_CHG_STAT, &chg_stat);482 if (ret)483 return ret;484 485 ret = mt6370_chg_field_get(priv, F_VBAT_LVL, &vbat_lvl);486 if (ret)487 return ret;488 489 switch (chg_stat) {490 case MT6370_CHG_STAT_CHARGE_IN_PROGRESS:491 if (vbat_lvl)492 type = POWER_SUPPLY_CHARGE_TYPE_FAST;493 else494 type = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;495 break;496 case MT6370_CHG_STAT_READY:497 case MT6370_CHG_STAT_DONE:498 case MT6370_CHG_STAT_FAULT:499 default:500 type = POWER_SUPPLY_CHARGE_TYPE_NONE;501 break;502 }503 504 val->intval = type;505 506 return 0;507}508 509static int mt6370_chg_set_online(struct mt6370_priv *priv,510 const union power_supply_propval *val)511{512 bool pwr_rdy = !!val->intval;513 514 mutex_lock(&priv->attach_lock);515 if (pwr_rdy == !!priv->attach) {516 dev_err(priv->dev, "pwr_rdy is same(%d)\n", pwr_rdy);517 mutex_unlock(&priv->attach_lock);518 return 0;519 }520 521 priv->attach = pwr_rdy;522 mutex_unlock(&priv->attach_lock);523 524 if (!queue_work(priv->wq, &priv->bc12_work))525 dev_err(priv->dev, "bc12 work has already queued\n");526 527 return 0;528}529 530static int mt6370_chg_get_property(struct power_supply *psy,531 enum power_supply_property psp,532 union power_supply_propval *val)533{534 struct mt6370_priv *priv = power_supply_get_drvdata(psy);535 536 switch (psp) {537 case POWER_SUPPLY_PROP_ONLINE:538 return mt6370_chg_get_online(priv, val);539 case POWER_SUPPLY_PROP_STATUS:540 return mt6370_chg_get_status(priv, val);541 case POWER_SUPPLY_PROP_CHARGE_TYPE:542 return mt6370_chg_get_charge_type(priv, val);543 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:544 return mt6370_chg_field_get(priv, F_ICHG, &val->intval);545 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:546 val->intval = linear_range_get_max_value(&mt6370_chg_ranges[MT6370_RANGE_F_ICHG]);547 return 0;548 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:549 return mt6370_chg_field_get(priv, F_VOREG, &val->intval);550 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:551 val->intval = linear_range_get_max_value(&mt6370_chg_ranges[MT6370_RANGE_F_VOREG]);552 return 0;553 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:554 return mt6370_chg_field_get(priv, F_IAICR, &val->intval);555 case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:556 return mt6370_chg_field_get(priv, F_VMIVR, &val->intval);557 case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:558 return mt6370_chg_field_get(priv, F_IPREC, &val->intval);559 case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:560 return mt6370_chg_field_get(priv, F_IEOC, &val->intval);561 case POWER_SUPPLY_PROP_USB_TYPE:562 val->intval = priv->psy_usb_type;563 return 0;564 default:565 return -EINVAL;566 }567}568 569static int mt6370_chg_set_property(struct power_supply *psy,570 enum power_supply_property psp,571 const union power_supply_propval *val)572{573 struct mt6370_priv *priv = power_supply_get_drvdata(psy);574 575 switch (psp) {576 case POWER_SUPPLY_PROP_ONLINE:577 return mt6370_chg_set_online(priv, val);578 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:579 return mt6370_chg_field_set(priv, F_ICHG, val->intval);580 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:581 return mt6370_chg_field_set(priv, F_VOREG, val->intval);582 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:583 return mt6370_chg_field_set(priv, F_IAICR, val->intval);584 case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:585 return mt6370_chg_field_set(priv, F_VMIVR, val->intval);586 case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:587 return mt6370_chg_field_set(priv, F_IPREC, val->intval);588 case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:589 return mt6370_chg_field_set(priv, F_IEOC, val->intval);590 default:591 return -EINVAL;592 }593}594 595static int mt6370_chg_property_is_writeable(struct power_supply *psy,596 enum power_supply_property psp)597{598 switch (psp) {599 case POWER_SUPPLY_PROP_ONLINE:600 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:601 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:602 case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:603 case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:604 case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:605 case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:606 return 1;607 default:608 return 0;609 }610}611 612static enum power_supply_property mt6370_chg_properties[] = {613 POWER_SUPPLY_PROP_ONLINE,614 POWER_SUPPLY_PROP_STATUS,615 POWER_SUPPLY_PROP_CHARGE_TYPE,616 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,617 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,618 POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,619 POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,620 POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,621 POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT,622 POWER_SUPPLY_PROP_PRECHARGE_CURRENT,623 POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,624 POWER_SUPPLY_PROP_USB_TYPE,625};626 627static const struct power_supply_desc mt6370_chg_psy_desc = {628 .name = "mt6370-charger",629 .type = POWER_SUPPLY_TYPE_USB,630 .properties = mt6370_chg_properties,631 .num_properties = ARRAY_SIZE(mt6370_chg_properties),632 .get_property = mt6370_chg_get_property,633 .set_property = mt6370_chg_set_property,634 .property_is_writeable = mt6370_chg_property_is_writeable,635 .usb_types = BIT(POWER_SUPPLY_USB_TYPE_SDP) |636 BIT(POWER_SUPPLY_USB_TYPE_CDP) |637 BIT(POWER_SUPPLY_USB_TYPE_DCP) |638 BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN),639};640 641static const struct regulator_ops mt6370_chg_otg_ops = {642 .list_voltage = regulator_list_voltage_linear,643 .enable = regulator_enable_regmap,644 .disable = regulator_disable_regmap,645 .is_enabled = regulator_is_enabled_regmap,646 .set_voltage_sel = regulator_set_voltage_sel_regmap,647 .get_voltage_sel = regulator_get_voltage_sel_regmap,648 .set_current_limit = regulator_set_current_limit_regmap,649 .get_current_limit = regulator_get_current_limit_regmap,650};651 652static const u32 mt6370_chg_otg_oc_ma[] = {653 500000, 700000, 1100000, 1300000, 1800000, 2100000, 2400000,654};655 656static const struct regulator_desc mt6370_chg_otg_rdesc = {657 .of_match = "usb-otg-vbus-regulator",658 .of_parse_cb = mt6370_chg_otg_of_parse_cb,659 .name = "mt6370-usb-otg-vbus",660 .ops = &mt6370_chg_otg_ops,661 .owner = THIS_MODULE,662 .type = REGULATOR_VOLTAGE,663 .min_uV = 4425000,664 .uV_step = 25000,665 .n_voltages = 57,666 .vsel_reg = MT6370_REG_CHG_CTRL5,667 .vsel_mask = MT6370_VOBST_MASK,668 .enable_reg = MT6370_REG_CHG_CTRL1,669 .enable_mask = MT6370_OPA_MODE_MASK,670 .curr_table = mt6370_chg_otg_oc_ma,671 .n_current_limits = ARRAY_SIZE(mt6370_chg_otg_oc_ma),672 .csel_reg = MT6370_REG_CHG_CTRL10,673 .csel_mask = MT6370_OTG_OC_MASK,674};675 676static int mt6370_chg_init_rmap_fields(struct mt6370_priv *priv)677{678 int i;679 const struct mt6370_chg_field *fds = mt6370_chg_fields;680 681 for (i = 0; i < F_MAX; i++) {682 priv->rmap_fields[i] = devm_regmap_field_alloc(priv->dev,683 priv->regmap,684 fds[i].field);685 if (IS_ERR(priv->rmap_fields[i]))686 return dev_err_probe(priv->dev,687 PTR_ERR(priv->rmap_fields[i]),688 "Failed to allocate regmapfield[%s]\n",689 fds[i].name);690 }691 692 return 0;693}694 695static int mt6370_chg_init_setting(struct mt6370_priv *priv)696{697 int ret;698 699 /* Disable usb_chg_en */700 ret = mt6370_chg_field_set(priv, F_USBCHGEN, 0);701 if (ret) {702 dev_err(priv->dev, "Failed to disable usb_chg_en\n");703 return ret;704 }705 706 /* Disable input current limit */707 ret = mt6370_chg_field_set(priv, F_ILIM_EN, 0);708 if (ret) {709 dev_err(priv->dev, "Failed to disable input current limit\n");710 return ret;711 }712 713 /* ICHG/IEOC Workaround, ICHG can not be set less than 900mA */714 ret = mt6370_chg_field_set(priv, F_ICHG, 900000);715 if (ret) {716 dev_err(priv->dev, "Failed to set ICHG to 900mA");717 return ret;718 }719 720 /* Change input current limit selection to using IAICR results */721 ret = mt6370_chg_field_set(priv, F_IINLMTSEL, 2);722 if (ret) {723 dev_err(priv->dev, "Failed to set IINLMTSEL\n");724 return ret;725 }726 727 return 0;728}729 730#define MT6370_CHG_DT_PROP_DECL(_name, _type, _field) \731{ \732 .name = "mediatek,chg-" #_name, \733 .type = MT6370_PARSE_TYPE_##_type, \734 .fd = _field, \735}736 737static int mt6370_chg_init_otg_regulator(struct mt6370_priv *priv)738{739 struct regulator_config rcfg = {740 .dev = priv->dev,741 .regmap = priv->regmap,742 .driver_data = priv,743 };744 745 priv->rdev = devm_regulator_register(priv->dev, &mt6370_chg_otg_rdesc,746 &rcfg);747 748 return PTR_ERR_OR_ZERO(priv->rdev);749}750 751static int mt6370_chg_init_psy(struct mt6370_priv *priv)752{753 struct power_supply_config cfg = {754 .drv_data = priv,755 .of_node = dev_of_node(priv->dev),756 };757 758 priv->psy = devm_power_supply_register(priv->dev, &mt6370_chg_psy_desc,759 &cfg);760 761 return PTR_ERR_OR_ZERO(priv->psy);762}763 764static void mt6370_chg_destroy_attach_lock(void *data)765{766 struct mutex *attach_lock = data;767 768 mutex_destroy(attach_lock);769}770 771static void mt6370_chg_destroy_wq(void *data)772{773 struct workqueue_struct *wq = data;774 775 flush_workqueue(wq);776 destroy_workqueue(wq);777}778 779static irqreturn_t mt6370_attach_i_handler(int irq, void *data)780{781 struct mt6370_priv *priv = data;782 unsigned int otg_en;783 int ret;784 785 /* Check in OTG mode or not */786 ret = mt6370_chg_field_get(priv, F_BOOST_STAT, &otg_en);787 if (ret) {788 dev_err(priv->dev, "Failed to get OTG state\n");789 return IRQ_NONE;790 }791 792 if (otg_en)793 return IRQ_HANDLED;794 795 mutex_lock(&priv->attach_lock);796 priv->attach = MT6370_ATTACH_STAT_ATTACH_BC12_DONE;797 mutex_unlock(&priv->attach_lock);798 799 if (!queue_work(priv->wq, &priv->bc12_work))800 dev_err(priv->dev, "bc12 work has already queued\n");801 802 return IRQ_HANDLED;803}804 805static irqreturn_t mt6370_uvp_d_evt_handler(int irq, void *data)806{807 struct mt6370_priv *priv = data;808 809 mt6370_chg_pwr_rdy_check(priv);810 811 return IRQ_HANDLED;812}813 814static irqreturn_t mt6370_mivr_handler(int irq, void *data)815{816 struct mt6370_priv *priv = data;817 818 pm_stay_awake(priv->dev);819 disable_irq_nosync(priv->irq_nums[MT6370_IRQ_MIVR]);820 schedule_delayed_work(&priv->mivr_dwork, msecs_to_jiffies(200));821 822 return IRQ_HANDLED;823}824 825#define MT6370_CHG_IRQ(_name) \826{ \827 .name = #_name, \828 .handler = mt6370_##_name##_handler, \829}830 831static int mt6370_chg_init_irq(struct mt6370_priv *priv)832{833 int i, ret;834 const struct {835 char *name;836 irq_handler_t handler;837 } mt6370_chg_irqs[] = {838 MT6370_CHG_IRQ(attach_i),839 MT6370_CHG_IRQ(uvp_d_evt),840 MT6370_CHG_IRQ(mivr),841 };842 843 for (i = 0; i < ARRAY_SIZE(mt6370_chg_irqs); i++) {844 ret = platform_get_irq_byname(to_platform_device(priv->dev),845 mt6370_chg_irqs[i].name);846 if (ret < 0)847 return ret;848 849 priv->irq_nums[i] = ret;850 ret = devm_request_threaded_irq(priv->dev, ret, NULL,851 mt6370_chg_irqs[i].handler,852 IRQF_TRIGGER_FALLING,853 dev_name(priv->dev), priv);854 if (ret)855 return dev_err_probe(priv->dev, ret,856 "Failed to request irq %s\n",857 mt6370_chg_irqs[i].name);858 }859 860 return 0;861}862 863static int mt6370_chg_probe(struct platform_device *pdev)864{865 struct device *dev = &pdev->dev;866 struct mt6370_priv *priv;867 int ret;868 869 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);870 if (!priv)871 return -ENOMEM;872 873 priv->dev = &pdev->dev;874 875 priv->regmap = dev_get_regmap(pdev->dev.parent, NULL);876 if (!priv->regmap)877 return dev_err_probe(dev, -ENODEV, "Failed to get regmap\n");878 879 ret = mt6370_chg_init_rmap_fields(priv);880 if (ret)881 return dev_err_probe(dev, ret, "Failed to init regmap fields\n");882 883 platform_set_drvdata(pdev, priv);884 885 priv->iio_adcs = devm_iio_channel_get_all(priv->dev);886 if (IS_ERR(priv->iio_adcs))887 return dev_err_probe(dev, PTR_ERR(priv->iio_adcs),888 "Failed to get iio adc\n");889 890 ret = mt6370_chg_init_otg_regulator(priv);891 if (ret)892 return dev_err_probe(dev, ret, "Failed to init OTG regulator\n");893 894 ret = mt6370_chg_init_psy(priv);895 if (ret)896 return dev_err_probe(dev, ret, "Failed to init psy\n");897 898 mutex_init(&priv->attach_lock);899 ret = devm_add_action_or_reset(dev, mt6370_chg_destroy_attach_lock,900 &priv->attach_lock);901 if (ret)902 return dev_err_probe(dev, ret, "Failed to init attach lock\n");903 904 priv->attach = MT6370_ATTACH_STAT_DETACH;905 906 priv->wq = create_singlethread_workqueue(dev_name(priv->dev));907 if (!priv->wq)908 return dev_err_probe(dev, -ENOMEM,909 "Failed to create workqueue\n");910 911 ret = devm_add_action_or_reset(dev, mt6370_chg_destroy_wq, priv->wq);912 if (ret)913 return dev_err_probe(dev, ret, "Failed to init wq\n");914 915 ret = devm_work_autocancel(dev, &priv->bc12_work, mt6370_chg_bc12_work_func);916 if (ret)917 return dev_err_probe(dev, ret, "Failed to init bc12 work\n");918 919 ret = devm_delayed_work_autocancel(dev, &priv->mivr_dwork, mt6370_chg_mivr_dwork_func);920 if (ret)921 return dev_err_probe(dev, ret, "Failed to init mivr delayed work\n");922 923 ret = mt6370_chg_init_setting(priv);924 if (ret)925 return dev_err_probe(dev, ret,926 "Failed to init mt6370 charger setting\n");927 928 ret = mt6370_chg_init_irq(priv);929 if (ret)930 return ret;931 932 mt6370_chg_pwr_rdy_check(priv);933 934 return 0;935}936 937static const struct of_device_id mt6370_chg_of_match[] = {938 { .compatible = "mediatek,mt6370-charger", },939 {}940};941MODULE_DEVICE_TABLE(of, mt6370_chg_of_match);942 943static struct platform_driver mt6370_chg_driver = {944 .probe = mt6370_chg_probe,945 .driver = {946 .name = "mt6370-charger",947 .of_match_table = mt6370_chg_of_match,948 },949};950module_platform_driver(mt6370_chg_driver);951 952MODULE_AUTHOR("ChiaEn Wu <chiaen_wu@richtek.com>");953MODULE_DESCRIPTION("MediaTek MT6370 Charger Driver");954MODULE_LICENSE("GPL v2");955