| /* arch/arm/mach-msm/htc_battery.c |
| * |
| * Copyright (C) 2008 HTC Corporation. |
| * Copyright (C) 2008 Google, Inc. |
| * |
| * This software is licensed under the terms of the GNU General Public |
| * License version 2, as published by the Free Software Foundation, and |
| * may be copied, distributed, and modified under those terms. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| */ |
| |
| #include <linux/init.h> |
| #include <linux/module.h> |
| #include <linux/kernel.h> |
| #include <linux/err.h> |
| #include <linux/power_supply.h> |
| #include <linux/platform_device.h> |
| #include <linux/debugfs.h> |
| #include <linux/wakelock.h> |
| #include <asm/gpio.h> |
| #include <mach/msm_rpcrouter.h> |
| #include <mach/board.h> |
| |
| static struct wake_lock vbus_wake_lock; |
| |
| #define TRACE_BATT 0 |
| |
| #if TRACE_BATT |
| #define BATT(x...) printk(KERN_INFO "[BATT] " x) |
| #else |
| #define BATT(x...) do {} while (0) |
| #endif |
| |
| /* rpc related */ |
| #define APP_BATT_PDEV_NAME "rs30100001" |
| #define APP_BATT_PROG 0x30100001 |
| #define APP_BATT_VER 0 |
| #define HTC_PROCEDURE_BATTERY_NULL 0 |
| #define HTC_PROCEDURE_GET_BATT_LEVEL 1 |
| #define HTC_PROCEDURE_GET_BATT_INFO 2 |
| #define HTC_PROCEDURE_GET_CABLE_STATUS 3 |
| #define HTC_PROCEDURE_SET_BATT_DELTA 4 |
| |
| /* module debugger */ |
| #define HTC_BATTERY_DEBUG 1 |
| #define BATTERY_PREVENTION 1 |
| |
| /* Enable this will shut down if no battery */ |
| #define ENABLE_BATTERY_DETECTION 0 |
| |
| #define GPIO_BATTERY_DETECTION 21 |
| #define GPIO_BATTERY_CHARGER_EN 128 |
| |
| /* Charge current selection */ |
| #define GPIO_BATTERY_CHARGER_CURRENT 129 |
| |
| typedef enum { |
| DISABLE = 0, |
| ENABLE_SLOW_CHG, |
| ENABLE_FAST_CHG |
| } batt_ctl_t; |
| |
| /* This order is the same as htc_power_supplies[] |
| * And it's also the same as htc_cable_status_update() |
| */ |
| typedef enum { |
| CHARGER_BATTERY = 0, |
| CHARGER_USB, |
| CHARGER_AC |
| } charger_type_t; |
| |
| struct battery_info_reply { |
| u32 batt_id; /* Battery ID from ADC */ |
| u32 batt_vol; /* Battery voltage from ADC */ |
| u32 batt_temp; /* Battery Temperature (C) from formula and ADC */ |
| u32 batt_current; /* Battery current from ADC */ |
| u32 level; /* formula */ |
| u32 charging_source; /* 0: no cable, 1:usb, 2:AC */ |
| u32 charging_enabled; /* 0: Disable, 1: Enable */ |
| u32 full_bat; /* Full capacity of battery (mAh) */ |
| }; |
| |
| struct htc_battery_info { |
| int present; |
| unsigned long update_time; |
| |
| /* lock to protect the battery info */ |
| struct mutex lock; |
| |
| /* lock held while calling the arm9 to query the battery info */ |
| struct mutex rpc_lock; |
| struct battery_info_reply rep; |
| }; |
| |
| static struct msm_rpc_endpoint *endpoint; |
| |
| static struct htc_battery_info htc_batt_info; |
| |
| static unsigned int cache_time = 1000; |
| |
| static int htc_battery_initial = 0; |
| |
| static enum power_supply_property htc_battery_properties[] = { |
| POWER_SUPPLY_PROP_STATUS, |
| POWER_SUPPLY_PROP_HEALTH, |
| POWER_SUPPLY_PROP_PRESENT, |
| POWER_SUPPLY_PROP_TECHNOLOGY, |
| POWER_SUPPLY_PROP_CAPACITY, |
| }; |
| |
| static enum power_supply_property htc_power_properties[] = { |
| POWER_SUPPLY_PROP_ONLINE, |
| }; |
| |
| static char *supply_list[] = { |
| "battery", |
| }; |
| |
| /* HTC dedicated attributes */ |
| static ssize_t htc_battery_show_property(struct device *dev, |
| struct device_attribute *attr, |
| char *buf); |
| |
| static int htc_power_get_property(struct power_supply *psy, |
| enum power_supply_property psp, |
| union power_supply_propval *val); |
| |
| static int htc_battery_get_property(struct power_supply *psy, |
| enum power_supply_property psp, |
| union power_supply_propval *val); |
| |
| static struct power_supply htc_power_supplies[] = { |
| { |
| .name = "battery", |
| .type = POWER_SUPPLY_TYPE_BATTERY, |
| .properties = htc_battery_properties, |
| .num_properties = ARRAY_SIZE(htc_battery_properties), |
| .get_property = htc_battery_get_property, |
| }, |
| { |
| .name = "usb", |
| .type = POWER_SUPPLY_TYPE_USB, |
| .supplied_to = supply_list, |
| .num_supplicants = ARRAY_SIZE(supply_list), |
| .properties = htc_power_properties, |
| .num_properties = ARRAY_SIZE(htc_power_properties), |
| .get_property = htc_power_get_property, |
| }, |
| { |
| .name = "ac", |
| .type = POWER_SUPPLY_TYPE_MAINS, |
| .supplied_to = supply_list, |
| .num_supplicants = ARRAY_SIZE(supply_list), |
| .properties = htc_power_properties, |
| .num_properties = ARRAY_SIZE(htc_power_properties), |
| .get_property = htc_power_get_property, |
| }, |
| }; |
| |
| |
| /* -------------------------------------------------------------------------- */ |
| |
| #if defined(CONFIG_DEBUG_FS) |
| int htc_battery_set_charging(batt_ctl_t ctl); |
| static int batt_debug_set(void *data, u64 val) |
| { |
| return htc_battery_set_charging((batt_ctl_t) val); |
| } |
| |
| static int batt_debug_get(void *data, u64 *val) |
| { |
| return -ENOSYS; |
| } |
| |
| DEFINE_SIMPLE_ATTRIBUTE(batt_debug_fops, batt_debug_get, batt_debug_set, "%llu\n"); |
| static int __init batt_debug_init(void) |
| { |
| struct dentry *dent; |
| |
| dent = debugfs_create_dir("htc_battery", 0); |
| if (IS_ERR(dent)) |
| return PTR_ERR(dent); |
| |
| debugfs_create_file("charger_state", 0644, dent, NULL, &batt_debug_fops); |
| |
| return 0; |
| } |
| |
| device_initcall(batt_debug_init); |
| #endif |
| |
| static int init_batt_gpio(void) |
| { |
| if (gpio_request(GPIO_BATTERY_DETECTION, "batt_detect") < 0) |
| goto gpio_failed; |
| if (gpio_request(GPIO_BATTERY_CHARGER_EN, "charger_en") < 0) |
| goto gpio_failed; |
| if (gpio_request(GPIO_BATTERY_CHARGER_CURRENT, "charge_current") < 0) |
| goto gpio_failed; |
| |
| return 0; |
| |
| gpio_failed: |
| return -EINVAL; |
| |
| } |
| |
| /* |
| * battery_charging_ctrl - battery charing control. |
| * @ctl: battery control command |
| * |
| */ |
| static int battery_charging_ctrl(batt_ctl_t ctl) |
| { |
| int result = 0; |
| |
| switch (ctl) { |
| case DISABLE: |
| BATT("charger OFF\n"); |
| /* 0 for enable; 1 disable */ |
| result = gpio_direction_output(GPIO_BATTERY_CHARGER_EN, 1); |
| break; |
| case ENABLE_SLOW_CHG: |
| BATT("charger ON (SLOW)\n"); |
| result = gpio_direction_output(GPIO_BATTERY_CHARGER_CURRENT, 0); |
| result = gpio_direction_output(GPIO_BATTERY_CHARGER_EN, 0); |
| break; |
| case ENABLE_FAST_CHG: |
| BATT("charger ON (FAST)\n"); |
| result = gpio_direction_output(GPIO_BATTERY_CHARGER_CURRENT, 1); |
| result = gpio_direction_output(GPIO_BATTERY_CHARGER_EN, 0); |
| break; |
| default: |
| printk(KERN_ERR "Not supported battery ctr called.!\n"); |
| result = -EINVAL; |
| break; |
| } |
| |
| return result; |
| } |
| |
| int htc_battery_set_charging(batt_ctl_t ctl) |
| { |
| int rc; |
| |
| if ((rc = battery_charging_ctrl(ctl)) < 0) |
| goto result; |
| |
| if (!htc_battery_initial) { |
| htc_batt_info.rep.charging_enabled = ctl & 0x3; |
| } else { |
| mutex_lock(&htc_batt_info.lock); |
| htc_batt_info.rep.charging_enabled = ctl & 0x3; |
| mutex_unlock(&htc_batt_info.lock); |
| } |
| result: |
| return rc; |
| } |
| |
| int htc_battery_status_update(u32 curr_level) |
| { |
| int notify; |
| if (!htc_battery_initial) |
| return 0; |
| |
| mutex_lock(&htc_batt_info.lock); |
| notify = (htc_batt_info.rep.level != curr_level); |
| htc_batt_info.rep.level = curr_level; |
| mutex_unlock(&htc_batt_info.lock); |
| |
| if (notify) |
| power_supply_changed(&htc_power_supplies[CHARGER_BATTERY]); |
| return 0; |
| } |
| |
| int htc_cable_status_update(int status) |
| { |
| int rc = 0; |
| unsigned source; |
| |
| if (!htc_battery_initial) |
| return 0; |
| |
| mutex_lock(&htc_batt_info.lock); |
| switch(status) { |
| case CHARGER_BATTERY: |
| BATT("cable NOT PRESENT\n"); |
| htc_batt_info.rep.charging_source = CHARGER_BATTERY; |
| break; |
| case CHARGER_USB: |
| BATT("cable USB\n"); |
| htc_batt_info.rep.charging_source = CHARGER_USB; |
| break; |
| case CHARGER_AC: |
| BATT("cable AC\n"); |
| htc_batt_info.rep.charging_source = CHARGER_AC; |
| break; |
| default: |
| printk(KERN_ERR "%s: Not supported cable status received!\n", |
| __FUNCTION__); |
| rc = -EINVAL; |
| } |
| source = htc_batt_info.rep.charging_source; |
| mutex_unlock(&htc_batt_info.lock); |
| |
| msm_hsusb_set_vbus_state(source == CHARGER_USB); |
| if (source == CHARGER_USB) { |
| wake_lock(&vbus_wake_lock); |
| } else { |
| /* give userspace some time to see the uevent and update |
| * LED state or whatnot... |
| */ |
| wake_lock_timeout(&vbus_wake_lock, HZ / 2); |
| } |
| |
| /* if the power source changes, all power supplies may change state */ |
| power_supply_changed(&htc_power_supplies[CHARGER_BATTERY]); |
| power_supply_changed(&htc_power_supplies[CHARGER_USB]); |
| power_supply_changed(&htc_power_supplies[CHARGER_AC]); |
| |
| return rc; |
| } |
| |
| static int htc_get_batt_info(struct battery_info_reply *buffer) |
| { |
| struct rpc_request_hdr req; |
| |
| struct htc_get_batt_info_rep { |
| struct rpc_reply_hdr hdr; |
| struct battery_info_reply info; |
| } rep; |
| |
| int rc; |
| |
| if (buffer == NULL) |
| return -EINVAL; |
| |
| rc = msm_rpc_call_reply(endpoint, HTC_PROCEDURE_GET_BATT_INFO, |
| &req, sizeof(req), |
| &rep, sizeof(rep), |
| 5 * HZ); |
| if ( rc < 0 ) |
| return rc; |
| |
| mutex_lock(&htc_batt_info.lock); |
| buffer->batt_id = be32_to_cpu(rep.info.batt_id); |
| buffer->batt_vol = be32_to_cpu(rep.info.batt_vol); |
| buffer->batt_temp = be32_to_cpu(rep.info.batt_temp); |
| buffer->batt_current = be32_to_cpu(rep.info.batt_current); |
| buffer->level = be32_to_cpu(rep.info.level); |
| buffer->charging_source = be32_to_cpu(rep.info.charging_source); |
| buffer->charging_enabled = be32_to_cpu(rep.info.charging_enabled); |
| buffer->full_bat = be32_to_cpu(rep.info.full_bat); |
| mutex_unlock(&htc_batt_info.lock); |
| |
| return 0; |
| } |
| |
| #if 0 |
| static int htc_get_cable_status(void) |
| { |
| |
| struct rpc_request_hdr req; |
| |
| struct htc_get_cable_status_rep { |
| struct rpc_reply_hdr hdr; |
| int status; |
| } rep; |
| |
| int rc; |
| |
| rc = msm_rpc_call_reply(endpoint, HTC_PROCEDURE_GET_CABLE_STATUS, |
| &req, sizeof(req), |
| &rep, sizeof(rep), |
| 5 * HZ); |
| if (rc < 0) |
| return rc; |
| |
| return be32_to_cpu(rep.status); |
| } |
| #endif |
| |
| /* -------------------------------------------------------------------------- */ |
| static int htc_power_get_property(struct power_supply *psy, |
| enum power_supply_property psp, |
| union power_supply_propval *val) |
| { |
| charger_type_t charger; |
| |
| mutex_lock(&htc_batt_info.lock); |
| charger = htc_batt_info.rep.charging_source; |
| mutex_unlock(&htc_batt_info.lock); |
| |
| switch (psp) { |
| case POWER_SUPPLY_PROP_ONLINE: |
| if (psy->type == POWER_SUPPLY_TYPE_MAINS) |
| val->intval = (charger == CHARGER_AC ? 1 : 0); |
| else if (psy->type == POWER_SUPPLY_TYPE_USB) |
| val->intval = (charger == CHARGER_USB ? 1 : 0); |
| else |
| val->intval = 0; |
| break; |
| default: |
| return -EINVAL; |
| } |
| |
| return 0; |
| } |
| |
| static int htc_battery_get_charging_status(void) |
| { |
| u32 level; |
| charger_type_t charger; |
| int ret; |
| |
| mutex_lock(&htc_batt_info.lock); |
| charger = htc_batt_info.rep.charging_source; |
| |
| switch (charger) { |
| case CHARGER_BATTERY: |
| ret = POWER_SUPPLY_STATUS_NOT_CHARGING; |
| break; |
| case CHARGER_USB: |
| case CHARGER_AC: |
| level = htc_batt_info.rep.level; |
| if (level == 100) |
| ret = POWER_SUPPLY_STATUS_FULL; |
| else |
| ret = POWER_SUPPLY_STATUS_CHARGING; |
| break; |
| default: |
| ret = POWER_SUPPLY_STATUS_UNKNOWN; |
| } |
| mutex_unlock(&htc_batt_info.lock); |
| return ret; |
| } |
| |
| static int htc_battery_get_property(struct power_supply *psy, |
| enum power_supply_property psp, |
| union power_supply_propval *val) |
| { |
| switch (psp) { |
| case POWER_SUPPLY_PROP_STATUS: |
| val->intval = htc_battery_get_charging_status(); |
| break; |
| case POWER_SUPPLY_PROP_HEALTH: |
| val->intval = POWER_SUPPLY_HEALTH_GOOD; |
| break; |
| case POWER_SUPPLY_PROP_PRESENT: |
| val->intval = htc_batt_info.present; |
| break; |
| case POWER_SUPPLY_PROP_TECHNOLOGY: |
| val->intval = POWER_SUPPLY_TECHNOLOGY_LION; |
| break; |
| case POWER_SUPPLY_PROP_CAPACITY: |
| mutex_lock(&htc_batt_info.lock); |
| val->intval = htc_batt_info.rep.level; |
| mutex_unlock(&htc_batt_info.lock); |
| break; |
| default: |
| return -EINVAL; |
| } |
| |
| return 0; |
| } |
| |
| #define HTC_BATTERY_ATTR(_name) \ |
| { \ |
| .attr = { .name = #_name, .mode = S_IRUGO, .owner = THIS_MODULE }, \ |
| .show = htc_battery_show_property, \ |
| .store = NULL, \ |
| } |
| |
| static struct device_attribute htc_battery_attrs[] = { |
| HTC_BATTERY_ATTR(batt_id), |
| HTC_BATTERY_ATTR(batt_vol), |
| HTC_BATTERY_ATTR(batt_temp), |
| HTC_BATTERY_ATTR(batt_current), |
| HTC_BATTERY_ATTR(charging_source), |
| HTC_BATTERY_ATTR(charging_enabled), |
| HTC_BATTERY_ATTR(full_bat), |
| }; |
| |
| enum { |
| BATT_ID = 0, |
| BATT_VOL, |
| BATT_TEMP, |
| BATT_CURRENT, |
| CHARGING_SOURCE, |
| CHARGING_ENABLED, |
| FULL_BAT, |
| }; |
| |
| static int htc_rpc_set_delta(unsigned delta) |
| { |
| struct set_batt_delta_req { |
| struct rpc_request_hdr hdr; |
| uint32_t data; |
| } req; |
| |
| req.data = cpu_to_be32(delta); |
| return msm_rpc_call(endpoint, HTC_PROCEDURE_SET_BATT_DELTA, |
| &req, sizeof(req), 5 * HZ); |
| } |
| |
| |
| static ssize_t htc_battery_set_delta(struct device *dev, |
| struct device_attribute *attr, |
| const char *buf, size_t count) |
| { |
| int rc; |
| unsigned long delta = 0; |
| |
| delta = simple_strtoul(buf, NULL, 10); |
| |
| if (delta > 100) |
| return -EINVAL; |
| |
| mutex_lock(&htc_batt_info.rpc_lock); |
| rc = htc_rpc_set_delta(delta); |
| mutex_unlock(&htc_batt_info.rpc_lock); |
| if (rc < 0) |
| return rc; |
| return count; |
| } |
| |
| static struct device_attribute htc_set_delta_attrs[] = { |
| __ATTR(delta, S_IWUSR | S_IWGRP, NULL, htc_battery_set_delta), |
| }; |
| |
| static int htc_battery_create_attrs(struct device * dev) |
| { |
| int i, j, rc; |
| |
| for (i = 0; i < ARRAY_SIZE(htc_battery_attrs); i++) { |
| rc = device_create_file(dev, &htc_battery_attrs[i]); |
| if (rc) |
| goto htc_attrs_failed; |
| } |
| |
| for (j = 0; j < ARRAY_SIZE(htc_set_delta_attrs); j++) { |
| rc = device_create_file(dev, &htc_set_delta_attrs[j]); |
| if (rc) |
| goto htc_delta_attrs_failed; |
| } |
| |
| goto succeed; |
| |
| htc_attrs_failed: |
| while (i--) |
| device_remove_file(dev, &htc_battery_attrs[i]); |
| htc_delta_attrs_failed: |
| while (j--) |
| device_remove_file(dev, &htc_set_delta_attrs[i]); |
| succeed: |
| return rc; |
| } |
| |
| static ssize_t htc_battery_show_property(struct device *dev, |
| struct device_attribute *attr, |
| char *buf) |
| { |
| int i = 0; |
| const ptrdiff_t off = attr - htc_battery_attrs; |
| |
| /* rpc lock is used to prevent two threads from calling |
| * into the get info rpc at the same time |
| */ |
| |
| mutex_lock(&htc_batt_info.rpc_lock); |
| /* check cache time to decide if we need to update */ |
| if (htc_batt_info.update_time && |
| time_before(jiffies, htc_batt_info.update_time + |
| msecs_to_jiffies(cache_time))) |
| goto dont_need_update; |
| |
| if (htc_get_batt_info(&htc_batt_info.rep) < 0) |
| printk(KERN_ERR "%s: rpc failed!!!\n", __FUNCTION__); |
| else |
| htc_batt_info.update_time = jiffies; |
| dont_need_update: |
| mutex_unlock(&htc_batt_info.rpc_lock); |
| |
| mutex_lock(&htc_batt_info.lock); |
| switch (off) { |
| case BATT_ID: |
| i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", |
| htc_batt_info.rep.batt_id); |
| break; |
| case BATT_VOL: |
| i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", |
| htc_batt_info.rep.batt_vol); |
| break; |
| case BATT_TEMP: |
| i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", |
| htc_batt_info.rep.batt_temp); |
| break; |
| case BATT_CURRENT: |
| i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", |
| htc_batt_info.rep.batt_current); |
| break; |
| case CHARGING_SOURCE: |
| i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", |
| htc_batt_info.rep.charging_source); |
| break; |
| case CHARGING_ENABLED: |
| i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", |
| htc_batt_info.rep.charging_enabled); |
| break; |
| case FULL_BAT: |
| i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", |
| htc_batt_info.rep.full_bat); |
| break; |
| default: |
| i = -EINVAL; |
| } |
| mutex_unlock(&htc_batt_info.lock); |
| |
| return i; |
| } |
| |
| static int htc_battery_probe(struct platform_device *pdev) |
| { |
| int i, rc; |
| |
| if (pdev->id != (APP_BATT_VER & RPC_VERSION_MAJOR_MASK)) |
| return -EINVAL; |
| |
| /* init battery gpio */ |
| if ((rc = init_batt_gpio()) < 0) { |
| printk(KERN_ERR "%s: init battery gpio failed!\n", __FUNCTION__); |
| return rc; |
| } |
| |
| /* init structure data member */ |
| htc_batt_info.update_time = jiffies; |
| htc_batt_info.present = gpio_get_value(GPIO_BATTERY_DETECTION); |
| |
| /* init rpc */ |
| endpoint = msm_rpc_connect(APP_BATT_PROG, APP_BATT_VER, 0); |
| if (IS_ERR(endpoint)) { |
| printk(KERN_ERR "%s: init rpc failed! rc = %ld\n", |
| __FUNCTION__, PTR_ERR(endpoint)); |
| return rc; |
| } |
| |
| /* init power supplier framework */ |
| for (i = 0; i < ARRAY_SIZE(htc_power_supplies); i++) { |
| rc = power_supply_register(&pdev->dev, &htc_power_supplies[i]); |
| if (rc) |
| printk(KERN_ERR "Failed to register power supply (%d)\n", rc); |
| } |
| |
| /* create htc detail attributes */ |
| htc_battery_create_attrs(htc_power_supplies[CHARGER_BATTERY].dev); |
| |
| /* After battery driver gets initialized, send rpc request to inquiry |
| * the battery status in case of we lost some info |
| */ |
| htc_battery_initial = 1; |
| |
| mutex_lock(&htc_batt_info.rpc_lock); |
| if (htc_get_batt_info(&htc_batt_info.rep) < 0) |
| printk(KERN_ERR "%s: get info failed\n", __FUNCTION__); |
| |
| htc_cable_status_update(htc_batt_info.rep.charging_source); |
| battery_charging_ctrl(htc_batt_info.rep.charging_enabled ? |
| ENABLE_SLOW_CHG : DISABLE); |
| |
| if (htc_rpc_set_delta(1) < 0) |
| printk(KERN_ERR "%s: set delta failed\n", __FUNCTION__); |
| htc_batt_info.update_time = jiffies; |
| mutex_unlock(&htc_batt_info.rpc_lock); |
| |
| if (htc_batt_info.rep.charging_enabled == 0) |
| battery_charging_ctrl(DISABLE); |
| |
| return 0; |
| } |
| |
| static struct platform_driver htc_battery_driver = { |
| .probe = htc_battery_probe, |
| .driver = { |
| .name = APP_BATT_PDEV_NAME, |
| .owner = THIS_MODULE, |
| }, |
| }; |
| |
| /* batt_mtoa server definitions */ |
| #define BATT_MTOA_PROG 0x30100000 |
| #define BATT_MTOA_VERS 0 |
| #define RPC_BATT_MTOA_NULL 0 |
| #define RPC_BATT_MTOA_SET_CHARGING_PROC 1 |
| #define RPC_BATT_MTOA_CABLE_STATUS_UPDATE_PROC 2 |
| #define RPC_BATT_MTOA_LEVEL_UPDATE_PROC 3 |
| |
| struct rpc_batt_mtoa_set_charging_args { |
| int enable; |
| }; |
| |
| struct rpc_batt_mtoa_cable_status_update_args { |
| int status; |
| }; |
| |
| struct rpc_dem_battery_update_args { |
| uint32_t level; |
| }; |
| |
| static int handle_battery_call(struct msm_rpc_server *server, |
| struct rpc_request_hdr *req, unsigned len) |
| { |
| switch (req->procedure) { |
| case RPC_BATT_MTOA_NULL: |
| return 0; |
| |
| case RPC_BATT_MTOA_SET_CHARGING_PROC: { |
| struct rpc_batt_mtoa_set_charging_args *args; |
| args = (struct rpc_batt_mtoa_set_charging_args *)(req + 1); |
| args->enable = be32_to_cpu(args->enable); |
| BATT("set_charging: enable=%d\n",args->enable); |
| htc_battery_set_charging(args->enable); |
| return 0; |
| } |
| case RPC_BATT_MTOA_CABLE_STATUS_UPDATE_PROC: { |
| struct rpc_batt_mtoa_cable_status_update_args *args; |
| args = (struct rpc_batt_mtoa_cable_status_update_args *)(req + 1); |
| args->status = be32_to_cpu(args->status); |
| BATT("cable_status_update: status=%d\n",args->status); |
| htc_cable_status_update(args->status); |
| return 0; |
| } |
| case RPC_BATT_MTOA_LEVEL_UPDATE_PROC: { |
| struct rpc_dem_battery_update_args *args; |
| args = (struct rpc_dem_battery_update_args *)(req + 1); |
| args->level = be32_to_cpu(args->level); |
| BATT("dem_battery_update: level=%d\n",args->level); |
| htc_battery_status_update(args->level); |
| return 0; |
| } |
| default: |
| printk(KERN_ERR "%s: program 0x%08x:%d: unknown procedure %d\n", |
| __FUNCTION__, req->prog, req->vers, req->procedure); |
| return -ENODEV; |
| } |
| } |
| |
| static struct msm_rpc_server battery_server = { |
| .prog = BATT_MTOA_PROG, |
| .vers = BATT_MTOA_VERS, |
| .rpc_call = handle_battery_call, |
| }; |
| |
| static int __init htc_battery_init(void) |
| { |
| wake_lock_init(&vbus_wake_lock, WAKE_LOCK_SUSPEND, "vbus_present"); |
| mutex_init(&htc_batt_info.lock); |
| mutex_init(&htc_batt_info.rpc_lock); |
| msm_rpc_create_server(&battery_server); |
| platform_driver_register(&htc_battery_driver); |
| return 0; |
| } |
| |
| module_init(htc_battery_init); |
| MODULE_DESCRIPTION("HTC Battery Driver"); |
| MODULE_LICENSE("GPL"); |
| |