diff options
| author | Doug Zobel <dzobel1@motorola.com> | 2013-11-15 14:29:07 -0600 |
|---|---|---|
| committer | James Wylder <jwylder@motorola.com> | 2014-03-05 17:46:52 -0600 |
| commit | d2a782003a6047da120a33e6f8ee6fd33bb825d6 (patch) | |
| tree | 8d20bd4ecda62a06e98993c4108456bc1acb0d0b /drivers/power/cpcap-battery.c | |
| parent | 32fd2d36d2464056d4522a9c02797b7c2b2e884f (diff) | |
| download | olio-linux-3.10-d2a782003a6047da120a33e6f8ee6fd33bb825d6.tar.xz olio-linux-3.10-d2a782003a6047da120a33e6f8ee6fd33bb825d6.zip | |
CW integration and minnow bringup
* create minnow machine type
* create Android makefile
* add pre-commit syntax check
* enable -Werror
* Add drivers: CPCAP, TPS65xxx, m4sensorhub, atmxt, lm3535,
usb gadget, minnow display, TI 12xx wireless
Change-Id: I7962f5e1256715f2452aed5a62a4f2f2383d5046
Diffstat (limited to 'drivers/power/cpcap-battery.c')
| -rw-r--r-- | drivers/power/cpcap-battery.c | 823 |
1 files changed, 823 insertions, 0 deletions
diff --git a/drivers/power/cpcap-battery.c b/drivers/power/cpcap-battery.c new file mode 100644 index 00000000000..517d41bb919 --- /dev/null +++ b/drivers/power/cpcap-battery.c @@ -0,0 +1,823 @@ +/* + * Copyright (C) 2007-2009 Motorola, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307, USA + */ + +#include <asm/div64.h> +#include <linux/device.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/platform_device.h> +#include <linux/poll.h> +#include <linux/power_supply.h> +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/spi/cpcap.h> +#include <linux/spi/cpcap-regbits.h> +#include <linux/spi/spi.h> +#include <linux/time.h> +#include <linux/miscdevice.h> +#include <linux/debugfs.h> + +#define CPCAP_BATT_IRQ_BATTDET 0x01 +#define CPCAP_BATT_IRQ_OV 0x02 +#define CPCAP_BATT_IRQ_CC_CAL 0x04 +#define CPCAP_BATT_IRQ_ADCDONE 0x08 +#define CPCAP_BATT_IRQ_MACRO 0x10 + +static long cpcap_batt_ioctl( + struct file *file, + unsigned int cmd, + unsigned long arg); +static unsigned int cpcap_batt_poll(struct file *file, poll_table *wait); +static int cpcap_batt_open(struct inode *inode, struct file *file); +static ssize_t cpcap_batt_read(struct file *file, char *buf, size_t count, + loff_t *ppos); +static int cpcap_batt_probe(struct platform_device *pdev); +static int cpcap_batt_remove(struct platform_device *pdev); +static int cpcap_batt_resume(struct platform_device *pdev); + +struct cpcap_batt_ps { + struct power_supply batt; + struct power_supply ac; + struct power_supply usb; + struct cpcap_device *cpcap; + struct cpcap_batt_data batt_state; + struct cpcap_batt_ac_data ac_state; + struct cpcap_batt_usb_data usb_state; + struct cpcap_adc_request req; + struct mutex lock; + char irq_status; + char data_pending; + wait_queue_head_t wait; + char async_req_pending; + unsigned long last_run_time; + bool no_update; +}; + +static const struct file_operations batt_fops = { + .owner = THIS_MODULE, + .open = cpcap_batt_open, + .unlocked_ioctl = cpcap_batt_ioctl, + .read = cpcap_batt_read, + .poll = cpcap_batt_poll, +}; + +static struct miscdevice batt_dev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "cpcap_batt", + .fops = &batt_fops, +}; + +static enum power_supply_property cpcap_batt_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_CHARGE_COUNTER +}; + +static enum power_supply_property cpcap_batt_ac_props[] = +{ + POWER_SUPPLY_PROP_ONLINE +}; + +static enum power_supply_property cpcap_batt_usb_props[] = +{ + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_MODEL_NAME +}; + +static struct platform_driver cpcap_batt_driver = { + .probe = cpcap_batt_probe, + .remove = cpcap_batt_remove, + .resume = cpcap_batt_resume, + .driver = { + .name = "cpcap_battery", + .owner = THIS_MODULE, + }, +}; + +static struct cpcap_batt_ps *cpcap_batt_sply; + +void cpcap_batt_irq_hdlr(enum cpcap_irqs irq, void *data) +{ + struct cpcap_batt_ps *sply = data; + + mutex_lock(&sply->lock); + sply->data_pending = 1; + + switch (irq) { + case CPCAP_IRQ_BATTDETB: + sply->irq_status |= CPCAP_BATT_IRQ_BATTDET; + cpcap_irq_unmask(sply->cpcap, irq); + break; + + case CPCAP_IRQ_VBUSOV: + sply->irq_status |= CPCAP_BATT_IRQ_OV; + cpcap_irq_unmask(sply->cpcap, irq); + break; + + case CPCAP_IRQ_CC_CAL: + sply->irq_status |= CPCAP_BATT_IRQ_CC_CAL; + cpcap_irq_unmask(sply->cpcap, irq); + break; + + case CPCAP_IRQ_UC_PRIMACRO_7: + case CPCAP_IRQ_UC_PRIMACRO_8: + case CPCAP_IRQ_UC_PRIMACRO_9: + case CPCAP_IRQ_UC_PRIMACRO_10: + case CPCAP_IRQ_UC_PRIMACRO_11: + sply->irq_status |= CPCAP_BATT_IRQ_MACRO; + break; + default: + break; + } + + mutex_unlock(&sply->lock); + + wake_up_interruptible(&sply->wait); +} + +void cpcap_batt_adc_hdlr(struct cpcap_device *cpcap, void *data) +{ + struct cpcap_batt_ps *sply = data; + mutex_lock(&sply->lock); + + sply->async_req_pending = 0; + + sply->data_pending = 1; + + sply->irq_status |= CPCAP_BATT_IRQ_ADCDONE; + + mutex_unlock(&sply->lock); + + wake_up_interruptible(&sply->wait); +} + +static int cpcap_batt_open(struct inode *inode, struct file *file) +{ + file->private_data = cpcap_batt_sply; + return 0; +} + +static unsigned int cpcap_batt_poll(struct file *file, poll_table *wait) +{ + struct cpcap_batt_ps *sply = file->private_data; + unsigned int ret = 0; + + poll_wait(file, &sply->wait, wait); + + if (sply->data_pending) + ret = (POLLIN | POLLRDNORM); + + return ret; +} + +static ssize_t cpcap_batt_read(struct file *file, + char *buf, size_t count, loff_t *ppos) +{ + struct cpcap_batt_ps *sply = file->private_data; + int ret = -EFBIG; + unsigned long long temp; + + if (count >= sizeof(char)) { + mutex_lock(&sply->lock); + if (!copy_to_user((void *)buf, (void *)&sply->irq_status, + sizeof(sply->irq_status))) + ret = sizeof(sply->irq_status); + else + ret = -EFAULT; + sply->data_pending = 0; + temp = sched_clock(); + do_div(temp, NSEC_PER_SEC); + sply->last_run_time = (unsigned long)temp; + + sply->irq_status = 0; + mutex_unlock(&sply->lock); + } + + return ret; +} + +static long cpcap_batt_ioctl( + struct file *file, + unsigned int cmd, + unsigned long arg) +{ + long ret = 0; + int i; + struct cpcap_batt_ps *sply = file->private_data; + struct cpcap_adc_request *req_async = &sply->req; + struct cpcap_adc_request req; + struct cpcap_adc_us_request req_us; + struct spi_device *spi = sply->cpcap->spi; + struct cpcap_platform_data *data = spi->controller_data; + + switch (cmd) { + case CPCAP_IOCTL_BATT_DISPLAY_UPDATE: + if (sply->no_update) + return 0; + if (copy_from_user((void *)&sply->batt_state, + (void *)arg, sizeof(struct cpcap_batt_data))) + return -EFAULT; + power_supply_changed(&sply->batt); + + if (data->batt_changed) + data->batt_changed(&sply->batt, &sply->batt_state); + break; + + case CPCAP_IOCTL_BATT_ATOD_ASYNC: + mutex_lock(&sply->lock); + if (!sply->async_req_pending) { + if (copy_from_user((void *)&req_us, (void *)arg, + sizeof(struct cpcap_adc_us_request) + )) { + mutex_unlock(&sply->lock); + return -EFAULT; + } + + req_async->format = req_us.format; + req_async->timing = req_us.timing; + req_async->type = req_us.type; + req_async->callback = cpcap_batt_adc_hdlr; + req_async->callback_param = sply; + + ret = cpcap_adc_async_read(sply->cpcap, req_async); + if (!ret) + sply->async_req_pending = 1; + } else { + ret = -EAGAIN; + } + mutex_unlock(&sply->lock); + + break; + + case CPCAP_IOCTL_BATT_ATOD_SYNC: + if (copy_from_user((void *)&req_us, (void *)arg, + sizeof(struct cpcap_adc_us_request))) + return -EFAULT; + + req.format = req_us.format; + req.timing = req_us.timing; + req.type = req_us.type; + + ret = cpcap_adc_sync_read(sply->cpcap, &req); + + if (ret) + return ret; + + req_us.status = req.status; + for (i = 0; i < CPCAP_ADC_BANK0_NUM; i++) + req_us.result[i] = req.result[i]; + + if (copy_to_user((void *)arg, (void *)&req_us, + sizeof(struct cpcap_adc_us_request))) + return -EFAULT; + break; + + case CPCAP_IOCTL_BATT_ATOD_READ: + req_us.format = req_async->format; + req_us.timing = req_async->timing; + req_us.type = req_async->type; + req_us.status = req_async->status; + for (i = 0; i < CPCAP_ADC_BANK0_NUM; i++) + req_us.result[i] = req_async->result[i]; + + if (copy_to_user((void *)arg, (void *)&req_us, + sizeof(struct cpcap_adc_us_request))) + return -EFAULT; + break; + + default: + return -ENOTTY; + break; + } + + return ret; +} + +static int cpcap_batt_ac_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + int ret = 0; + struct cpcap_batt_ps *sply = container_of(psy, struct cpcap_batt_ps, + ac); + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + val->intval = sply->ac_state.online; + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static char *cpcap_batt_usb_models[] = { + "none", "usb", "factory" +}; + +static int cpcap_batt_usb_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + int ret = 0; + struct cpcap_batt_ps *sply = container_of(psy, struct cpcap_batt_ps, + usb); + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + val->intval = sply->usb_state.online; + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + val->intval = sply->usb_state.current_now; + break; + case POWER_SUPPLY_PROP_MODEL_NAME: + val->strval = cpcap_batt_usb_models[sply->usb_state.model]; + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int cpcap_batt_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + int ret = 0; + struct cpcap_batt_ps *sply = container_of(psy, struct cpcap_batt_ps, + batt); + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + val->intval = sply->batt_state.status; + break; + + case POWER_SUPPLY_PROP_HEALTH: + val->intval = sply->batt_state.health; + break; + + case POWER_SUPPLY_PROP_PRESENT: + val->intval = sply->batt_state.present; + break; + + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = POWER_SUPPLY_TECHNOLOGY_LION; + break; + + case POWER_SUPPLY_PROP_CAPACITY: + val->intval = sply->batt_state.capacity; + break; + + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = sply->batt_state.batt_volt; + break; + + case POWER_SUPPLY_PROP_TEMP: + val->intval = sply->batt_state.batt_temp; + break; + + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + val->intval = sply->batt_state.batt_full_capacity; + break; + + case POWER_SUPPLY_PROP_CHARGE_COUNTER: + val->intval = sply->batt_state.batt_capacity_one; + break; + + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int cpcap_batt_probe(struct platform_device *pdev) +{ + int ret = 0; + struct cpcap_batt_ps *sply; + + if (pdev->dev.platform_data == NULL) { + dev_err(&pdev->dev, "no platform_data\n"); + ret = -EINVAL; + goto prb_exit; + } + + sply = kzalloc(sizeof(struct cpcap_batt_ps), GFP_KERNEL); + if (sply == NULL) { + ret = -ENOMEM; + goto prb_exit; + } + + sply->cpcap = pdev->dev.platform_data; + mutex_init(&sply->lock); + init_waitqueue_head(&sply->wait); + + sply->batt_state.status = POWER_SUPPLY_STATUS_UNKNOWN; + sply->batt_state.health = POWER_SUPPLY_HEALTH_GOOD; + sply->batt_state.present = 1; + sply->batt_state.capacity = 100; /* Percentage */ + sply->batt_state.batt_volt = 4200000; /* uV */ + sply->batt_state.batt_temp = 230; /* tenths of degrees Celsius */ + sply->batt_state.batt_full_capacity = 0; + sply->batt_state.batt_capacity_one = 100; + + sply->ac_state.online = 0; + + sply->usb_state.online = 0; + sply->usb_state.current_now = 0; + sply->usb_state.model = CPCAP_BATT_USB_MODEL_NONE; + + sply->batt.properties = cpcap_batt_props; + sply->batt.num_properties = ARRAY_SIZE(cpcap_batt_props); + sply->batt.get_property = cpcap_batt_get_property; + sply->batt.name = "battery"; + sply->batt.type = POWER_SUPPLY_TYPE_BATTERY; + + sply->ac.properties = cpcap_batt_ac_props; + sply->ac.num_properties = ARRAY_SIZE(cpcap_batt_ac_props); + sply->ac.get_property = cpcap_batt_ac_get_property; + sply->ac.name = "ac"; + sply->ac.type = POWER_SUPPLY_TYPE_MAINS; + + sply->usb.properties = cpcap_batt_usb_props; + sply->usb.num_properties = ARRAY_SIZE(cpcap_batt_usb_props); + sply->usb.get_property = cpcap_batt_usb_get_property; + sply->usb.name = "usb"; + sply->usb.type = POWER_SUPPLY_TYPE_USB; + + sply->no_update = false; + + ret = power_supply_register(&pdev->dev, &sply->ac); + if (ret) + goto prb_exit; + ret = power_supply_register(&pdev->dev, &sply->batt); + if (ret) + goto unregac_exit; + ret = power_supply_register(&pdev->dev, &sply->usb); + if (ret) + goto unregbatt_exit; + platform_set_drvdata(pdev, sply); + sply->cpcap->battdata = sply; + cpcap_batt_sply = sply; + + ret = misc_register(&batt_dev); + if (ret) + goto unregusb_exit; + + ret = cpcap_irq_register(sply->cpcap, CPCAP_IRQ_VBUSOV, + cpcap_batt_irq_hdlr, sply); + if (ret) + goto unregmisc_exit; + ret = cpcap_irq_register(sply->cpcap, CPCAP_IRQ_BATTDETB, + cpcap_batt_irq_hdlr, sply); + if (ret) + goto unregirq_exit; + ret = cpcap_irq_register(sply->cpcap, CPCAP_IRQ_CC_CAL, + cpcap_batt_irq_hdlr, sply); + if (ret) + goto unregirq_exit; + + ret = cpcap_irq_register(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_7, + cpcap_batt_irq_hdlr, sply); + cpcap_irq_mask(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_7); + + if (ret) + goto unregirq_exit; + + ret = cpcap_irq_register(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_8, + cpcap_batt_irq_hdlr, sply); + cpcap_irq_mask(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_8); + + if (ret) + goto unregirq_exit; + + ret = cpcap_irq_register(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_9, + cpcap_batt_irq_hdlr, sply); + cpcap_irq_mask(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_9); + + if (ret) + goto unregirq_exit; + + ret = cpcap_irq_register(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_10, + cpcap_batt_irq_hdlr, sply); + cpcap_irq_mask(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_10); + + if (ret) + goto unregirq_exit; + + ret = cpcap_irq_register(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_11, + cpcap_batt_irq_hdlr, sply); + cpcap_irq_mask(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_11); + + if (ret) + goto unregirq_exit; + + goto prb_exit; + +unregirq_exit: + cpcap_irq_free(sply->cpcap, CPCAP_IRQ_VBUSOV); + cpcap_irq_free(sply->cpcap, CPCAP_IRQ_BATTDETB); + cpcap_irq_free(sply->cpcap, CPCAP_IRQ_CC_CAL); + cpcap_irq_free(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_7); + cpcap_irq_free(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_8); + cpcap_irq_free(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_9); + cpcap_irq_free(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_10); + cpcap_irq_free(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_11); +unregmisc_exit: + misc_deregister(&batt_dev); +unregusb_exit: + power_supply_unregister(&sply->usb); +unregbatt_exit: + power_supply_unregister(&sply->batt); +unregac_exit: + power_supply_unregister(&sply->ac); + +prb_exit: + return ret; +} + +static int cpcap_batt_remove(struct platform_device *pdev) +{ + struct cpcap_batt_ps *sply = platform_get_drvdata(pdev); + + power_supply_unregister(&sply->batt); + power_supply_unregister(&sply->ac); + power_supply_unregister(&sply->usb); + misc_deregister(&batt_dev); + cpcap_irq_free(sply->cpcap, CPCAP_IRQ_VBUSOV); + cpcap_irq_free(sply->cpcap, CPCAP_IRQ_BATTDETB); + cpcap_irq_free(sply->cpcap, CPCAP_IRQ_CC_CAL); + cpcap_irq_free(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_7); + cpcap_irq_free(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_8); + cpcap_irq_free(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_9); + cpcap_irq_free(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_10); + cpcap_irq_free(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_11); + sply->cpcap->battdata = NULL; + kfree(sply); + + return 0; +} + +static int cpcap_batt_resume(struct platform_device *pdev) +{ + struct cpcap_batt_ps *sply = platform_get_drvdata(pdev); + unsigned long cur_time; + unsigned long long temp; + + temp = sched_clock(); + do_div(temp, NSEC_PER_SEC); + cur_time = ((unsigned long)temp); + if ((cur_time - sply->last_run_time) < 0) + sply->last_run_time = 0; + + if ((cur_time - sply->last_run_time) > 50) { + mutex_lock(&sply->lock); + sply->data_pending = 1; + sply->irq_status |= CPCAP_BATT_IRQ_MACRO; + + mutex_unlock(&sply->lock); + + wake_up_interruptible(&sply->wait); + } + + return 0; +} + +void cpcap_batt_set_ac_prop(struct cpcap_device *cpcap, int online) +{ + struct cpcap_batt_ps *sply = cpcap->battdata; + struct spi_device *spi = cpcap->spi; + struct cpcap_platform_data *data = spi->controller_data; + + if (sply != NULL) { + sply->ac_state.online = online; + power_supply_changed(&sply->ac); + + if (data->ac_changed) + data->ac_changed(&sply->ac, &sply->ac_state); + } +} +EXPORT_SYMBOL(cpcap_batt_set_ac_prop); + +void cpcap_batt_set_usb_prop_online(struct cpcap_device *cpcap, int online, + enum cpcap_batt_usb_model model) +{ + struct cpcap_batt_ps *sply = cpcap->battdata; + struct spi_device *spi = cpcap->spi; + struct cpcap_platform_data *data = spi->controller_data; + + if (sply != NULL) { + sply->usb_state.online = online; + sply->usb_state.model = model; + power_supply_changed(&sply->usb); + + if (data->usb_changed) + data->usb_changed(&sply->usb, &sply->usb_state); + } +} +EXPORT_SYMBOL(cpcap_batt_set_usb_prop_online); + +void cpcap_batt_set_usb_prop_curr(struct cpcap_device *cpcap, unsigned int curr) +{ + struct cpcap_batt_ps *sply = cpcap->battdata; + struct spi_device *spi = cpcap->spi; + struct cpcap_platform_data *data = spi->controller_data; + + if (sply != NULL) { + sply->usb_state.current_now = curr; + power_supply_changed(&sply->usb); + + if (data->usb_changed) + data->usb_changed(&sply->usb, &sply->usb_state); + } +} +EXPORT_SYMBOL(cpcap_batt_set_usb_prop_curr); + +/* + * Debugfs interface to test how system works with different values of + * the battery properties. Once the propety value is set through the + * debugfs, updtes from the drivers will be discarded. + */ +#ifdef CONFIG_DEBUG_FS + +static int cpcap_batt_debug_set(void *prop, u64 val) +{ + int data = (int)val; + enum power_supply_property psp = (enum power_supply_property)prop; + struct cpcap_batt_ps *sply = cpcap_batt_sply; + bool changed = true; + sply->no_update = true; + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + sply->batt_state.status = data; + break; + + case POWER_SUPPLY_PROP_HEALTH: + sply->batt_state.health = data; + break; + + case POWER_SUPPLY_PROP_PRESENT: + sply->batt_state.present = data; + break; + + case POWER_SUPPLY_PROP_CAPACITY: + sply->batt_state.capacity = data; + break; + + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + sply->batt_state.batt_volt = data; + break; + + case POWER_SUPPLY_PROP_TEMP: + sply->batt_state.batt_temp = data; + break; + + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + sply->batt_state.batt_full_capacity = data; + break; + + case POWER_SUPPLY_PROP_CHARGE_COUNTER: + sply->batt_state.batt_capacity_one = data; + break; + + default: + changed = false; + break; + } + + if (changed) + power_supply_changed(&sply->batt); + + return 0; +} + +static int cpcap_batt_debug_get(void *prop, u64 *val) +{ + enum power_supply_property psp = (enum power_supply_property)prop; + struct cpcap_batt_ps *sply = cpcap_batt_sply; + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + *val = sply->batt_state.status; + break; + + case POWER_SUPPLY_PROP_HEALTH: + *val = sply->batt_state.health; + break; + + case POWER_SUPPLY_PROP_PRESENT: + *val = sply->batt_state.present; + break; + + case POWER_SUPPLY_PROP_CAPACITY: + *val = sply->batt_state.capacity; + break; + + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + *val = sply->batt_state.batt_volt; + break; + + case POWER_SUPPLY_PROP_TEMP: + *val = sply->batt_state.batt_temp; + break; + + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + *val = sply->batt_state.batt_full_capacity; + break; + + case POWER_SUPPLY_PROP_CHARGE_COUNTER: + *val = sply->batt_state.batt_capacity_one; + break; + + default: + break; + } + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(cpcap_battery_fops, cpcap_batt_debug_get, + cpcap_batt_debug_set, "%llu\n"); + +static int __init cpcap_batt_debug_init(void) +{ + struct dentry *dent = debugfs_create_dir("battery", 0); + int ret = 0; + + if (!IS_ERR(dent)) { + debugfs_create_file("status", 0666, dent, + (void *)POWER_SUPPLY_PROP_STATUS, &cpcap_battery_fops); + debugfs_create_file("health", 0666, dent, + (void *)POWER_SUPPLY_PROP_HEALTH, &cpcap_battery_fops); + debugfs_create_file("present", 0666, dent, + (void *)POWER_SUPPLY_PROP_PRESENT, &cpcap_battery_fops); + debugfs_create_file("voltage", 0666, dent, + (void *)POWER_SUPPLY_PROP_VOLTAGE_NOW, &cpcap_battery_fops); + debugfs_create_file("capacity", 0666, dent, + (void *)POWER_SUPPLY_PROP_CAPACITY, &cpcap_battery_fops); + debugfs_create_file("temp", 0666, dent, + (void *)POWER_SUPPLY_PROP_TEMP, &cpcap_battery_fops); + debugfs_create_file("charge_full_design", 0666, dent, + (void *)POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + &cpcap_battery_fops); + debugfs_create_file("charge_counter", 0666, dent, + (void *)POWER_SUPPLY_PROP_CHARGE_COUNTER, + &cpcap_battery_fops); + } else { + ret = PTR_ERR(dent); + } + + return ret; +} + +late_initcall(cpcap_batt_debug_init); + +#endif /* CONFIG_DEBUG_FS */ + +static int __init cpcap_batt_init(void) +{ + return platform_driver_register(&cpcap_batt_driver); +} +subsys_initcall(cpcap_batt_init); + +static void __exit cpcap_batt_exit(void) +{ + platform_driver_unregister(&cpcap_batt_driver); +} +module_exit(cpcap_batt_exit); + +MODULE_ALIAS("platform:cpcap_batt"); +MODULE_DESCRIPTION("CPCAP BATTERY driver"); +MODULE_AUTHOR("Motorola"); +MODULE_LICENSE("GPL"); |