hp6xx_apm.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * bios-less APM driver for hp680
  4. *
  5. * Copyright 2005 (c) Andriy Skulysh <[email protected]>
  6. * Copyright 2008 (c) Kristoffer Ericson <[email protected]>
  7. */
  8. #include <linux/module.h>
  9. #include <linux/kernel.h>
  10. #include <linux/init.h>
  11. #include <linux/interrupt.h>
  12. #include <linux/apm-emulation.h>
  13. #include <linux/io.h>
  14. #include <asm/adc.h>
  15. #include <mach/hp6xx.h>
  16. /* percentage values */
  17. #define APM_CRITICAL 10
  18. #define APM_LOW 30
  19. /* resonably sane values */
  20. #define HP680_BATTERY_MAX 898
  21. #define HP680_BATTERY_MIN 486
  22. #define HP680_BATTERY_AC_ON 1023
  23. #define MODNAME "hp6x0_apm"
  24. #define PGDR 0xa400012c
  25. static void hp6x0_apm_get_power_status(struct apm_power_info *info)
  26. {
  27. int battery, backup, charging, percentage;
  28. u8 pgdr;
  29. battery = adc_single(ADC_CHANNEL_BATTERY);
  30. backup = adc_single(ADC_CHANNEL_BACKUP);
  31. charging = adc_single(ADC_CHANNEL_CHARGE);
  32. percentage = 100 * (battery - HP680_BATTERY_MIN) /
  33. (HP680_BATTERY_MAX - HP680_BATTERY_MIN);
  34. /* % of full battery */
  35. info->battery_life = percentage;
  36. /* We want our estimates in minutes */
  37. info->units = 0;
  38. /* Extremely(!!) rough estimate, we will replace this with a datalist later on */
  39. info->time = (2 * battery);
  40. info->ac_line_status = (battery > HP680_BATTERY_AC_ON) ?
  41. APM_AC_ONLINE : APM_AC_OFFLINE;
  42. pgdr = __raw_readb(PGDR);
  43. if (pgdr & PGDR_MAIN_BATTERY_OUT) {
  44. info->battery_status = APM_BATTERY_STATUS_NOT_PRESENT;
  45. info->battery_flag = 0x80;
  46. } else if (charging < 8) {
  47. info->battery_status = APM_BATTERY_STATUS_CHARGING;
  48. info->battery_flag = 0x08;
  49. info->ac_line_status = 0x01;
  50. } else if (percentage <= APM_CRITICAL) {
  51. info->battery_status = APM_BATTERY_STATUS_CRITICAL;
  52. info->battery_flag = 0x04;
  53. } else if (percentage <= APM_LOW) {
  54. info->battery_status = APM_BATTERY_STATUS_LOW;
  55. info->battery_flag = 0x02;
  56. } else {
  57. info->battery_status = APM_BATTERY_STATUS_HIGH;
  58. info->battery_flag = 0x01;
  59. }
  60. }
  61. static irqreturn_t hp6x0_apm_interrupt(int irq, void *dev)
  62. {
  63. if (!APM_DISABLED)
  64. apm_queue_event(APM_USER_SUSPEND);
  65. return IRQ_HANDLED;
  66. }
  67. static int __init hp6x0_apm_init(void)
  68. {
  69. int ret;
  70. ret = request_irq(HP680_BTN_IRQ, hp6x0_apm_interrupt,
  71. 0, MODNAME, NULL);
  72. if (unlikely(ret < 0)) {
  73. printk(KERN_ERR MODNAME ": IRQ %d request failed\n",
  74. HP680_BTN_IRQ);
  75. return ret;
  76. }
  77. apm_get_power_status = hp6x0_apm_get_power_status;
  78. return ret;
  79. }
  80. static void __exit hp6x0_apm_exit(void)
  81. {
  82. free_irq(HP680_BTN_IRQ, 0);
  83. }
  84. module_init(hp6x0_apm_init);
  85. module_exit(hp6x0_apm_exit);
  86. MODULE_AUTHOR("Adriy Skulysh");
  87. MODULE_DESCRIPTION("hp6xx Advanced Power Management");
  88. MODULE_LICENSE("GPL");