充电IC和电量计的驱动调试

  • LK是little kernel的缩写
  • 高通平台android普遍采用LK作为其bootloader,LK是一个开源项目。但是,LK只是整个系统的引导部分,所以它不是独立存在。LK是一个功能极其强大的bootloader,但只支持arm和x86平台。
  • LK的一个显著的特点就是它实现了一个简单的线程机制(thread),和对高通处理器的深度定制和使用。

一、LK部分代码修改

开机电压检测,关机充电使能
1.1、bootable/bootloader/lk/app/aboot/aboot.c

#include <display_menu.h>
 #include "fastboot_test.h"
 
+#include <i2c_qup.h>
+#include <blsp_qup.h>
+static struct qup_i2c_dev *i2c_dev;
 void *info_buf;
 void write_device_info_mmc(device_info *dev);
  	} else if (boot_reason_alarm) {
 		cmdline_len += strlen(alarmboot_cmdline);
-	} else if ((target_build_variant_user() || device.charger_screen_enabled)
-			&& target_pause_for_battery_charge() && !boot_into_recovery) {
+	} else if (/*(target_build_variant_user() || device.charger_screen_enabled)
+			&& */target_pause_for_battery_charge() && !boot_into_recovery) {
 		pause_at_bootup = 1;
 		cmdline_len += strlen(battchg_pause);
 	}
static int blsp_i2c_read_reg(uint8_t i2c_addr, uint8_t reg_addr, uint8_t *reg_data)
{
        int ret = 0;

        struct i2c_msg msg_buf[] = {
                {i2c_addr, I2C_M_WR, 1, &reg_addr},
                {i2c_addr, I2C_M_RD, 1, reg_data}
        };

        ret = qup_i2c_xfer(i2c_dev, msg_buf, 2);
        if (ret < 0) {
                dprintf(CRITICAL, "qup_i2c_xfer read error %d, slave addr: %02x\n",
                        ret, i2c_addr);
                return ret;
        }

        return ret;
}

static int blsp_i2c_write_reg(uint8_t i2c_addr, uint8_t reg_addr, uint8_t reg_data)
{
        int ret = 0;
        uint8_t buf[2];

        buf[0] = reg_addr;
        buf[1] = reg_data;

        struct i2c_msg msg_buf[] = {
                {i2c_addr, I2C_M_WR, sizeof(buf), buf},
        };

        ret = qup_i2c_xfer(i2c_dev, msg_buf, 1);
        if (ret < 0) {
                dprintf(CRITICAL, "qup_i2c_xfer write error %d, slave addr: %02x\n",
                        ret, i2c_addr);
                return ret;
        }

        return ret;
}

static void battery_voltage_check_loop(void)
{
        int ret;
        uint8_t reg_sysmin = 0x03;
        uint8_t reg_wdt = 0x07;
        uint8_t reg_chip_id = 0x14;
        uint8_t reg_vbat = 0x0E;
        uint8_t reg_charger_online = 0x0B;
        uint8_t reg_adc_convert = 0x02;
        uint8_t chip_id, sysmin, wdt, adc_convert, vbat, charger_online;
        uint32_t vbat_voltage, power_on_voltage = 3500;

        gpio_tlmm_config(2, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA, GPIO_DISABLE);
        //gpio_tlmm_config(137, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA, GPIO_DISABLE);
        gpio_set_dir(2, 0); // enable charge chip enable
        //gpio_set_dir(137, 2); // connect usb dpdm to sc60 module

        i2c_dev = qup_blsp_i2c_init(BLSP_ID_1, QUP_ID_2, 100000, 19200000);
        thread_sleep(100);
    ret = blsp_i2c_read_reg(0x6A, reg_chip_id, &chip_id);
        if (ret < 0 || ((chip_id >> 3) & 7) != 3) {
                dprintf(CRITICAL, "get ba25890 chip id failed\n");
                return;
        }
        // reset chip
        ret = blsp_i2c_write_reg(0x6A, 0x14, 0x80);
        if (ret < 0) { // any error will exit battery voltage check
                dprintf(CRITICAL, "reset chip failed\n");
                return;
        }
        thread_sleep(100);
        ret = blsp_i2c_read_reg(0x6A, reg_wdt, &wdt);
        if (ret < 0) { // any error will exit battery voltage check
                dprintf(CRITICAL, "get wdt reg failed\n");
                return;
        }
        wdt &= ~(3 << 4);
        ret = blsp_i2c_write_reg(0x6A, reg_wdt, wdt);
        if (ret < 0) { // any error will exit battery voltage check
                dprintf(CRITICAL, "disable wdt failed\n");
                return;
        }
        ret = blsp_i2c_read_reg(0x6A, reg_sysmin, &sysmin);
        if (ret < 0) { // any error will exit battery voltage check
                dprintf(CRITICAL, "get sysmin reg failed\n");
                return;
        }
        sysmin &= ~(7 << 1);
		 ret = blsp_i2c_write_reg(0x6A, reg_sysmin, sysmin);
        if (ret < 0) { // any error will exit battery voltage check
                dprintf(CRITICAL, "set sysmin reg failed\n");
                return;
        }
        ret = blsp_i2c_read_reg(0x6A, reg_adc_convert, &adc_convert);
        if (ret < 0) { // any error will exit battery voltage check
                dprintf(CRITICAL, "get adc convert reg failed\n");
                return;
        }
        adc_convert |= 3 << 6;
        ret = blsp_i2c_write_reg(0x6A, reg_adc_convert, adc_convert);
        if (ret < 0) { // any error will exit battery voltage check
                dprintf(CRITICAL, "enable adc convert failed\n");
                return;
        }
        // wait adc start convert
        thread_sleep(100);
        while (1) {
                ret = blsp_i2c_read_reg(0x6A, reg_vbat, &vbat);
                if (ret < 0) {
                        dprintf(CRITICAL, "get vbat reg failed\n");
                        break;
                }
                ret = blsp_i2c_read_reg(0x6A, reg_charger_online, &charger_online);
                if (ret < 0) { // any error will exit battery voltage check
                        dprintf(CRITICAL, "get charger_online reg failed\n");
                        break;
                }
                charger_online = (charger_online >> 2) & 1;
                vbat_voltage = 2304 + (vbat & 0x7f) * 20;
                // if charger online, decrease 50mV from battery voltage
                if (charger_online)
                        vbat_voltage -= 50;
                dprintf(CRITICAL, "battery voltage %d\n", vbat_voltage);
                // if battery is absent, ntc will report cold, boot into android
                if (vbat_voltage >= power_on_voltage)
                        break; // exit battery voltage check
                else {
                        // sleep 1 minute, then recheck battery voltage
                        if (charger_online)
                                thread_sleep(3000);
                        else {
                                dprintf(CRITICAL, "battery voltage too low, shutdown device\n");
                                ret = blsp_i2c_write_reg(0x6A, 0x14, 0x80);
                                if (ret < 0) { // any error will exit battery voltage check
                                        dprintf(CRITICAL, "reset chip failed\n");
                                        break;
                                }
                                shutdown_device();
                        }
                }
        }
}

以下文件关于 I2C-2 使能
1.2、bootable/bootloader/lk/platform/msm8953/acpuclock.c

 #include <clock.h>
 #include <platform/clock.h>
 #include <platform.h>
+#include <blsp_qup.h>
void clock_config_blsp_i2c(uint8_t blsp_id, uint8_t qup_id)
{
        uint8_t ret = 0;
        char clk_name[64];

        struct clk *qup_clk;

        snprintf(clk_name, sizeof(clk_name), "blsp1_ahb_clk");

        ret = clk_get_set_enable(clk_name, 0 , 1);

        if (ret) {
                dprintf(CRITICAL, "Failed to enable %s clock\n", clk_name);
                return;
        }

        snprintf(clk_name, sizeof(clk_name), "gcc_blsp1_qup3_i2c_apps_clk");

        qup_clk = clk_get(clk_name);

        if (!qup_clk) {
                dprintf(CRITICAL, "Failed to get %s\n", clk_name);
                return;
        }

        ret = clk_enable(qup_clk);

        if (ret) {
                dprintf(CRITICAL, "Failed to enable %s\n", clk_name);
                return;
        }
}

1.3、bootable/bootloader/lk/platform/msm8953/gpio.c

+
+void gpio_config_blsp_i2c(uint8_t blsp_id, uint8_t qup_id)
+{
+	/* configure I2C SDA gpio */
+	gpio_tlmm_config(10, 2, GPIO_OUTPUT, GPIO_NO_PULL,
+		GPIO_2MA, GPIO_DISABLE);
+
+	/* configure I2C SCL gpio */
+	gpio_tlmm_config(11, 2, GPIO_OUTPUT, GPIO_NO_PULL,
+		GPIO_2MA, GPIO_DISABLE);
+}
+

1.4、bootable/bootloader/lk/platform/msm8953/include/platform/clock.h

 void clock_usb30_init(void);
 void clock_reset_usb_phy();
+void clock_config_blsp_i2c(uint8_t blsp_id, uint8_t qup_id);
 #endif

1.5、bootable/bootloader/lk/platform/msm8953/include/platform/gpio.h

 void gpio_config_uart_dm(uint8_t id);
+void gpio_config_blsp_i2c(uint8_t blsp_id, uint8_t qup_id);
 uint32_t gpio_status(uint32_t gpio);

1.6、bootable/bootloader/lk/platform/msm8953/include/platform/iomap.h

 #define USB2_PHY_SEL                       0x01937000
 #define QUSB2_PHY_BASE                     0X79000
 
+#define BLSP_QUP_BASE(blsp_id, qup_id) 	(PERIPH_SS_BASE + 0xB5000 + 0x1000 * qup_id)
+#define GCC_BLSP1_QUP3_APPS_CBCR           (CLK_CTL_BASE + 0x04020)
+#define GCC_BLSP1_QUP3_CMD_RCGR	        (CLK_CTL_BASE + 0x04000)
+#define GCC_BLSP1_QUP3_CFG_RCGR	        (CLK_CTL_BASE + 0x04004)

 /* SS QMP (Qulacomm Multi Protocol) */
 #define QMP_PHY_BASE                0x78000

1.7、bootable/bootloader/lk/platform/msm8953/include/platform/irqs.h

 #define SMD_IRQ                                (GIC_SPI_START + 168)

+#define BLSP_QUP_IRQ(blsp_id, qup_id)          (GIC_SPI_START + 95 + qup_id)
 #endif /* __IRQS_MSM8953_H */

1.8、bootable/bootloader/lk/platform/msm8953/msm8953-clock.c

/* I2C Clocks */
static struct clk_freq_tbl ftbl_gcc_blsp1_qup3_i2c_apps_clk_src[] =
{
        F(      96000,    cxo,  10,   1,  2),
        F(    4800000,    cxo,   4,   0,  0),
        F(    9600000,    cxo,   2,   0,  0),
        F(   16000000,  gpll0,  10,   1,  5),
        F(   19200000,  gpll0,   1,   0,  0),
        F(   25000000,  gpll0,  16,   1,  2),
        F(   50000000,  gpll0,  16,   0,  0),
        F_END
};

static struct rcg_clk gcc_blsp1_qup3_i2c_apps_clk_src =
{
        .cmd_reg      = (uint32_t *) GCC_BLSP1_QUP3_CMD_RCGR,
        .cfg_reg      = (uint32_t *) GCC_BLSP1_QUP3_CFG_RCGR,
        .set_rate     = clock_lib2_rcg_set_rate_hid,
        .freq_tbl     = ftbl_gcc_blsp1_qup3_i2c_apps_clk_src,
        .current_freq = &rcg_dummy_freq,

        .c = {
                .dbg_name = "gcc_blsp1_qup3_i2c_apps_clk_src",
                .ops      = &clk_ops_rcg,
        },
};

static struct branch_clk gcc_blsp1_qup3_i2c_apps_clk = {
        .cbcr_reg = (uint32_t *)GCC_BLSP1_QUP3_APPS_CBCR,
        .parent   = &gcc_blsp1_qup3_i2c_apps_clk_src.c,

        .c = {
                .dbg_name = "gcc_blsp1_qup3_i2c_apps_clk",
                .ops      = &clk_ops_branch,
        },
};

/* UART Clocks */

static struct clk_lookup msm_clocks_8953[] =
{
	CLK_LOOKUP("ce1_core_clk", gcc_ce1_clk.c),
 	CLK_LOOKUP("ce1_src_clk",  ce1_clk_src.c),

+    CLK_LOOKUP("blsp1_ahb_clk", gcc_blsp1_ahb_clk.c),
+	CLK_LOOKUP("gcc_blsp1_qup3_i2c_apps_clk_src", gcc_blsp1_qup3_i2c_apps_clk_src.c),
+	CLK_LOOKUP("gcc_blsp1_qup3_i2c_apps_clk", gcc_blsp1_qup3_i2c_apps_clk.c),
}

1.9、bootable/bootloader/lk/platform/msm_shared/rules.mk

 			$(LOCAL_DIR)/mipi_dsc.o \
 			$(LOCAL_DIR)/mipi_dsi_phy.o \
+			$(LOCAL_DIR)/i2c_qup.o \
 			$(LOCAL_DIR)/mipi_dsi_autopll_thulium.o
 endif

二、sys目录权限添加

2.1、device/qcom/sepolicy/vendor/msm8953/genfs_contexts

 #PMI path
 genfscon sysfs /devices/soc/qpnp-haptic-24/leds/vibrator u:object_r:sysfs_leds:s0
 genfscon sysfs /devices/soc/qpnp-vadc-14/usbin u:object_r:sysfs_battery_supply:s0
 
+genfscon sysfs /devices/platform/soc/78b7000.i2c/i2c-3/3-0062/power_supply/bms u:object_r:sysfs_battery_supply:s0
+genfscon sysfs /devices/platform/soc/78b7000.i2c/i2c-3/3-006a/power_supply/pc_port u:object_r:sysfs_battery_supply:s0
+genfscon sysfs /devices/platform/soc/78b7000.i2c/i2c-3/3-006a/power_supply/usb u:object_r:sysfs_usb_supply:s0
+genfscon sysfs /devices/platform/soc/78b7000.i2c/i2c-3/3-006a/power_supply/main u:object_r:sysfs_usb_supply:s0

三、kernel内核驱动

3.1、添加 ChargerIC 和电量计配置
/kernel/msm-4.9/arch/arm64/boot/dts/qcom/msm8953-mtp.dtsi

	bq25890: bq25890@6a {
		compatible = "ti,bq25890";
		reg = <0x6a>;
		ti,otg-charge = <1>;
		ti,otg-sw-supply = <&pm8953_l5>;
		ti,charge-enable-gpio = <&tlmm 2 0x00>;
		ti,interrupt-gpio = <&tlmm 137 0x00>;
		pinctrl-names = "default";
		pinctrl-0 = <&bq25980_gpio_default>;
	};

	cw2015: cw2015@62 {
		compatible = "cellwise,cw2015";
		reg = <0x62>;
	};

3.2、配置 ChargerIC 中断脚
kernel/msm-4.9/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi

bq25980_gpio_default: bq25980_gpio_default {
                        mux {
                                pins = "gpio137";
                                function = "gpio";
                        };

                        config {
                                pins = "gpio137";
                                drive-strength = <2>;
                                bias-pull-up;
                        };
                };

3.3、配置编译宏开关
kernel/msm-4.9/arch/arm64/configs/msm8953_defconfig

 CONFIG_CRYPTO_CRC32_ARM64=y
 CONFIG_QMI_ENCDEC=y
 CONFIG_KEYBOARD_TCA8418=y
+CONFIG_CHARGER_BQ25890=y
+CONFIG_BATTERY_CW2015=y

3.4、配置编译宏开关
kernel/msm-4.9/drivers/power/supply/Makefile

 obj-$(CONFIG_CHARGER_BQ24735)	+= bq24735-charger.o
 obj-$(CONFIG_CHARGER_BQ25890)	+= bq25890_charger.o
+obj-$(CONFIG_BATTERY_CW2015)	+= cw2015_battery.o
 obj-$(CONFIG_CHARGER_SMB347)	+= smb347-charger.o
 obj-$(CONFIG_CHARGER_TPS65090)	+= tps65090-charger.o

3.5、ChargerIC 驱动
kernel/msm-4.9/drivers/power/supply/bq25890_charger.c
3.6、电量计驱动
kernel/msm-4.9/drivers/power/supply/xxxx_battery.c

四、关机充电显示电量百分比

4.1、/system/core/healthd/healthd_draw.cpp

#define STR_LEN 8
void HealthdDraw::draw_percent(const animation* anim) {
  int cur_level = anim->cur_level;
  if (anim->cur_status == BATTERY_STATUS_FULL) {
    cur_level = 100;
  }

  if (cur_level <= 0) return;

  const animation::text_field& field = anim->text_percent;
  if (field.font == nullptr || field.font->char_width == 0 ||
      field.font->char_height == 0) {
    char cap_str[STR_LEN];
    int x, y;
    int str_len_px;
    static int char_height = -1, char_width = -1;

    if (char_height == -1 && char_width == -1)
        gr_font_size(gr_sys_font(), &char_width, &char_height);

    snprintf(cap_str, (STR_LEN - 1), "%d%%", cur_level);
    str_len_px = gr_measure(gr_sys_font(), cap_str);
    x = (gr_fb_width() - str_len_px) / 2;
    y = (gr_fb_height() + char_height) / 2;
    gr_color(0xa4, 0xc6, 0x39, 255);
    gr_text(gr_sys_font(), x, y, cap_str, 0);
    LOGE("draw_percent use default\n");
  } else {
    std::string str = base::StringPrintf("%d%%", cur_level);
    int x, y;
    determine_xy(field, str.size(), &x, &y);

    LOGV("drawing percent %s %d %d\n", str.c_str(), x, y);
    gr_color(field.color_r, field.color_g, field.color_b, field.color_a);
    draw_text(field.font, x, y, str.c_str());
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值