| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092 |
- /* Copyright Statement:
- *
- * This software/firmware and related documentation ("MediaTek Software") are
- * protected under relevant copyright laws. The information contained herein
- * is confidential and proprietary to MediaTek Inc. and/or its licensors.
- * Without the prior written permission of MediaTek inc. and/or its licensors,
- * any reproduction, modification, use or disclosure of MediaTek Software,
- * and information contained herein, in whole or in part,
- * shall be strictly prohibited.
- */
- /* MediaTek Inc. (C) 2015. All rights reserved.
- *
- * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
- * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
- * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
- * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
- * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
- * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
- * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
- * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY
- * ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY
- * THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL
- * ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO RECEIVER'S
- * SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM.
- * RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE
- * LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
- * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
- * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
- * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
- */
- #include <platform/mt_typedefs.h>
- #include <platform/errno.h>
- #include <platform/mt_i2c.h>
- #include <printf.h>
- #include <debug.h>
- #include <platform/timer.h>
- #include "mt6360_pmu_charger.h"
- #include "mtk_charger_intf.h"
- #define MT6360_PMU_CHARGER_LK_DRV_VERSION "1.0.0_MTK"
- /* ================= */
- /* Internal variable */
- /* ================= */
- enum mt6360_chg_mode {
- MT6360_CHG_MODE_UNKNOWN,
- MT6360_CHG_MODE_TRICHG,
- MT6360_CHG_MODE_PRECHG,
- MT6360_CHG_MODE_FASTCHG,
- };
- static const char *mt6360_chg_mode_name[] = {
- "unknown",
- "trickle-charge",
- "pre-charge",
- "fast-charge",
- };
- struct mt6360_pmu_chg_info {
- struct mtk_charger_info mchr_info;
- struct mt_i2c_t i2c;
- int i2c_log_level;
- u8 vid;
- u32 iprec;
- u32 ichg;
- u32 ichg_dis_chg;
- bool chg_en;
- u32 aicr;
- u32 mivr;
- u32 cv;
- bool wkard_en;
- };
- enum mt6360_iinlmtsel {
- MT6360_IIMLMTSEL_AICR_3250 = 0,
- MT6360_IIMLMTSEL_CHR_TYPE,
- MT6360_IINLMTSEL_AICR,
- MT6360_IINLMTSEL_LOWER_LEVEL, /* lower of above three */
- };
- enum mt6360_charging_status {
- MT6360_CHG_STATUS_READY = 0,
- MT6360_CHG_STATUS_PROGRESS,
- MT6360_CHG_STATUS_DONE,
- MT6360_CHG_STATUS_FAULT,
- MT6360_CHG_STATUS_MAX,
- };
- /* Charging status name */
- static const char *mt6360_chg_status_name[MT6360_CHG_STATUS_MAX] = {
- "ready", "progress", "done", "fault",
- };
- /* ========================= */
- /* I2C operations */
- /* ========================= */
- static int mt6360_i2c_write_byte(struct mt6360_pmu_chg_info *info,
- u8 cmd, u8 data)
- {
- struct mt_i2c_t *i2c = &info->i2c;
- int ret = I2C_OK;
- u8 write_buf[2] = {cmd, data};
- ret = i2c_write(i2c, write_buf, 2);
- if (ret != I2C_OK)
- dprintf(CRITICAL,
- "%s: I2CW[0x%02X] = 0x%02X failed, code = %d\n",
- __func__, cmd, data, ret);
- else
- dprintf(info->i2c_log_level, "%s: I2CW[0x%02X] = 0x%02X\n",
- __func__, cmd, data);
- return ret;
- }
- static int mt6360_i2c_read_byte(struct mt6360_pmu_chg_info *info,
- u8 cmd, u8 *data)
- {
- struct mt_i2c_t *i2c = &info->i2c;
- int ret = I2C_OK;
- u8 ret_data = cmd;
- ret = i2c_write_read(i2c, &ret_data, 1, 1);
- if (ret != I2C_OK)
- dprintf(CRITICAL, "%s: I2CR[0x%02X] failed, code = %d\n",
- __func__, cmd, ret);
- else {
- dprintf(info->i2c_log_level, "%s: I2CR[0x%02X] = 0x%02X\n",
- __func__, cmd, ret_data);
- *data = ret_data;
- }
- return ret;
- }
- static int mt6360_i2c_block_write(struct mt6360_pmu_chg_info *info,
- u8 cmd, int len, const u8 *data)
- {
- struct mt_i2c_t *i2c = &info->i2c;
- unsigned char write_buf[len + 1];
- write_buf[0] = cmd;
- memcpy(&write_buf[1], data, len);
- return i2c_write(i2c, write_buf, len + 1);
- }
- static int mt6360_i2c_block_read(struct mt6360_pmu_chg_info *info,
- u8 cmd, int len, u8 *data)
- {
- struct mt_i2c_t *i2c = &info->i2c;
- data[0] = cmd;
- return i2c_write_read(i2c, data, 1, len);
- }
- static int mt6360_i2c_update_bits(struct mt6360_pmu_chg_info *info,
- u8 cmd, u8 mask, u8 data)
- {
- int ret = 0;
- u8 reg_data = 0;
- ret = mt6360_i2c_read_byte(info, cmd, ®_data);
- if (ret != I2C_OK)
- return ret;
- reg_data = reg_data & 0xFF;
- reg_data &= ~mask;
- reg_data |= (data & mask);
- return mt6360_i2c_write_byte(info, cmd, reg_data);
- }
- static inline int mt6360_set_bit(struct mt6360_pmu_chg_info *info,
- u8 reg, u8 mask)
- {
- return mt6360_i2c_update_bits(info, reg, mask, mask);
- }
- static inline int mt6360_clr_bit(struct mt6360_pmu_chg_info *info,
- u8 reg, u8 mask)
- {
- return mt6360_i2c_update_bits(info, reg, mask, 0x00);
- }
- /* ================== */
- /* internal functions */
- /* ================== */
- static int mt6360_enable_hidden_mode(struct mt6360_pmu_chg_info *info, bool en)
- {
- return mt6360_i2c_write_byte(info, MT6360_PMU_TM_PAS_CODE1, en ? 0x69 : 0);
- }
- static bool mt6360_is_hw_exist(struct mt6360_pmu_chg_info *info)
- {
- int ret = 0;
- u8 vid = 0, rev_id = 0;
- u8 data = 0;
- ret = mt6360_i2c_read_byte(info, MT6360_PMU_DEV_INFO, &data);
- if (ret != I2C_OK)
- return false;
- vid = data & 0xF0;
- rev_id = data & 0x0F;
- if (vid != MT6360_VENDOR_ID) {
- dprintf(CRITICAL, "%s: vid is not match(%d)\n", __func__, vid);
- return false;
- }
- dprintf(CRITICAL, "%s: rev_id = %d\n", __func__, rev_id);
- info->mchr_info.device_id = rev_id;
- info->vid = vid;
- return true;
- }
- static int mt6360_enable_ilim(struct mt6360_pmu_chg_info *info, bool enable)
- {
- dprintf(CRITICAL, "%s: enable ilim = %d\n", __func__, enable);
- return (enable ? mt6360_set_bit : mt6360_clr_bit)
- (info, MT6360_PMU_CHG_CTRL3, MT6360_MASK_ILIM_EN);
- }
- /* Select IINLMTSEL to use AICR */
- static int mt6360_select_input_current_limit(
- struct mt6360_pmu_chg_info *info, enum mt6360_iinlmtsel sel)
- {
- dprintf(CRITICAL, "%s: select input current limit = %d\n",
- __func__, sel);
- return mt6360_i2c_update_bits(info,
- MT6360_PMU_CHG_CTRL2,
- MT6360_MASK_IINLMTSEL,
- sel << MT6360_SHFT_IINLMTSEL);
- }
- static int mt6360_set_cv(struct mt6360_pmu_chg_info *info, u32 uV)
- {
- u8 data = 0;
- if (uV >= 3900)
- data = (uV - 3900) / 10;
- if (data > MT6360_VOREG_MAXVAL)
- data = MT6360_VOREG_MAXVAL;
- dprintf(CRITICAL, "%s: cv = %d\n", __func__, uV);
- return mt6360_i2c_update_bits(info,
- MT6360_PMU_CHG_CTRL4,
- MT6360_MASK_VOREG,
- data << MT6360_SHFT_VOREG);
- }
- static int mt6360_enable_wdt(struct mt6360_pmu_chg_info *info, bool en)
- {
- dprintf(CRITICAL, "%s: en = %d\n", __func__, en);
- return (en ? mt6360_set_bit : mt6360_clr_bit)
- (info, MT6360_PMU_CHG_CTRL13, MT6360_MASK_CHG_WDT_EN);
- }
- static int mt6360_get_charging_status(struct mt6360_pmu_chg_info *info,
- enum mt6360_charging_status *chg_stat)
- {
- int ret = 0;
- u8 data = 0;
- ret = mt6360_i2c_read_byte(info, MT6360_PMU_CHG_STAT, &data);
- if (ret != I2C_OK)
- return ret;
- *chg_stat = (data & MT6360_MASK_CHG_STAT) >> MT6360_SHFT_CHG_STAT;
- return ret;
- }
- static int mt6360_get_mivr(struct mt6360_pmu_chg_info *info, u32 *mivr)
- {
- int ret = 0;
- u8 data = 0;
- ret = mt6360_i2c_read_byte(info, MT6360_PMU_CHG_CTRL6, &data);
- if (ret != I2C_OK)
- return ret;
- data = (data & MT6360_MASK_MIVR) >> MT6360_SHFT_MIVR;
- *mivr = 3900 + (data * 100);
- return ret;
- }
- static int mt6360_get_ieoc(struct mt6360_pmu_chg_info *info, u32 *ieoc)
- {
- int ret = 0;
- u8 data = 0;
- ret = mt6360_i2c_read_byte(info, MT6360_PMU_CHG_CTRL9, &data);
- if (ret != I2C_OK)
- return ret;
- data = (data & MT6360_MASK_IEOC) >> MT6360_SHFT_IEOC;
- *ieoc = 100 + (data * 50);
- return ret;
- }
- static int mt6360_is_charging_enable(struct mt6360_pmu_chg_info *info,
- bool *enable)
- {
- int ret = 0;
- u8 data = 0;
- ret = mt6360_i2c_read_byte(info, MT6360_PMU_CHG_CTRL2, &data);
- if (ret != I2C_OK)
- return ret;
- *enable = (data & MT6360_MASK_CHG_EN) ? true : false;
- return ret;
- }
- /* =========================================================== */
- /* The following is implementation for interface of mt_charger */
- /* =========================================================== */
- static int mt_charger_set_ichg(struct mtk_charger_info *mchr_info, u32 ichg)
- {
- struct mt6360_pmu_chg_info *info =
- (struct mt6360_pmu_chg_info *)mchr_info;
- int ret = 0;
- u8 data = 0;
- dprintf(CRITICAL, "%s: ichg = %d\n", __func__, ichg);
- if (ichg >= 100)
- data = (ichg - 100) / 100;
- if (data > MT6360_ICHG_MAXVAL)
- data = MT6360_ICHG_MAXVAL;
- ret = mt6360_i2c_update_bits(info,
- MT6360_PMU_CHG_CTRL7,
- MT6360_MASK_ICHG,
- data << MT6360_SHFT_ICHG);
- if (ret < 0)
- dprintf(CRITICAL, "%s: fail(%d)\n", __func__, ret);
- else
- info->ichg = ichg;
- return ret;
- }
- static int mt_charger_enable_charging(struct mtk_charger_info *mchr_info,
- bool enable)
- {
- struct mt6360_pmu_chg_info *info =
- (struct mt6360_pmu_chg_info *)mchr_info;
- int ret = 0;
- u32 ichg_ramp_t = 0;
- u8 data = 0;
- if (info->chg_en == enable) {
- dprintf(CRITICAL,
- "%s: is the same, en = %d\n", __func__, enable);
- return 0;
- }
- ret = mt6360_i2c_read_byte(info, MT6360_PMU_CHRDET_STAT, &data);
- if (ret != I2C_OK)
- goto bypass_wkard;
- if (!(data & MT6360_MASK_CHRDET_EXT_EVT)) {
- dprintf(CRITICAL, "%s: pwr_rdy = 0, bypass wkard\n", __func__);
- goto bypass_wkard;
- }
- if (info->ichg < 500) {
- dprintf(CRITICAL, "%s: ichg < 500, bypass wkard\n", __func__);
- goto bypass_wkard;
- }
- /* Workaround for avoid vsys overshoot when charge disable */
- if (!enable) {
- info->ichg_dis_chg = info->ichg;
- ichg_ramp_t = (info->ichg - 500) / 50 * 2;
- /* Set ichg 500mA */
- ret = mt6360_i2c_update_bits(info,
- MT6360_PMU_CHG_CTRL7,
- MT6360_MASK_ICHG,
- 0x04 << MT6360_SHFT_ICHG);
- if (ret < 0) {
- dprintf(CRITICAL, "%s: set ichg fail\n", __func__);
- return ret;
- }
- mdelay(ichg_ramp_t);
- } else {
- if (info->ichg == info->ichg_dis_chg) {
- ret = mt_charger_set_ichg(mchr_info, info->ichg);
- if (ret < 0) {
- dprintf(CRITICAL,
- "%s: set ichg fail\n", __func__);
- return ret;
- }
- }
- }
- bypass_wkard:
- ret = (enable ? mt6360_set_bit : mt6360_clr_bit)
- (info, MT6360_PMU_CHG_CTRL2, MT6360_MASK_CHG_EN);
- if (ret < 0)
- dprintf(CRITICAL, "%s: fail, en = %d\n", __func__, enable);
- else
- info->chg_en = enable;
- return ret;
- }
- static int mt_charger_get_ichg(struct mtk_charger_info *mchr_info, u32 *ichg)
- {
- struct mt6360_pmu_chg_info *info =
- (struct mt6360_pmu_chg_info *)mchr_info;
- int ret = 0;
- u8 data = 0;
- ret = mt6360_i2c_read_byte(info, MT6360_PMU_CHG_CTRL7, &data);
- if (ret != I2C_OK)
- return ret;
- data = (data & MT6360_MASK_ICHG) >> MT6360_SHFT_ICHG;
- *ichg = 100 + (data * 100);
- return ret;
- }
- static int mt_charger_set_iprec(struct mtk_charger_info *mchr_info, u32 iprec)
- {
- struct mt6360_pmu_chg_info *info =
- (struct mt6360_pmu_chg_info *)mchr_info;
- u8 data = 0;
- dprintf(CRITICAL, "%s: iprec = %d\n", __func__, iprec);
- if (iprec >= 100)
- data = (iprec - 100) / 50;
- if (data > MT6360_IPREC_MAXVAL)
- data = MT6360_IPREC_MAXVAL;
- return mt6360_i2c_update_bits(info,
- MT6360_PMU_CHG_CTRL8,
- MT6360_MASK_IPREC,
- data << MT6360_SHFT_IPREC);
- }
- static enum mt6360_chg_mode mt6360_get_charging_mode(
- struct mt6360_pmu_chg_info *info)
- {
- int ret = 0;
- u8 data = 0;
- dprintf(CRITICAL, "%s\n", __func__);
- ret = mt6360_i2c_read_byte(info, MT6360_PMU_CHG_STAT, &data);
- if (ret < 0)
- return MT6360_CHG_MODE_UNKNOWN;
- if (data & MT6360_MASK_VBAT_TRI)
- return MT6360_CHG_MODE_TRICHG;
- return (data & MT6360_MASK_VBAT_LVL) ? MT6360_CHG_MODE_FASTCHG :
- MT6360_CHG_MODE_PRECHG;
- }
- static int mt_charger_set_ichg_ext(struct mtk_charger_info *mchr_info, u32 ichg)
- {
- struct mt6360_pmu_chg_info *info =
- (struct mt6360_pmu_chg_info *)mchr_info;
- enum mt6360_chg_mode cur_mode = MT6360_CHG_MODE_UNKNOWN;
- dprintf(CRITICAL, "%s: ichg = %u\n", __func__, ichg);
- cur_mode = mt6360_get_charging_mode(info);
- if (cur_mode == MT6360_CHG_MODE_UNKNOWN) {
- dprintf(CRITICAL, "%s: get charging mode fail\n", __func__);
- return -EINVAL;
- }
- info->ichg = ichg;
- if (cur_mode != MT6360_CHG_MODE_FASTCHG) {
- dprintf(CRITICAL, "%s: not in fast-charge mode\n", __func__);
- return 0;
- }
- if (info->wkard_en) {
- dprintf(CRITICAL, "%s: in work around\n", __func__);
- return 0;
- }
- return mt_charger_set_ichg(mchr_info, ichg);
- }
- static int mt_charger_get_aicr(struct mtk_charger_info *mchr_info, u32 *aicr)
- {
- struct mt6360_pmu_chg_info *info =
- (struct mt6360_pmu_chg_info *)mchr_info;
- int ret = 0;
- u8 data = 0;
- ret = mt6360_i2c_read_byte(info, MT6360_PMU_CHG_CTRL3, &data);
- if (ret != I2C_OK)
- return ret;
- data = (data & MT6360_MASK_AICR) >> MT6360_SHFT_AICR;
- *aicr = 100 + (data * 50);
- return ret;
- }
- static int mt6360_adc_get_process_val(struct mt6360_pmu_chg_info *info,
- enum mt6360_adc_channel chan, u32 *val)
- {
- int ret = 0;
- u8 data = 0;
- switch (chan) {
- case MT6360_ADC_USBID:
- case MT6360_ADC_VREF_TS:
- case MT6360_ADC_TS:
- *val *= 1250;
- break;
- case MT6360_ADC_TEMP_JC:
- *val -= 40;
- break;
- case MT6360_ADC_VBAT:
- case MT6360_ADC_VSYS:
- case MT6360_ADC_CHG_VDDP:
- *val *= 1250;
- break;
- case MT6360_ADC_VBUSDIV5:
- *val *= 6250;
- break;
- case MT6360_ADC_VBUSDIV2:
- case MT6360_ADC_IBAT:
- *val *= 2500;
- break;
- case MT6360_ADC_IBUS:
- ret = mt6360_i2c_read_byte(info, MT6360_PMU_CHG_CTRL3, &data);
- if (ret < 0)
- return ret;
- if (((data & 0xfc) >> 2) < 0x6)
- *val *= 1900;
- else
- *val *= 2500;
- break;
- default:
- break;
- }
- return ret;
- }
- static int mt_charger_get_adc(struct mtk_charger_info *mchr_info,
- int chan, u32 *val)
- {
- struct mt6360_pmu_chg_info *info =
- (struct mt6360_pmu_chg_info *)mchr_info;
- u8 tmp[3], rpt[3];
- u8 data = 0;
- int i, ret = 0, max_retry_cnt = 20;
- dprintf(CRITICAL, "%s: ++\n", __func__);
- if (chan >= MT6360_ADC_MAX) {
- dprintf(CRITICAL, "%s: undeine channel(%d)\n",
- __func__, chan);
- ret = -EINVAL;
- goto err_adc_init;
- }
- /* first reset all channels and adc en */
- memset(tmp, 0, sizeof(tmp));
- ret = mt6360_i2c_block_write(info, MT6360_PMU_ADC_CONFIG, 3, tmp);
- if (ret < 0) {
- dprintf(CRITICAL, "%s: reset all channels fail\n", __func__);
- goto err_adc_init;
- }
- /* enable adc_donei irq */
- ret = mt6360_clr_bit(info, MT6360_PMU_CHG_MASK6, MT6360_MASK_ADC_DONE);
- if (ret < 0) {
- dprintf(CRITICAL, "%s: unmask adc_donei fail\n", __func__);
- goto err_adc_conv;
- }
- /* select preferred channel : vbus */
- ret = mt6360_i2c_update_bits(info,
- MT6360_PMU_ADC_RPT_1, 0xf0, chan << 4);
- if (ret < 0) {
- dprintf(CRITICAL, "%s: select prefer channel fail\n", __func__);
- goto err_adc_conv;
- }
- /* enable vbus adc channel and adc_en */
- tmp[0] |= (1 << 7);
- if ((chan / 8) > 0)
- tmp[0] |= (1 << (chan % 8));
- else
- tmp[1] |= (1 << (chan % 8));
- ret = mt6360_i2c_block_write(info, MT6360_PMU_ADC_CONFIG, 2, tmp);
- if (ret < 0) {
- dprintf(CRITICAL,
- "%s: enable vbus adc and adc en fail\n", __func__);
- goto err_adc_conv;
- }
- /* wait adc conversion done */
- for (i = 0; i < max_retry_cnt; i++) {
- mdelay(30);
- /* read adc conversion donei event */
- ret = mt6360_i2c_read_byte(info, MT6360_PMU_CHG_IRQ6, &data);
- if (ret < 0)
- goto err_adc_conv;
- if (!(data & MT6360_MASK_ADC_DONE))
- continue;
- ret = mt6360_set_bit(info, MT6360_PMU_CHG_IRQ6,
- MT6360_MASK_ADC_DONE);
- if (ret < 0) {
- dprintf(CRITICAL,
- "%s: clear adc donei irq fail\n", __func__);
- goto err_adc_conv;
- }
- memset(rpt, 0, sizeof(rpt));
- ret = mt6360_i2c_block_read(info, MT6360_PMU_ADC_RPT_1, 3, rpt);
- if (ret < 0)
- goto err_adc_conv;
- if ((rpt[0] & 0x0f) != chan) {
- dprintf(CRITICAL, "%s: not want channel report(%d)\n",
- __func__, rpt[0]);
- continue;
- }
- *val = ((rpt[1] << 8) | rpt[2]);
- ret = mt6360_adc_get_process_val(info, chan, val);
- break;
- }
- if (i == max_retry_cnt) {
- dprintf(CRITICAL, "%s: reach adc retry cnt\n", __func__);
- ret = -EBUSY;
- goto err_adc_conv;
- }
- err_adc_conv:
- tmp[0] &= ~(0x7);
- tmp[1] = 0;
- mt6360_i2c_block_write(info, MT6360_PMU_ADC_CONFIG, 2, tmp);
- mt6360_set_bit(info, MT6360_PMU_CHG_MASK6, MT6360_MASK_ADC_DONE);
- err_adc_init:
- dprintf(CRITICAL, "%s: --\n", __func__);
- return ret;
- }
- static int mt_charger_get_vbus(struct mtk_charger_info *mchr_info, u32 *vbus)
- {
- return mt_charger_get_adc(mchr_info, MT6360_ADC_VBUSDIV5, vbus);
- }
- static int mt_charger_set_aicr(struct mtk_charger_info *mchr_info, u32 aicr)
- {
- struct mt6360_pmu_chg_info *info =
- (struct mt6360_pmu_chg_info *)mchr_info;
- u8 data = 0;
- dprintf(CRITICAL, "%s: aicr = %d\n", __func__, aicr);
- if (aicr >= 100)
- data = (aicr - 100) / 50;
- if (data > MT6360_AICR_MAXVAL)
- data = MT6360_AICR_MAXVAL;
- return mt6360_i2c_update_bits(info,
- MT6360_PMU_CHG_CTRL3,
- MT6360_MASK_AICR,
- data << MT6360_SHFT_AICR);
- }
- static int mt_charger_set_aicr_ext(struct mtk_charger_info *mchr_info, u32 aicr)
- {
- struct mt6360_pmu_chg_info *info =
- (struct mt6360_pmu_chg_info *)mchr_info;
- enum mt6360_chg_mode cur_mode = MT6360_CHG_MODE_UNKNOWN;
- dprintf(CRITICAL, "%s: aicr = %d\n", __func__, aicr);
- cur_mode = mt6360_get_charging_mode(info);
- if (cur_mode == MT6360_CHG_MODE_UNKNOWN) {
- dprintf(CRITICAL, "%s: get charging mode fail\n", __func__);
- return -EINVAL;
- }
- info->aicr = aicr;
- if (cur_mode != MT6360_CHG_MODE_FASTCHG) {
- dprintf(CRITICAL, "%s: not in fast-charge mode\n", __func__);
- return 0;
- }
- if (info->wkard_en) {
- dprintf(CRITICAL, "%s: in work around\n", __func__);
- return 0;
- }
- return mt_charger_set_aicr(mchr_info, aicr);
- }
- static int mt_charger_set_mivr(struct mtk_charger_info *mchr_info, u32 mivr)
- {
- struct mt6360_pmu_chg_info *info =
- (struct mt6360_pmu_chg_info *)mchr_info;
- u8 data = 0;
- dprintf(CRITICAL, "%s: mivr = %d\n", __func__, mivr);
- if (mivr >= 3900)
- data = (mivr - 3900) / 100;
- if (data > MT6360_MIVR_MAXVAL)
- data = MT6360_MIVR_MAXVAL;
- return mt6360_i2c_update_bits(info,
- MT6360_PMU_CHG_CTRL6,
- MT6360_MASK_MIVR,
- data << MT6360_SHFT_MIVR);
- }
- static int mt_charger_enable_power_path(struct mtk_charger_info *mchr_info,
- bool enable)
- {
- struct mt6360_pmu_chg_info *info =
- (struct mt6360_pmu_chg_info *)mchr_info;
- dprintf(CRITICAL, "%s: enable = %d\n", __func__, enable);
- return (enable ? mt6360_clr_bit : mt6360_set_bit)
- (info, MT6360_PMU_CHG_CTRL1, MT6360_MASK_FORCE_SLEEP);
- }
- static int mt_charger_reset_pumpx(struct mtk_charger_info *mchr_info,
- bool reset)
- {
- struct mt6360_pmu_chg_info *info =
- (struct mt6360_pmu_chg_info *)mchr_info;
- if (reset)
- mt_charger_get_aicr(mchr_info, &info->aicr);
- return mt_charger_set_aicr(mchr_info, reset ? 100 : info->aicr);
- }
- static int mt_charger_enable_wdt(struct mtk_charger_info *mchr_info, bool en)
- {
- struct mt6360_pmu_chg_info *info =
- (struct mt6360_pmu_chg_info *)mchr_info;
- return mt6360_enable_wdt(info, en);
- }
- static int mt_charger_dump_register(struct mtk_charger_info *mchr_info)
- {
- struct mt6360_pmu_chg_info *info =
- (struct mt6360_pmu_chg_info *)mchr_info;
- enum mt6360_charging_status chg_status = MT6360_CHG_STATUS_READY;
- u32 ichg = 0, aicr = 0, mivr = 0, ieoc = 0;
- bool chg_en = 0;
- int ret = 0;
- ret = mt_charger_get_ichg(mchr_info, &ichg);
- ret = mt_charger_get_aicr(mchr_info, &aicr);
- ret = mt6360_get_mivr(info, &mivr);
- ret = mt6360_get_ieoc(info, &ieoc);
- ret = mt6360_is_charging_enable(info, &chg_en);
- ret = mt6360_get_charging_status(info, &chg_status);
- dprintf(CRITICAL,
- "%s: ICHG = %dmA, AICR = %dmA, MIVR = %dmV, IEOC = %dmA\n",
- __func__, ichg, aicr, mivr, ieoc);
- dprintf(CRITICAL, "%s: CHG_EN = %d, CHG_STATUS = %s\n",
- __func__, chg_en, mt6360_chg_status_name[chg_status]);
- return ret;
- }
- static int mt6360_fix_current_accuracy(struct mtk_charger_info *mchr_info,
- bool enable)
- {
- struct mt6360_pmu_chg_info *info =
- (struct mt6360_pmu_chg_info *)mchr_info;
- u8 swit_feq[3] = { 0x80, 0x20, 0x00 };
- int i, ret = 0;
- if (!(info->wkard_en ^ enable))
- return 0;
- ret = mt6360_enable_hidden_mode(info, true);
- if (ret < 0) {
- dprintf(CRITICAL, "%s: enter hidden mode fail\n", __func__);
- return ret;
- }
- if (enable) {
- /* Set chg/otg switch frequence 0.75MHz */
- ret = mt6360_set_bit(info, MT6360_PMU_CHG_CTRL1, 0x80);
- if (ret < 0) {
- dprintf(CRITICAL,
- "%s: set switch feq to 0.75MHz fail\n",
- __func__);
- goto out;
- }
- /* Set buck slope ratio to 0.6x */
- ret = mt6360_i2c_update_bits(info, MT6360_PMU_CHG_HIDDEN_CTRL10,
- 0x07, 0);
- if (ret < 0) {
- dprintf(CRITICAL,
- "%s: set buck slope ratio 0.6x fail\n",
- __func__);
- goto out;
- }
- /* Set Power path MOS gate driving slew rate to 2x */
- ret = mt6360_set_bit(info, MT6360_PMU_CHG_HIDDEN_CTRL11, 0xC0);
- if (ret < 0) {
- dprintf(CRITICAL,
- "%s: set pp gate slew rate fail\n", __func__);
- goto out;
- }
- } else {
- /* Clear Power path MOS gate driving slew rate to 1x */
- ret = mt6360_clr_bit(info, MT6360_PMU_CHG_HIDDEN_CTRL11, 0xC0);
- if (ret < 0) {
- dprintf(CRITICAL,
- "%s: clr pp gate slew rate fail\n", __func__);
- goto out;
- }
- /* set buck slope ratio step 0.6x to 1.8x */
- for (i = 0; i < 7; i++) {
- ret = mt6360_i2c_update_bits(info,
- MT6360_PMU_CHG_HIDDEN_CTRL10, 0x07, i);
- if (ret < 0) {
- dprintf(CRITICAL,
- "%s: step up buck slope ratio fail\n",
- __func__);
- goto out;
- }
- }
- /* Set chg/otg switch frequence step 0.75->1.0->1.5MHz */
- for (i = 0; i < 3; i++) {
- ret = mt6360_i2c_update_bits(info, MT6360_PMU_CHG_CTRL1,
- 0xa0, swit_feq[i]);
- if (ret < 0) {
- dprintf(CRITICAL,
- "%s: step down switch feq fail\n",
- __func__);
- goto out;
- }
- }
- }
- info->wkard_en = enable;
- out:
- mt6360_enable_hidden_mode(info, false);
- return (ret < 0) ? ret : 0;
- }
- static int mt_charger_check_charging_mode(struct mtk_charger_info *mchr_info)
- {
- struct mt6360_pmu_chg_info *info =
- (struct mt6360_pmu_chg_info *)mchr_info;
- int ret = 0;
- static enum mt6360_chg_mode pre_mode = MT6360_CHG_MODE_UNKNOWN;
- enum mt6360_chg_mode cur_mode = MT6360_CHG_MODE_UNKNOWN;
- u8 data = 0;
- dprintf(CRITICAL, "%s\n", __func__);
- ret = mt6360_i2c_read_byte(info, MT6360_PMU_CHRDET_STAT, &data);
- if (ret < 0)
- return ret;
- if (!(data & MT6360_MASK_CHRDET_EXT_EVT)) {
- dprintf(CRITICAL, "%s: pwr_rdy = 0\n", __func__);
- return 0;
- }
- ret = mt6360_i2c_read_byte(info, MT6360_PMU_CHG_CTRL2, &data);
- if (ret < 0)
- return ret;
- if (!(data & MT6360_MASK_CFO_EN)) {
- dprintf(CRITICAL, "%s: CFO_EN = 0\n", __func__);
- return 0;
- }
- cur_mode = mt6360_get_charging_mode(info);
- if (cur_mode == MT6360_CHG_MODE_UNKNOWN) {
- dprintf(CRITICAL, "%s: get charging mode fail\n", __func__);
- return -EINVAL;
- }
- dprintf(CRITICAL, "%s: in %s mode, previously in %s mode\n", __func__,
- mt6360_chg_mode_name[cur_mode],
- mt6360_chg_mode_name[pre_mode]);
- if (cur_mode == pre_mode)
- return 0;
- switch (cur_mode) {
- case MT6360_CHG_MODE_TRICHG:
- ret = mt_charger_set_ichg(mchr_info, info->iprec);
- if (ret < 0) {
- dprintf(CRITICAL,
- "%s: set ichg to %umA fail\n",
- __func__, info->iprec);
- return ret;
- }
- ret = mt6360_fix_current_accuracy(mchr_info, true);
- if (ret < 0) {
- dprintf(CRITICAL,
- "%s: fix current accuracy fail\n", __func__);
- return ret;
- }
- break;
- case MT6360_CHG_MODE_PRECHG:
- ret = mt_charger_set_ichg(mchr_info, info->iprec);
- if (ret < 0) {
- dprintf(CRITICAL,
- "%s: set ichg to %umA fail\n",
- __func__, info->iprec);
- return ret;
- }
- ret = mt6360_fix_current_accuracy(mchr_info,
- (info->iprec < 500) ?
- true : false);
- if (ret < 0) {
- dprintf(CRITICAL,
- "%s: fix current accuracy fail\n", __func__);
- return ret;
- }
- break;
- case MT6360_CHG_MODE_FASTCHG:
- ret = mt6360_fix_current_accuracy(mchr_info, false);
- if (ret < 0) {
- dprintf(CRITICAL,
- "%s: fix current accuracy fail\n", __func__);
- return ret;
- }
- ret = mt_charger_set_aicr(mchr_info, info->aicr);
- if (ret < 0) {
- dprintf(CRITICAL,
- "%s: set aicr to %umA fail\n",
- __func__, info->aicr);
- return ret;
- }
- ret = mt_charger_set_ichg(mchr_info, info->ichg);
- if (ret < 0) {
- dprintf(CRITICAL,
- "%s: set ichg to %umA fail\n",
- __func__, info->ichg);
- return ret;
- }
- break;
- default:
- dprintf(CRITICAL, "%s: Unkown mode\n", __func__);
- break;
- }
- pre_mode = cur_mode;
- return 0;
- }
- static int mt_charger_enable_discharge(struct mtk_charger_info *mchr_info, bool en)
- {
- struct mt6360_pmu_chg_info *info =
- (struct mt6360_pmu_chg_info *)mchr_info;
- int ret = 0;
- dprintf(CRITICAL, "%s: en = %d\n", __func__, en);
- ret = mt6360_enable_hidden_mode(info, true);
- if (ret < 0)
- return ret;
- /* Set bit2 of reg[0x31] to 1/0 to enable/disable discharging */
- ret = mt6360_i2c_update_bits(info, MT6360_PMU_CHG_HIDDEN_CTRL2,
- MT6360_MASK_DISCHG, en ? 0xff : 0);
- if (ret < 0)
- dprintf(CRITICAL, "%s: fail(%d)\n", __func__, ret);
- mt6360_enable_hidden_mode(info, false);
- return ret;
- }
- static int mt_charger_sw_reset(struct mtk_charger_info *mchr_info)
- {
- struct mt6360_pmu_chg_info *info =
- (struct mt6360_pmu_chg_info *)mchr_info;
- int ret = 0;
- u32 i = 0;
- u8 cmds[3] = {MT6360_PMU_RST_PAS_CODE1, MT6360_PMU_RST_PAS_CODE2,
- MT6360_PMU_RST1};
- u8 data[3] = {0xA9, 0x96, 0x7F};
- for (i = 0; i < ARRAY_SIZE(cmds); i++) {
- ret = mt6360_i2c_write_byte(info, cmds[i], data[i]);
- if (ret < 0) {
- dprintf(CRITICAL, "%s: fail(%d)\n", __func__, ret);
- return ret;
- }
- }
- mdelay(1);
- for (i = 0; i < ARRAY_SIZE(cmds); i++) {
- ret = mt6360_i2c_write_byte(info, cmds[i], 0x00);
- if (ret < 0) {
- dprintf(CRITICAL, "%s: fail(%d)\n", __func__, ret);
- return ret;
- }
- }
- return mt6360_clr_bit(info, MT6360_PMU_CORE_CTRL1, MT6360_MASK_MREN);
- }
- static struct mtk_charger_ops mt6360_mchr_ops = {
- .dump_register = mt_charger_dump_register,
- .enable_charging = mt_charger_enable_charging,
- .get_ichg = mt_charger_get_ichg,
- .set_ichg = mt_charger_set_ichg_ext,
- .get_aicr = mt_charger_get_aicr,
- .get_adc = mt_charger_get_adc,
- .get_vbus = mt_charger_get_vbus,
- .set_aicr = mt_charger_set_aicr_ext,
- .set_mivr = mt_charger_set_mivr,
- .enable_power_path = mt_charger_enable_power_path,
- .reset_pumpx = mt_charger_reset_pumpx,
- .enable_wdt = mt_charger_enable_wdt,
- .check_charging_mode = mt_charger_check_charging_mode,
- .enable_discharge = mt_charger_enable_discharge,
- .sw_reset = mt_charger_sw_reset,
- };
- /* Info of primary charger */
- static struct mt6360_pmu_chg_info g_mpci = {
- .mchr_info = {
- .name = "primary_charger",
- .device_id = -1,
- .mchr_ops = &mt6360_mchr_ops,
- },
- .i2c = {
- .id = I2C5,
- .addr = MT6360_SLAVE_ADDR,
- .mode = HS_MODE,
- .speed = 400,
- .pushpull = true,
- },
- .i2c_log_level = INFO,
- .vid = 0x00,
- .iprec = 150,
- .ichg = 2000,
- .aicr = 500,
- .mivr = 4500,
- .cv = 4350,
- .wkard_en = false,
- .ichg_dis_chg = 2000,
- .chg_en = true,
- };
- static int mt6360_chg_init_setting(struct mt6360_pmu_chg_info *info)
- {
- int ret = 0;
- dprintf(CRITICAL, "%s: starts\n", __func__);
- ret = mt6360_enable_wdt(info, true);
- if (ret < 0) {
- dprintf(CRITICAL, "%s: enable wdt failed\n", __func__);
- goto out;
- }
- /* Select input current limit to referenced from AICR */
- ret = mt6360_select_input_current_limit(info,
- MT6360_IINLMTSEL_AICR);
- if (ret < 0) {
- dprintf(CRITICAL, "%s: select input current limit failed\n",
- __func__);
- goto out;
- }
- mdelay(5);
- /* Disable HW iinlimit, use SW */
- ret = mt6360_enable_ilim(info, false);
- if (ret < 0) {
- dprintf(CRITICAL, "%s: disable ilim failed\n", __func__);
- goto out;
- }
- ret = mt_charger_set_iprec(&info->mchr_info, info->iprec);
- if (ret < 0) {
- dprintf(CRITICAL, "%s: set iprec failed\n", __func__);
- goto out;
- }
- /* Set ichg 500mA for vsys overshoot */
- ret = mt_charger_set_ichg(&info->mchr_info, 500);
- if (ret < 0) {
- dprintf(CRITICAL, "%s: set ichg failed\n", __func__);
- goto out;
- }
- ret = mt_charger_set_aicr(&info->mchr_info, info->aicr);
- if (ret < 0) {
- dprintf(CRITICAL, "%s: set aicr failed\n", __func__);
- goto out;
- }
- ret = mt_charger_set_mivr(&info->mchr_info, info->mivr);
- if (ret < 0) {
- dprintf(CRITICAL, "%s: set mivr failed\n", __func__);
- goto out;
- }
- ret = mt6360_set_cv(info, info->cv);
- if (ret < 0) {
- dprintf(CRITICAL, "%s: set cv failed\n", __func__);
- goto out;
- }
- /* Fix pre-chg/fast-chg current loop not correct */
- ret = mt_charger_check_charging_mode(&info->mchr_info);
- if (ret < 0) {
- dprintf(CRITICAL, "%s: check charging mode fail\n", __func__);
- goto out;
- }
- /* Disable sys drop improvement for download mode */
- ret = mt6360_clr_bit(info, MT6360_PMU_CHG_CTRL20, MT6360_MASK_EN_SDI);
- if (ret < 0)
- dprintf(CRITICAL,
- "%s: disable sys drop improvement fail\n", __func__);
- out:
- return ret;
- }
- int mt6360_chg_probe(void)
- {
- int ret = 0;
- /* Check primary charger */
- if (!mt6360_is_hw_exist(&g_mpci))
- return -ENODEV;
- dprintf(CRITICAL, "%s: %s\n",
- __func__, MT6360_PMU_CHARGER_LK_DRV_VERSION);
- ret = mt6360_chg_init_setting(&g_mpci);
- if (ret < 0) {
- dprintf(CRITICAL, "%s: init setting fail\n", __func__);
- return ret;
- }
- mtk_charger_set_info(&(g_mpci.mchr_info));
- return ret;
- }
- /*
- * Revision Note
- * 1.0.0
- * (1) Initial release
- */
|