1. 程式人生 > >[Android6.0][RK3399] 電池系統(二)BQ IC 新增 DC 充電功能

[Android6.0][RK3399] 電池系統(二)BQ IC 新增 DC 充電功能

Platform: RK3399
OS: Android 6.0
Kernel: 4.4
Version: v2017.04
IC: TI BQ25700、RK808

我們也知道了平臺預設的程式碼,定位是 PD 充電,不支援 DC 充電。
這一章我們來新增 DC 充電的功能。

解決思路

首先我們知道 DC 插入的時候, CHG_OK_H 會被拉高。所以我們思考是否可以在 CHG_OK 的中斷處理函式中完成對 BQ IC DC 充電功能的配置。
但是當 TypeC 介面卡插入的時候,CHG_OK_H 也會被拉高。
不過利用 TypeC 充電時候的配置和 利用 DC 充電的配置是相同的。

另外需要說明的是,硬體上實現了,在插入 DC 的時候,會關斷 TypeC 的供電。以防止兩邊同時往板子充電而引起的異常。

所以,一共有以下幾種情況:
僅插上 TypeC 介面卡,程式碼預設實現正常充電。
僅插上 DC 介面卡,在 CHG_OK 中斷處理函式中完成充電配置。
插上 TypeC 介面卡後,再插入 DC 介面卡,不會觸發中斷處理函式,但是在 BQ IC 中的配置此時是適用於 DC 充電的。所以沒問題。硬體上 TypeC 充電被關斷。
插上 DC 介面卡後,再插入 TypeC 介面卡,先利用中斷處理函式中對 BQ IC 的配置進行充電。由於硬體上此時已經關斷了 TypeC 充電。所以沒問題。

分析得知這樣是可行的,那麼我們開始在 CHG_OK 的中斷處理函式中完成對 BQ IC 的操作。

程式碼新增

根據 datasheet ,我們瞭解到開啟 BQ IC 充電需要完成 INPUT_CURRENT 與 CHARGE_CURRENT 暫存器的寫操作。
其次,深入 TypeC 檢測後的處理函式,我們也可以看到最後其是呼叫了 bq25700_enable_charger 完成充電:

static void bq25700_enable_charger(struct bq25700_device *charger,
                   u32 input_current)
{ bq25700_field_write(charger, INPUT_CURRENT, input_current); bq25700_field_write(charger, CHARGE_CURRENT, charger->init_data.ichg); }

那麼我們仿照其使能 BQ IC 充電的方式來完成中斷處理函式中的操作:

bq25700_probe
{
...
    ret = devm_request_threaded_irq(dev, client->irq, NULL,
                    bq25700_irq_handler_thread,
                    irq_flag | IRQF_ONESHOT ,   
                    "bq25700_irq", charger);
    if (ret)
...
}

static irqreturn_t bq25700_irq_handler_thread(int irq, void *private)
{
    struct bq25700_device *charger = private;
    int irq_flag;
    struct bq25700_state state;
    DBG("BQ25700: bq25700_irq_handler_thread\n");

    if (bq25700_field_read(charger, AC_STAT)) {
        irq_flag = IRQF_TRIGGER_LOW;

++      bq25700_field_write(charger, INPUT_CURRENT, charger->init_data.input_current_cdp);
++      bq25700_field_write(charger, CHARGE_CURRENT, charger->init_data.ichg);
++      bq25700_get_chip_state(charger, &state);
++      charger->state = state;
++      power_supply_changed(charger->supply_charger);
++      DBG("BQ25700: set irq_flag = IRQF_TRIGGER_LOW\n");
    } else {
        irq_flag = IRQF_TRIGGER_HIGH;

        bq25700_field_write(charger, INPUT_CURRENT, charger->init_data.input_current);
        bq25700_disable_charge(charger);
        bq25700_get_chip_state(charger, &state);
        charger->state = state;
        power_supply_changed(charger->supply_charger);
        charger->typec0_status = USB_STATUS_NONE;
        charger->typec1_status = USB_STATUS_NONE;
++    DBG("BQ25700:set irq_flag = IRQF_TRIGGER_HIGH\n");
    }
    irq_set_irq_type(irq, irq_flag | IRQF_ONESHOT );
    rk_send_wakeup_key();

    DBG("BQ25700: bq25700_irq_handler_thread done\n");
    return IRQ_HANDLED;
}

驗證結果

在插拔 DC 的時候我們

cat /sys/class/i2c-adapter/i2c-4/4-0009/charge_info

發現插入 DC 時充電電流為 2.3 A,表示其是可以正常工作的。

遇到 Bug

過程中遇到兩個問題。
第一個問題是使能 BQ IC 充電的方式
當時查閱 Datasheet 發現說需要 給 CHRG_INHIBIT 寫 0 ,表示使能 BQ IC。寫 1 表示禁能 BQ IC。如下:

bq25700_field_write(charger, CHRG_INHIBIT, 0);

所以我就這樣寫了,但是這個導致的問題是輸入電流極大,為 3.25A。再仔細查閱 datasheet 發現,如果採用 CHRG_INHIBIT 來使能 BQ IC 的話,會自動對 INPUT_CURRENT 配置,預設為 3.25A。

第二個問題很蠢
如下完成寫這兩個暫存器

        bq25700_field_write(charger, INPUT_CURRENT, charger->init_data.input_current);
        bq25700_field_write(charger, CHARGE_CURRENT, charger->init_data.ichg);

我們 dts 是這樣配的

        ti,charge-current = <2500000>;
        ti,input-current = <2000000>;     //2A
        ti,input-current-sdp = <500000>;
        ti,input-current-dcp = <2000000>;
        ti,input-current-cdp = <2000000>;
        ti,minimum-sys-voltage = <7400000>;

看起來這樣就是配置 INPUT_CURRENT 為 2A 、配置 CHAGRE_CURRENT 為 2.5A 了?
錯!
實際上在 dts 解析的過程是沒有解析 input_current 的,也就是說其是為 0 的:

    struct {
        char *name;
        bool optional;
        enum bq25700_table_ids tbl_id;
        u32 *conv_data; /* holds converted value from given property */
    } props[] = {
        /* required properties */
        {"ti,charge-current", false, TBL_ICHG,
         &init->ichg},
        {"ti,max-charge-voltage", false, TBL_CHGMAX,
         &init->max_chg_vol},
        {"ti,input-current-sdp", false, TBL_INPUTCUR,
         &init->input_current_sdp},
        {"ti,input-current-dcp", false, TBL_INPUTCUR,
         &init->input_current_dcp},
        {"ti,input-current-cdp", false, TBL_INPUTCUR,
         &init->input_current_cdp},
        {"ti,minimum-sys-voltage", false, TBL_SYSVMIN,
         &init->sys_min_voltage},
        {"ti,otg-voltage", false, TBL_OTGVOL,
         &init->otg_voltage},
        {"ti,otg-current", false, TBL_OTGCUR,
         &init->otg_current},
    };

所以要充 2A 應該改為

        bq25700_field_write(charger, INPUT_CURRENT, charger->init_data.input_current_cdp);