| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043 |
- /* 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 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,
- };
- /* 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
- */
|