Advertisement
Guest User

cpcap-battery.c

a guest
Feb 16th, 2011
241
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 21.09 KB | None | 0 0
  1. /*
  2.  * Copyright (C) 2007-2009 Motorola, Inc.
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License version 2 as
  6.  * published by the Free Software Foundation.
  7.  *
  8.  * This program is distributed in the hope that it will be useful,
  9.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.  * GNU General Public License for more details.
  12.  *
  13.  * You should have received a copy of the GNU General Public License
  14.  * along with this program; if not, write to the Free Software
  15.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  16.  * 02111-1307, USA
  17.  */
  18.  
  19. #include <asm/div64.h>
  20. #include <linux/device.h>
  21. #include <linux/fs.h>
  22. #include <linux/init.h>
  23. #include <linux/module.h>
  24. #include <linux/mutex.h>
  25. #include <linux/platform_device.h>
  26. #include <linux/poll.h>
  27. #include <linux/power_supply.h>
  28. #include <linux/types.h>
  29. #include <linux/sched.h>
  30. #include <linux/slab.h>
  31. #include <linux/spi/cpcap.h>
  32. #include <linux/spi/cpcap-regbits.h>
  33. #include <linux/spi/spi.h>
  34. #include <linux/time.h>
  35. #include <linux/miscdevice.h>
  36. #include <linux/debugfs.h>
  37.  
  38. #define CPCAP_BATT_IRQ_BATTDET 0x01
  39. #define CPCAP_BATT_IRQ_OV      0x02
  40. #define CPCAP_BATT_IRQ_CC_CAL  0x04
  41. #define CPCAP_BATT_IRQ_ADCDONE 0x08
  42. #define CPCAP_BATT_IRQ_MACRO   0x10
  43.  
  44. static int cpcap_batt_ioctl(struct inode *inode,
  45.                 struct file *file,
  46.                 unsigned int cmd,
  47.                 unsigned long arg);
  48. static unsigned int cpcap_batt_poll(struct file *file, poll_table *wait);
  49. static int cpcap_batt_open(struct inode *inode, struct file *file);
  50. static ssize_t cpcap_batt_read(struct file *file, char *buf, size_t count,
  51.                    loff_t *ppos);
  52. static int cpcap_batt_probe(struct platform_device *pdev);
  53. static int cpcap_batt_remove(struct platform_device *pdev);
  54. static int cpcap_batt_resume(struct platform_device *pdev);
  55.  
  56. struct cpcap_batt_ps {
  57.     struct power_supply batt;
  58.     struct power_supply ac;
  59.     struct power_supply usb;
  60.     struct cpcap_device *cpcap;
  61.     struct cpcap_batt_data batt_state;
  62.     struct cpcap_batt_ac_data ac_state;
  63.     struct cpcap_batt_usb_data usb_state;
  64.     struct cpcap_adc_request req;
  65.     struct mutex lock;
  66.     char irq_status;
  67.     char data_pending;
  68.     wait_queue_head_t wait;
  69.     char async_req_pending;
  70.     unsigned long last_run_time;
  71.     bool no_update;
  72. };
  73.  
  74. static const struct file_operations batt_fops = {
  75.     .owner = THIS_MODULE,
  76.     .open = cpcap_batt_open,
  77.     .ioctl = cpcap_batt_ioctl,
  78.     .read = cpcap_batt_read,
  79.     .poll = cpcap_batt_poll,
  80. };
  81.  
  82. static struct miscdevice batt_dev = {
  83.     .minor  = MISC_DYNAMIC_MINOR,
  84.     .name   = "cpcap_batt",
  85.     .fops   = &batt_fops,
  86. };
  87.  
  88. static enum power_supply_property cpcap_batt_props[] = {
  89.     POWER_SUPPLY_PROP_STATUS,
  90.     POWER_SUPPLY_PROP_HEALTH,
  91.     POWER_SUPPLY_PROP_PRESENT,
  92.     POWER_SUPPLY_PROP_TECHNOLOGY,
  93.     POWER_SUPPLY_PROP_CAPACITY,
  94.     POWER_SUPPLY_PROP_VOLTAGE_NOW,
  95.     POWER_SUPPLY_PROP_TEMP,
  96.     POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
  97.     POWER_SUPPLY_PROP_CHARGE_COUNTER
  98. };
  99.  
  100. static enum power_supply_property cpcap_batt_ac_props[] =
  101. {
  102.     POWER_SUPPLY_PROP_ONLINE
  103. };
  104.  
  105. static enum power_supply_property cpcap_batt_usb_props[] =
  106. {
  107.     POWER_SUPPLY_PROP_ONLINE,
  108.     POWER_SUPPLY_PROP_CURRENT_NOW,
  109.     POWER_SUPPLY_PROP_MODEL_NAME
  110. };
  111.  
  112. static struct platform_driver cpcap_batt_driver = {
  113.     .probe      = cpcap_batt_probe,
  114.     .remove     = cpcap_batt_remove,
  115.     .resume     = cpcap_batt_resume,
  116.     .driver     = {
  117.         .name   = "cpcap_battery",
  118.         .owner  = THIS_MODULE,
  119.     },
  120. };
  121.  
  122. static struct cpcap_batt_ps *cpcap_batt_sply;
  123.  
  124. void cpcap_batt_irq_hdlr(enum cpcap_irqs irq, void *data)
  125. {
  126.     struct cpcap_batt_ps *sply = data;
  127.  
  128.     mutex_lock(&sply->lock);
  129.     sply->data_pending = 1;
  130.  
  131.     switch (irq) {
  132.     case CPCAP_IRQ_BATTDETB:
  133.         sply->irq_status |= CPCAP_BATT_IRQ_BATTDET;
  134.         cpcap_irq_unmask(sply->cpcap, irq);
  135.         break;
  136.  
  137.     case CPCAP_IRQ_VBUSOV:
  138.         sply->irq_status |=  CPCAP_BATT_IRQ_OV;
  139.         cpcap_irq_unmask(sply->cpcap, irq);
  140.         break;
  141.  
  142.     case CPCAP_IRQ_CC_CAL:
  143.         sply->irq_status |= CPCAP_BATT_IRQ_CC_CAL;
  144.         cpcap_irq_unmask(sply->cpcap, irq);
  145.         break;
  146.  
  147.     case CPCAP_IRQ_UC_PRIMACRO_7:
  148.     case CPCAP_IRQ_UC_PRIMACRO_8:
  149.     case CPCAP_IRQ_UC_PRIMACRO_9:
  150.     case CPCAP_IRQ_UC_PRIMACRO_10:
  151.     case CPCAP_IRQ_UC_PRIMACRO_11:
  152.         sply->irq_status |= CPCAP_BATT_IRQ_MACRO;
  153.         break;
  154.     default:
  155.         break;
  156.     }
  157.  
  158.     mutex_unlock(&sply->lock);
  159.  
  160.     wake_up_interruptible(&sply->wait);
  161. }
  162.  
  163. void cpcap_batt_adc_hdlr(struct cpcap_device *cpcap, void *data)
  164. {
  165.     struct cpcap_batt_ps *sply = data;
  166.     mutex_lock(&sply->lock);
  167.  
  168.     sply->async_req_pending = 0;
  169.  
  170.     sply->data_pending = 1;
  171.  
  172.     sply->irq_status |= CPCAP_BATT_IRQ_ADCDONE;
  173.  
  174.     mutex_unlock(&sply->lock);
  175.  
  176.     wake_up_interruptible(&sply->wait);
  177. }
  178.  
  179. static int cpcap_batt_open(struct inode *inode, struct file *file)
  180. {
  181.     file->private_data = cpcap_batt_sply;
  182.     return 0;
  183. }
  184.  
  185. static unsigned int cpcap_batt_poll(struct file *file, poll_table *wait)
  186. {
  187.     struct cpcap_batt_ps *sply = file->private_data;
  188.     unsigned int ret = 0;
  189.  
  190.     poll_wait(file, &sply->wait, wait);
  191.  
  192.     if (sply->data_pending)
  193.         ret = (POLLIN | POLLRDNORM);
  194.  
  195.     return ret;
  196. }
  197.  
  198. static ssize_t cpcap_batt_read(struct file *file,
  199.                    char *buf, size_t count, loff_t *ppos)
  200. {
  201.     struct cpcap_batt_ps *sply = file->private_data;
  202.     int ret = -EFBIG;
  203.     unsigned long long temp;
  204.  
  205.     if (count >= sizeof(char)) {
  206.         mutex_lock(&sply->lock);
  207.         if (!copy_to_user((void *)buf, (void *)&sply->irq_status,
  208.                   sizeof(sply->irq_status)))
  209.             ret = sizeof(sply->irq_status);
  210.         else
  211.             ret = -EFAULT;
  212.         sply->data_pending = 0;
  213.         temp = sched_clock();
  214.         do_div(temp, NSEC_PER_SEC);
  215.         sply->last_run_time = (unsigned long)temp;
  216.  
  217.         sply->irq_status = 0;
  218.         mutex_unlock(&sply->lock);
  219.     }
  220.  
  221.     return ret;
  222. }
  223.  
  224. static int cpcap_batt_ioctl(struct inode *inode,
  225.                 struct file *file,
  226.                 unsigned int cmd,
  227.                 unsigned long arg)
  228. {
  229.     int ret = 0;
  230.     int i;
  231.     struct cpcap_batt_ps *sply = file->private_data;
  232.     struct cpcap_adc_request *req_async = &sply->req;
  233.     struct cpcap_adc_request req;
  234.     struct cpcap_adc_us_request req_us;
  235.     struct spi_device *spi = sply->cpcap->spi;
  236.     struct cpcap_platform_data *data = spi->controller_data;
  237.  
  238.     switch (cmd) {
  239.     case CPCAP_IOCTL_BATT_DISPLAY_UPDATE:
  240.         if (sply->no_update)
  241.             return 0;
  242.         if (copy_from_user((void *)&sply->batt_state,
  243.                    (void *)arg, sizeof(struct cpcap_batt_data)))
  244.             return -EFAULT;
  245.         power_supply_changed(&sply->batt);
  246.  
  247.         if (data->batt_changed)
  248.             data->batt_changed(&sply->batt, &sply->batt_state);
  249.         break;
  250.  
  251.     case CPCAP_IOCTL_BATT_ATOD_ASYNC:
  252.         mutex_lock(&sply->lock);
  253.         if (!sply->async_req_pending) {
  254.             if (copy_from_user((void *)&req_us, (void *)arg,
  255.                        sizeof(struct cpcap_adc_us_request)
  256.                        )) {
  257.                 mutex_unlock(&sply->lock);
  258.                 return -EFAULT;
  259.             }
  260.  
  261.             req_async->format = req_us.format;
  262.             req_async->timing = req_us.timing;
  263.             req_async->type = req_us.type;
  264.             req_async->callback = cpcap_batt_adc_hdlr;
  265.             req_async->callback_param = sply;
  266.  
  267.             ret = cpcap_adc_async_read(sply->cpcap, req_async);
  268.             if (!ret)
  269.                 sply->async_req_pending = 1;
  270.         } else {
  271.             ret = -EAGAIN;
  272.         }
  273.         mutex_unlock(&sply->lock);
  274.  
  275.         break;
  276.  
  277.     case CPCAP_IOCTL_BATT_ATOD_SYNC:
  278.         if (copy_from_user((void *)&req_us, (void *)arg,
  279.                    sizeof(struct cpcap_adc_us_request)))
  280.             return -EFAULT;
  281.  
  282.         req.format = req_us.format;
  283.         req.timing = req_us.timing;
  284.         req.type = req_us.type;
  285.  
  286.         ret = cpcap_adc_sync_read(sply->cpcap, &req);
  287.  
  288.         if (ret)
  289.             return ret;
  290.  
  291.         req_us.status = req.status;
  292.         for (i = 0; i < CPCAP_ADC_BANK0_NUM; i++)
  293.             req_us.result[i] = req.result[i];
  294.  
  295.         if (copy_to_user((void *)arg, (void *)&req_us,
  296.                  sizeof(struct cpcap_adc_us_request)))
  297.             return -EFAULT;
  298.         break;
  299.  
  300.     case CPCAP_IOCTL_BATT_ATOD_READ:
  301.         req_us.format = req_async->format;
  302.         req_us.timing = req_async->timing;
  303.         req_us.type = req_async->type;
  304.         req_us.status = req_async->status;
  305.         for (i = 0; i < CPCAP_ADC_BANK0_NUM; i++)
  306.             req_us.result[i] = req_async->result[i];
  307.  
  308.         if (copy_to_user((void *)arg, (void *)&req_us,
  309.                  sizeof(struct cpcap_adc_us_request)))
  310.             return -EFAULT;
  311.         break;
  312.  
  313.     default:
  314.         return -ENOTTY;
  315.         break;
  316.     }
  317.  
  318.     return ret;
  319. }
  320.  
  321. static int cpcap_batt_ac_get_property(struct power_supply *psy,
  322.                       enum power_supply_property psp,
  323.                       union power_supply_propval *val)
  324. {
  325.     int ret = 0;
  326.     struct cpcap_batt_ps *sply = container_of(psy, struct cpcap_batt_ps,
  327.                          ac);
  328.  
  329.     switch (psp) {
  330.     case POWER_SUPPLY_PROP_ONLINE:
  331.         val->intval = sply->ac_state.online;
  332.         break;
  333.     default:
  334.         ret = -EINVAL;
  335.         break;
  336.     }
  337.  
  338.     return ret;
  339. }
  340.  
  341. static char *cpcap_batt_usb_models[] = {
  342.     "none", "usb", "factory"
  343. };
  344.  
  345. static int cpcap_batt_usb_get_property(struct power_supply *psy,
  346.                        enum power_supply_property psp,
  347.                        union power_supply_propval *val)
  348. {
  349.     int ret = 0;
  350.     struct cpcap_batt_ps *sply = container_of(psy, struct cpcap_batt_ps,
  351.                          usb);
  352.  
  353.     switch (psp) {
  354.     case POWER_SUPPLY_PROP_ONLINE:
  355.         val->intval = sply->usb_state.online;
  356.         break;
  357.     case POWER_SUPPLY_PROP_CURRENT_NOW:
  358.         val->intval = sply->usb_state.current_now;
  359.         break;
  360.     case POWER_SUPPLY_PROP_MODEL_NAME:
  361.         val->strval = cpcap_batt_usb_models[sply->usb_state.model];
  362.         break;
  363.     default:
  364.         ret = -EINVAL;
  365.         break;
  366.     }
  367.  
  368.     return ret;
  369. }
  370.  
  371. static int cpcap_batt_get_property(struct power_supply *psy,
  372.                    enum power_supply_property psp,
  373.                    union power_supply_propval *val)
  374. {
  375.     int ret = 0;
  376.     struct cpcap_batt_ps *sply = container_of(psy, struct cpcap_batt_ps,
  377.                           batt);
  378.  
  379.     switch (psp) {
  380.     case POWER_SUPPLY_PROP_STATUS:
  381.         val->intval = sply->batt_state.status;
  382.         break;
  383.  
  384.     case POWER_SUPPLY_PROP_HEALTH:
  385.         val->intval = sply->batt_state.health;
  386.         break;
  387.  
  388.     case POWER_SUPPLY_PROP_PRESENT:
  389.         val->intval = sply->batt_state.present;
  390.         break;
  391.  
  392.     case POWER_SUPPLY_PROP_TECHNOLOGY:
  393.         val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
  394.         break;
  395.  
  396.     case POWER_SUPPLY_PROP_CAPACITY:
  397.         val->intval = sply->batt_state.capacity;
  398.         break;
  399.  
  400.     case POWER_SUPPLY_PROP_VOLTAGE_NOW:
  401.         val->intval = sply->batt_state.batt_volt;
  402.         break;
  403.  
  404.     case POWER_SUPPLY_PROP_TEMP:
  405.         val->intval = sply->batt_state.batt_temp;
  406.         break;
  407.  
  408.     case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
  409.         val->intval = sply->batt_state.batt_full_capacity;
  410.         break;
  411.  
  412.     case POWER_SUPPLY_PROP_CHARGE_COUNTER:
  413.         val->intval = sply->batt_state.batt_capacity_one;
  414.         break;
  415.  
  416.     default:
  417.         ret = -EINVAL;
  418.         break;
  419.     }
  420.  
  421.     return ret;
  422. }
  423.  
  424. static int cpcap_batt_probe(struct platform_device *pdev)
  425. {
  426.     int ret = 0;
  427.     struct cpcap_batt_ps *sply;
  428.  
  429.     if (pdev->dev.platform_data == NULL) {
  430.         dev_err(&pdev->dev, "no platform_data\n");
  431.         ret = -EINVAL;
  432.         goto prb_exit;
  433.     }
  434.  
  435.     sply = kzalloc(sizeof(struct cpcap_batt_ps), GFP_KERNEL);
  436.     if (sply == NULL) {
  437.         ret = -ENOMEM;
  438.         goto prb_exit;
  439.     }
  440.  
  441.     sply->cpcap = pdev->dev.platform_data;
  442.     mutex_init(&sply->lock);
  443.     init_waitqueue_head(&sply->wait);
  444.  
  445.     sply->batt_state.status = POWER_SUPPLY_STATUS_UNKNOWN;
  446.     sply->batt_state.health = POWER_SUPPLY_HEALTH_GOOD;
  447.     sply->batt_state.present = 1;
  448.     sply->batt_state.capacity = 100;    /* Percentage */
  449.     sply->batt_state.batt_volt = 4200000;   /* uV */
  450.     sply->batt_state.batt_temp = 230;   /* tenths of degrees Celsius */
  451.     sply->batt_state.batt_full_capacity = 0;
  452.     sply->batt_state.batt_capacity_one = 100;
  453.  
  454.     sply->ac_state.online = 0;
  455.  
  456.     sply->usb_state.online = 0;
  457.     sply->usb_state.current_now = 0;
  458.     sply->usb_state.model = CPCAP_BATT_USB_MODEL_NONE;
  459.  
  460.     sply->batt.properties = cpcap_batt_props;
  461.     sply->batt.num_properties = ARRAY_SIZE(cpcap_batt_props);
  462.     sply->batt.get_property = cpcap_batt_get_property;
  463.     sply->batt.name = "battery";
  464.     sply->batt.type = POWER_SUPPLY_TYPE_BATTERY;
  465.  
  466.     sply->ac.properties = cpcap_batt_ac_props;
  467.     sply->ac.num_properties = ARRAY_SIZE(cpcap_batt_ac_props);
  468.     sply->ac.get_property = cpcap_batt_ac_get_property;
  469.     sply->ac.name = "ac";
  470.     sply->ac.type = POWER_SUPPLY_TYPE_MAINS;
  471.  
  472.     sply->usb.properties = cpcap_batt_usb_props;
  473.     sply->usb.num_properties = ARRAY_SIZE(cpcap_batt_usb_props);
  474.     sply->usb.get_property = cpcap_batt_usb_get_property;
  475.     sply->usb.name = "usb";
  476.     sply->usb.type = POWER_SUPPLY_TYPE_USB;
  477.  
  478.     sply->no_update = false;
  479.  
  480.     ret = power_supply_register(&pdev->dev, &sply->ac);
  481.     if (ret)
  482.         goto prb_exit;
  483.     ret = power_supply_register(&pdev->dev, &sply->batt);
  484.     if (ret)
  485.         goto unregac_exit;
  486.     ret = power_supply_register(&pdev->dev, &sply->usb);
  487.     if (ret)
  488.         goto unregbatt_exit;
  489.     platform_set_drvdata(pdev, sply);
  490.     sply->cpcap->battdata = sply;
  491.     cpcap_batt_sply = sply;
  492.  
  493.     ret = misc_register(&batt_dev);
  494.     if (ret)
  495.         goto unregusb_exit;
  496.  
  497.     ret = cpcap_irq_register(sply->cpcap, CPCAP_IRQ_VBUSOV,
  498.                  cpcap_batt_irq_hdlr, sply);
  499.     if (ret)
  500.         goto unregmisc_exit;
  501.     ret = cpcap_irq_register(sply->cpcap, CPCAP_IRQ_BATTDETB,
  502.                  cpcap_batt_irq_hdlr, sply);
  503.     if (ret)
  504.         goto unregirq_exit;
  505.     ret = cpcap_irq_register(sply->cpcap, CPCAP_IRQ_CC_CAL,
  506.                  cpcap_batt_irq_hdlr, sply);
  507.     if (ret)
  508.         goto unregirq_exit;
  509.  
  510.     ret = cpcap_irq_register(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_7,
  511.                  cpcap_batt_irq_hdlr, sply);
  512.     cpcap_irq_mask(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_7);
  513.  
  514.     if (ret)
  515.         goto unregirq_exit;
  516.  
  517.     ret = cpcap_irq_register(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_8,
  518.                  cpcap_batt_irq_hdlr, sply);
  519.     cpcap_irq_mask(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_8);
  520.  
  521.     if (ret)
  522.         goto unregirq_exit;
  523.  
  524.     ret = cpcap_irq_register(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_9,
  525.                  cpcap_batt_irq_hdlr, sply);
  526.     cpcap_irq_mask(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_9);
  527.  
  528.     if (ret)
  529.         goto unregirq_exit;
  530.  
  531.     ret = cpcap_irq_register(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_10,
  532.                  cpcap_batt_irq_hdlr, sply);
  533.     cpcap_irq_mask(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_10);
  534.  
  535.     if (ret)
  536.         goto unregirq_exit;
  537.  
  538.     ret = cpcap_irq_register(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_11,
  539.                  cpcap_batt_irq_hdlr, sply);
  540.     cpcap_irq_mask(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_11);
  541.  
  542.     if (ret)
  543.         goto unregirq_exit;
  544.  
  545.     goto prb_exit;
  546.  
  547. unregirq_exit:
  548.     cpcap_irq_free(sply->cpcap, CPCAP_IRQ_VBUSOV);
  549.     cpcap_irq_free(sply->cpcap, CPCAP_IRQ_BATTDETB);
  550.     cpcap_irq_free(sply->cpcap, CPCAP_IRQ_CC_CAL);
  551.     cpcap_irq_free(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_7);
  552.     cpcap_irq_free(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_8);
  553.     cpcap_irq_free(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_9);
  554.     cpcap_irq_free(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_10);
  555.     cpcap_irq_free(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_11);
  556. unregmisc_exit:
  557.     misc_deregister(&batt_dev);
  558. unregusb_exit:
  559.     power_supply_unregister(&sply->usb);
  560. unregbatt_exit:
  561.     power_supply_unregister(&sply->batt);
  562. unregac_exit:
  563.     power_supply_unregister(&sply->ac);
  564.  
  565. prb_exit:
  566.     return ret;
  567. }
  568.  
  569. static int cpcap_batt_remove(struct platform_device *pdev)
  570. {
  571.     struct cpcap_batt_ps *sply = platform_get_drvdata(pdev);
  572.  
  573.     power_supply_unregister(&sply->batt);
  574.     power_supply_unregister(&sply->ac);
  575.     power_supply_unregister(&sply->usb);
  576.     misc_deregister(&batt_dev);
  577.     cpcap_irq_free(sply->cpcap, CPCAP_IRQ_VBUSOV);
  578.     cpcap_irq_free(sply->cpcap, CPCAP_IRQ_BATTDETB);
  579.     cpcap_irq_free(sply->cpcap, CPCAP_IRQ_CC_CAL);
  580.     cpcap_irq_free(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_7);
  581.     cpcap_irq_free(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_8);
  582.     cpcap_irq_free(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_9);
  583.     cpcap_irq_free(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_10);
  584.     cpcap_irq_free(sply->cpcap, CPCAP_IRQ_UC_PRIMACRO_11);
  585.     sply->cpcap->battdata = NULL;
  586.     kfree(sply);
  587.  
  588.     return 0;
  589. }
  590.  
  591. static int cpcap_batt_resume(struct platform_device *pdev)
  592. {
  593.     struct cpcap_batt_ps *sply = platform_get_drvdata(pdev);
  594.     unsigned long cur_time;
  595.     unsigned long long temp;
  596.  
  597.     temp = sched_clock();
  598.     do_div(temp, NSEC_PER_SEC);
  599.     cur_time = ((unsigned long)temp);
  600.     if ((cur_time - sply->last_run_time) < 0)
  601.         sply->last_run_time = 0;
  602.  
  603.     if ((cur_time - sply->last_run_time) > 50) {
  604.         mutex_lock(&sply->lock);
  605.         sply->data_pending = 1;
  606.         sply->irq_status |= CPCAP_BATT_IRQ_MACRO;
  607.  
  608.         mutex_unlock(&sply->lock);
  609.  
  610.         wake_up_interruptible(&sply->wait);
  611.     }
  612.  
  613.     return 0;
  614. }
  615.  
  616. void cpcap_batt_set_ac_prop(struct cpcap_device *cpcap, int online)
  617. {
  618.     struct cpcap_batt_ps *sply = cpcap->battdata;
  619.     struct spi_device *spi = cpcap->spi;
  620.     struct cpcap_platform_data *data = spi->controller_data;
  621.  
  622.     if (sply != NULL) {
  623.         sply->ac_state.online = online;
  624.         power_supply_changed(&sply->ac);
  625.  
  626.         if (data->ac_changed)
  627.             data->ac_changed(&sply->ac, &sply->ac_state);
  628.     }
  629. }
  630. EXPORT_SYMBOL(cpcap_batt_set_ac_prop);
  631.  
  632. void cpcap_batt_set_usb_prop_online(struct cpcap_device *cpcap, int online,
  633.                     enum cpcap_batt_usb_model model)
  634. {
  635.     struct cpcap_batt_ps *sply = cpcap->battdata;
  636.     struct spi_device *spi = cpcap->spi;
  637.     struct cpcap_platform_data *data = spi->controller_data;
  638.  
  639.     if (sply != NULL) {
  640.         sply->usb_state.online = online;
  641.         sply->usb_state.model = model;
  642.         power_supply_changed(&sply->usb);
  643.  
  644.         if (data->usb_changed)
  645.             data->usb_changed(&sply->usb, &sply->usb_state);
  646.     }
  647. }
  648. EXPORT_SYMBOL(cpcap_batt_set_usb_prop_online);
  649.  
  650. void cpcap_batt_set_usb_prop_curr(struct cpcap_device *cpcap, unsigned int curr)
  651. {
  652.     struct cpcap_batt_ps *sply = cpcap->battdata;
  653.     struct spi_device *spi = cpcap->spi;
  654.     struct cpcap_platform_data *data = spi->controller_data;
  655.  
  656.     if (sply != NULL) {
  657.         sply->usb_state.current_now = curr;
  658.         power_supply_changed(&sply->usb);
  659.  
  660.         if (data->usb_changed)
  661.             data->usb_changed(&sply->usb, &sply->usb_state);
  662.     }
  663. }
  664. EXPORT_SYMBOL(cpcap_batt_set_usb_prop_curr);
  665.  
  666. /*
  667.  * Debugfs interface to test how system works with different values of
  668.  * the battery properties. Once the propety value is set through the
  669.  * debugfs, updtes from the drivers will be discarded.
  670.  */
  671. #ifdef CONFIG_DEBUG_FS
  672.  
  673. static int cpcap_batt_debug_set(void *prop, u64 val)
  674. {
  675.     int data = (int)val;
  676.     enum power_supply_property psp = (enum power_supply_property)prop;
  677.     struct cpcap_batt_ps *sply = cpcap_batt_sply;
  678.     bool changed = true;
  679.     sply->no_update = true;
  680.  
  681.     switch (psp) {
  682.     case POWER_SUPPLY_PROP_STATUS:
  683.         sply->batt_state.status = data;
  684.         break;
  685.  
  686.     case POWER_SUPPLY_PROP_HEALTH:
  687.         sply->batt_state.health = data;
  688.         break;
  689.  
  690.     case POWER_SUPPLY_PROP_PRESENT:
  691.         sply->batt_state.present = data;
  692.         break;
  693.  
  694.     case POWER_SUPPLY_PROP_CAPACITY:
  695.         sply->batt_state.capacity = data;
  696.         break;
  697.  
  698.     case POWER_SUPPLY_PROP_VOLTAGE_NOW:
  699.         sply->batt_state.batt_volt = data;
  700.         break;
  701.  
  702.     case POWER_SUPPLY_PROP_TEMP:
  703.         sply->batt_state.batt_temp = data;
  704.         break;
  705.  
  706.     case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
  707.         sply->batt_state.batt_full_capacity = data;
  708.         break;
  709.  
  710.     case POWER_SUPPLY_PROP_CHARGE_COUNTER:
  711.         sply->batt_state.batt_capacity_one = data;
  712.         break;
  713.  
  714.     default:
  715.         changed = false;
  716.         break;
  717.     }
  718.  
  719.     if (changed)
  720.         power_supply_changed(&sply->batt);
  721.  
  722.     return 0;
  723. }
  724.  
  725. static int cpcap_batt_debug_get(void *prop, u64 *val)
  726. {
  727.     enum power_supply_property psp = (enum power_supply_property)prop;
  728.     struct cpcap_batt_ps *sply = cpcap_batt_sply;
  729.  
  730.     switch (psp) {
  731.     case POWER_SUPPLY_PROP_STATUS:
  732.         *val = sply->batt_state.status;
  733.         break;
  734.  
  735.     case POWER_SUPPLY_PROP_HEALTH:
  736.         *val = sply->batt_state.health;
  737.         break;
  738.  
  739.     case POWER_SUPPLY_PROP_PRESENT:
  740.         *val = sply->batt_state.present;
  741.         break;
  742.  
  743.     case POWER_SUPPLY_PROP_CAPACITY:
  744.         *val = sply->batt_state.capacity;
  745.         break;
  746.  
  747.     case POWER_SUPPLY_PROP_VOLTAGE_NOW:
  748.         *val = sply->batt_state.batt_volt;
  749.         break;
  750.  
  751.     case POWER_SUPPLY_PROP_TEMP:
  752.         *val = sply->batt_state.batt_temp;
  753.         break;
  754.  
  755.     case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
  756.         *val = sply->batt_state.batt_full_capacity;
  757.         break;
  758.  
  759.     case POWER_SUPPLY_PROP_CHARGE_COUNTER:
  760.         *val = sply->batt_state.batt_capacity_one;
  761.         break;
  762.  
  763.     default:
  764.         break;
  765.     }
  766.  
  767.     return 0;
  768. }
  769.  
  770. DEFINE_SIMPLE_ATTRIBUTE(cpcap_battery_fops, cpcap_batt_debug_get,
  771.             cpcap_batt_debug_set, "%llu\n");
  772.  
  773. static int __init cpcap_batt_debug_init(void)
  774. {
  775.     struct dentry *dent = debugfs_create_dir("battery", 0);
  776.     int            ret  = 0;
  777.  
  778.     if (!IS_ERR(dent)) {
  779.         debugfs_create_file("status", 0666, dent,
  780.           (void *)POWER_SUPPLY_PROP_STATUS, &cpcap_battery_fops);
  781.         debugfs_create_file("health", 0666, dent,
  782.           (void *)POWER_SUPPLY_PROP_HEALTH, &cpcap_battery_fops);
  783.         debugfs_create_file("present", 0666, dent,
  784.           (void *)POWER_SUPPLY_PROP_PRESENT, &cpcap_battery_fops);
  785.         debugfs_create_file("voltage", 0666, dent,
  786.           (void *)POWER_SUPPLY_PROP_VOLTAGE_NOW, &cpcap_battery_fops);
  787.         debugfs_create_file("capacity", 0666, dent,
  788.           (void *)POWER_SUPPLY_PROP_CAPACITY, &cpcap_battery_fops);
  789.         debugfs_create_file("temp", 0666, dent,
  790.           (void *)POWER_SUPPLY_PROP_TEMP, &cpcap_battery_fops);
  791.         debugfs_create_file("charge_full_design", 0666, dent,
  792.           (void *)POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
  793.           &cpcap_battery_fops);
  794.         debugfs_create_file("charge_counter", 0666, dent,
  795.           (void *)POWER_SUPPLY_PROP_CHARGE_COUNTER,
  796.           &cpcap_battery_fops);
  797.     } else {
  798.         ret = PTR_ERR(dent);
  799.     }
  800.  
  801.     return ret;
  802. }
  803.  
  804. late_initcall(cpcap_batt_debug_init);
  805.  
  806. #endif /* CONFIG_DEBUG_FS */
  807.  
  808. static int __init cpcap_batt_init(void)
  809. {
  810.     return platform_driver_register(&cpcap_batt_driver);
  811. }
  812. subsys_initcall(cpcap_batt_init);
  813.  
  814. static void __exit cpcap_batt_exit(void)
  815. {
  816.     platform_driver_unregister(&cpcap_batt_driver);
  817. }
  818. module_exit(cpcap_batt_exit);
  819.  
  820. MODULE_ALIAS("platform:cpcap_batt");
  821. MODULE_DESCRIPTION("CPCAP BATTERY driver");
  822. MODULE_AUTHOR("Motorola");
  823. MODULE_LICENSE("GPL");
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement