2 * Support for OLPC XO-1.5 System Control Interrupts (SCI)
4 * Copyright (C) 2009-2010 One Laptop per Child
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
12 #include <linux/device.h>
13 #include <linux/slab.h>
14 #include <linux/workqueue.h>
15 #include <linux/power_supply.h>
17 #include <acpi/acpi_bus.h>
18 #include <acpi/acpi_drivers.h>
21 #define DRV_NAME "olpc-xo15-sci"
22 #define PFX DRV_NAME ": "
23 #define XO15_SCI_CLASS DRV_NAME
24 #define XO15_SCI_DEVICE_NAME "OLPC XO-1.5 SCI"
26 static unsigned long xo15_sci_gpe
;
28 static void battery_status_changed(void)
30 struct power_supply
*psy
= power_supply_get_by_name("olpc-battery");
33 power_supply_changed(psy
);
38 static void ac_status_changed(void)
40 struct power_supply
*psy
= power_supply_get_by_name("olpc-ac");
43 power_supply_changed(psy
);
48 static void process_sci_queue(void)
54 r
= olpc_ec_sci_query(&data
);
58 pr_debug(PFX
"SCI 0x%x received\n", data
);
61 case EC_SCI_SRC_BATERR
:
62 case EC_SCI_SRC_BATSOC
:
63 case EC_SCI_SRC_BATTERY
:
64 case EC_SCI_SRC_BATCRIT
:
65 battery_status_changed();
67 case EC_SCI_SRC_ACPWR
:
74 pr_err(PFX
"Failed to clear SCI queue");
77 static void process_sci_queue_work(struct work_struct
*work
)
82 static DECLARE_WORK(sci_work
, process_sci_queue_work
);
84 static u32
xo15_sci_gpe_handler(acpi_handle gpe_device
, u32 gpe
, void *context
)
86 schedule_work(&sci_work
);
87 return ACPI_INTERRUPT_HANDLED
| ACPI_REENABLE_GPE
;
90 static int xo15_sci_add(struct acpi_device
*device
)
92 unsigned long long tmp
;
98 strcpy(acpi_device_name(device
), XO15_SCI_DEVICE_NAME
);
99 strcpy(acpi_device_class(device
), XO15_SCI_CLASS
);
101 /* Get GPE bit assignment (EC events). */
102 status
= acpi_evaluate_integer(device
->handle
, "_GPE", NULL
, &tmp
);
103 if (ACPI_FAILURE(status
))
107 status
= acpi_install_gpe_handler(NULL
, xo15_sci_gpe
,
108 ACPI_GPE_EDGE_TRIGGERED
,
109 xo15_sci_gpe_handler
, device
);
110 if (ACPI_FAILURE(status
))
113 dev_info(&device
->dev
, "Initialized, GPE = 0x%lx\n", xo15_sci_gpe
);
115 /* Flush queue, and enable all SCI events */
117 olpc_ec_mask_write(EC_SCI_SRC_ALL
);
119 acpi_enable_gpe(NULL
, xo15_sci_gpe
);
121 /* Enable wake-on-EC */
122 if (device
->wakeup
.flags
.valid
)
123 device_init_wakeup(&device
->dev
, true);
128 static int xo15_sci_remove(struct acpi_device
*device
, int type
)
130 acpi_disable_gpe(NULL
, xo15_sci_gpe
);
131 acpi_remove_gpe_handler(NULL
, xo15_sci_gpe
, xo15_sci_gpe_handler
);
132 cancel_work_sync(&sci_work
);
136 static int xo15_sci_resume(struct acpi_device
*device
)
138 /* Enable all EC events */
139 olpc_ec_mask_write(EC_SCI_SRC_ALL
);
141 /* Power/battery status might have changed */
142 battery_status_changed();
148 static const struct acpi_device_id xo15_sci_device_ids
[] = {
153 static struct acpi_driver xo15_sci_drv
= {
155 .class = XO15_SCI_CLASS
,
156 .ids
= xo15_sci_device_ids
,
159 .remove
= xo15_sci_remove
,
160 .resume
= xo15_sci_resume
,
164 static int __init
xo15_sci_init(void)
166 return acpi_bus_register_driver(&xo15_sci_drv
);
168 device_initcall(xo15_sci_init
);