mtk GM3.0流程

创建了一个netlink用于给上层获取电池各类信息,如bat_current,charger_status等,详见bmd_ctrl_cmd_from_user函数

static int __init battery_init(void)
{
 struct netlink_kernel_cfg cfg = {
  .input = nl_data_handler,
 };
 int ret;
 daemo_nl_sk = netlink_kernel_create(&init_net, NETLINK_FGD, &cfg);
 bm_err("netlink_kernel_create protol= %d\n", NETLINK_FGD);
 if (daemo_nl_sk == NULL) {
  bm_err("netlink_kernel_create error\n");
  return -1;
 }
 bm_err("netlink_kernel_create ok\n");
#ifdef CONFIG_OF
 /* register battery_device by DTS */
#else
 ret = platform_device_register(&battery_device);
#endif
 ret = platform_driver_register(&battery_driver_probe);
 ret = platform_driver_register(&battery_dts_driver_probe);
 bm_err("[battery_init] Initialization : DONE\n");
 return 0;
}

nl_data_handler

struct fgd_nl_msg_t {
    unsigned int fgd_cmd;
    unsigned int fgd_subcmd;
    unsigned int fgd_subcmd_para1;
    unsigned int fgd_data_len;
    unsigned int fgd_ret_data_len;
    char fgd_data[FGD_NL_MSG_MAX_LEN];
};

static struct sock *daemo_nl_sk;
static void nl_data_handler(struct sk_buff *skb) {
    u32 pid;
    kuid_t uid;
    int seq;
    void *data;
    struct nlmsghdr *nlh;
    struct fgd_nl_msg_t *fgd_msg, *fgd_ret_msg;
    int size = 0;//拿出数据
    nlh = (struct nlmsghdr *)skb->data;
    pid = NETLINK_CREDS(skb)->pid;
    uid = NETLINK_CREDS(skb)->uid;
    seq = nlh->nlmsg_seq;
    /*bm_debug("[Netlink] recv skb from user space uid:%d pid:%d seq:%d\n",uid,pid,seq); */
    data = NLMSG_DATA(nlh);//取得消息的数据部分的首地

    fgd_msg = (struct fgd_nl_msg_t *)data;

    size = fgd_msg->fgd_ret_data_len + FGD_NL_MSG_T_HDR_LEN;

    fgd_ret_msg = vmalloc(size);
    if (!fgd_ret_msg) {
        /* bm_err("Error: nl_data_handler() vmalloc fail!!!\n"); */
        return;
    }

    memset(fgd_ret_msg, 0, size);

    bmd_ctrl_cmd_from_user(data, fgd_ret_msg);//数据到fgd_ret_msg
    nl_send_to_user(pid, seq, fgd_ret_msg);

    vfree(fgd_ret_msg);
}

根据不同的fgd_cmd填充fgd_data以及fgd_data_len

bmd_ctrl_cmd_from_user

void bmd_ctrl_cmd_from_user(void *nl_data, struct fgd_nl_msg_t *ret_msg)
{
    struct fgd_nl_msg_t *msg;
    static int ptim_vbat, ptim_i;

    msg = nl_data;
    ret_msg->fgd_cmd = msg->fgd_cmd;

    switch (msg->fgd_cmd) {

    case FG_DAEMON_CMD_IS_BAT_PLUGOUT:
        {
            int is_bat_plugout = 0;
            int bat_plugout_time = 0;

            gauge_dev_get_boot_battery_plug_out_status(gauge_dev, &is_bat_plugout, &bat_plugout_time);
            ret_msg->fgd_data_len += sizeof(is_bat_plugout);
            memcpy(ret_msg->fgd_data, &is_bat_plugout, sizeof(is_bat_plugout));

            bm_debug("[fg_res] BATTERY_METER_CMD_GET_BOOT_BATTERY_PLUG_STATUS = %d\n", is_bat_plugout);
        }
        break;
    case FG_DAEMON_CMD_GET_FG_SHUTDOWN_COND:
        {
            unsigned int shutdown_cond = get_shutdown_cond();

            ret_msg->fgd_data_len += sizeof(shutdown_cond);
            memcpy(ret_msg->fgd_data, &shutdown_cond, sizeof(shutdown_cond));

            bm_debug("[fg_res] shutdown_cond = %d\n", shutdown_cond);
        }
        break;

如在FG_DAEMON_CMD_GET_FG_SHUTDOWN_COND获取的是,是否满足关机条件

int get_shutdown_cond(void)
{
    int ret = 0;
    int vbat = pmic_get_battery_voltage();

    if (sdc.shutdown_status.is_soc_zero_percent)
        ret |= 1;
    if (sdc.shutdown_status.is_uisoc_one_percent)
        ret |= 1;
    if (sdc.lowbatteryshutdown)
        ret |= 1;
    bm_err("get_shutdown_cond ret:%d %d %d %d vbat:%d\n",
    ret, sdc.shutdown_status.is_soc_zero_percent,
    sdc.shutdown_status.is_uisoc_one_percent,
    sdc.lowbatteryshutdown, vbat);

    return ret;
}

向user发送数据

static void nl_send_to_user(u32 pid, int seq, struct fgd_nl_msg_t *reply_msg)
{
    struct sk_buff *skb;
    struct nlmsghdr *nlh;
    /* int size=sizeof(struct fgd_nl_msg_t); */
    int size = reply_msg->fgd_data_len + FGD_NL_MSG_T_HDR_LEN;
    int len = NLMSG_SPACE(size);
    void *data;
    int ret;

    skb = alloc_skb(len, GFP_ATOMIC);//alloc skb
    if (!skb)
        return;

    nlh = nlmsg_put(skb, pid, seq, 0, size, 0);//设置netlink消息头
    data = NLMSG_DATA(nlh);//首地址赋予data
    memcpy(data, reply_msg, size);//将要发送给user的msg赋予skb
    NETLINK_CB(skb).portid = 0;    /* from kernel */
    NETLINK_CB(skb).dst_group = 0;    /* unicast 单播。多播为5*/

    ret = netlink_unicast(daemo_nl_sk, skb, pid, MSG_DONTWAIT);//send msg
    if (ret < 0) {
        bm_err("[Netlink] send failed %d\n", ret);
        return;
    }
    /*bm_debug("[Netlink] reply_user: netlink_unicast- ret=%d\n", ret); */


}

一共注册了两个平台

#ifdef CONFIG_OF
static const struct of_device_id mtk_bat_of_match[] = {
    {.compatible = "mediatek,bat_gm30",},
    {},
};
MODULE_DEVICE_TABLE(of, mtk_bat_of_match);
#endi
static struct platform_driver battery_dts_driver_probe = {
    .probe = battery_dts_probe,
    .remove = NULL,
    .shutdown = NULL,
    .suspend = NULL,
    .resume = NULL,
    .driver = {
        .name = "battery-dts",
#ifdef CONFIG_OF
        .of_match_table = mtk_bat_of_match,
#endif
    },
};

static struct platform_driver battery_driver_probe = {
    .probe = battery_probe,
    .remove = NULL,
    .shutdown = NULL,
    .suspend = battery_suspend,
    .resume = battery_resume,
    .driver = {
           .name = "battery",
    },
};

在fg_custom_init_from_dts中解析设备树

static int battery_dts_probe(struct platform_device *dev)
{
 int ret = 0;
 bm_err("******** battery_dts_probe!! ********\n");
 battery_device.dev.of_node = dev->dev.of_node;
 ret = platform_device_register(&battery_device);
 if (ret) {
  bm_err("****[battery_dts_probe] Unable to register device (%d)\n", ret);
  return ret;
 }
 check_isevb_dtsi(dev);
 fg_custom_init_from_dts(dev);
 return 0;
}

从中可以得知目前mtk电池曲线是按照mah,voltage,resistance,percentage来读取的

switch (bat_id) {
  case 0:
   fg_custom_parse_table(np, "battery0_profile_t0",
    fg_table_cust_data.fg_profile_t0);
   fg_custom_parse_table(np, "battery0_profile_t1",
    fg_table_cust_data.fg_profile_t1);
   fg_custom_parse_table(np, "battery0_profile_t2",
    fg_table_cust_data.fg_profile_t2);
   fg_custom_parse_table(np, "battery0_profile_t3",
    fg_table_cust_data.fg_profile_t3);
#ifdef CONFIG_MTK_ADDITIONAL_BATTERY_TABLE
   fg_custom_parse_table(np, "battery0_profile_t4",
    fg_table_cust_data.fg_profile_t4);
#endif

struct FUELGAUGE_PROFILE_STRUCT {
 unsigned int mah;
 unsigned short voltage
 unsigned short resistance; /* Ohm*/
 unsigned short resistance;
};

而在fg_custom_parse_table中实际用到的只有mah,voltage,resistance;

static void fg_custom_parse_table(const struct device_node *np,
    const char *node_srting, struct FUELGAUGE_PROFILE_STRUCT *profile_struct)
{
 int mah, voltage, resistance, idx, saddles;
 struct FUELGAUGE_PROFILE_STRUCT *profile_p;
 profile_p = profile_struct;
 saddles = fg_table_cust_data.fg_profile_t0_size;
 idx = 0;
 bm_debug("fg_custom_parse_table: %s, %d\n", node_srting, saddles);
 while (!of_property_read_u32_index(np, node_srting, idx, &mah)) {
  idx++;
  if (!of_property_read_u32_index(np, node_srting, idx, &voltage)) {
   /*bm_err("fg_custom_parse_table: mah: %d, voltage: %d\n", mah, voltage);*/
   /*bm_err("fg_custom_parse_table: mah: %d, voltage: %d\n", mah, voltage);*/
  }
  idx++;
  if (!of_property_read_u32_index(np, node_srting, idx, &resistance)) {
   bm_debug("fg_custom_parse_table: mah: %d, voltage: %d, resistance: %d\n",
        mah, voltage, resistance);
  }
  profile_p->mah = mah;
  profile_p->voltage = voltage;
  profile_p->resistance = resistance;
  /* dump parsing data */
  #if 0
  msleep(20);
  bm_print(BM_LOG_CRTI, "__batt_meter_parse_table>> %s[%d]: <%d, %d>\n",
    node_srting, (idx/2), profile_p->percentage, profile_p->voltage);
  #endif
  profile_p++;
  if ((idx++) >= (saddles * 3))
   break;
 }

你可能感兴趣的:(power)