diff options
Diffstat (limited to 'drivers/hwmon')
-rw-r--r-- | drivers/hwmon/Kconfig | 19 | ||||
-rw-r--r-- | drivers/hwmon/Makefile | 1 | ||||
-rw-r--r-- | drivers/hwmon/hp_accel.c | 405 |
3 files changed, 0 insertions, 425 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index c48101cf58f4..3f8c895417de 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
@@ -1302,25 +1302,6 @@ config SENSORS_ATK0110 | |||
1302 | This driver can also be built as a module. If so, the module | 1302 | This driver can also be built as a module. If so, the module |
1303 | will be called asus_atk0110. | 1303 | will be called asus_atk0110. |
1304 | 1304 | ||
1305 | config HP_ACCEL | ||
1306 | tristate "HP laptop accelerometer" | ||
1307 | depends on INPUT | ||
1308 | select SENSORS_LIS3LV02D | ||
1309 | select NEW_LEDS | ||
1310 | select LEDS_CLASS | ||
1311 | default n | ||
1312 | help | ||
1313 | This driver provides support for the "Mobile Data Protection System 3D" | ||
1314 | or "3D DriveGuard" feature of HP laptops. On such systems the driver | ||
1315 | should load automatically (via ACPI alias). | ||
1316 | |||
1317 | Support for a led indicating disk protection will be provided as | ||
1318 | hp::hddprotect. For more information on the feature, refer to | ||
1319 | Documentation/hwmon/lis3lv02d. | ||
1320 | |||
1321 | To compile this driver as a module, choose M here: the module will | ||
1322 | be called hp_accel. | ||
1323 | |||
1324 | endif # ACPI | 1305 | endif # ACPI |
1325 | 1306 | ||
1326 | endif # HWMON | 1307 | endif # HWMON |
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 94bf27482979..55ba906def74 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile | |||
@@ -10,7 +10,6 @@ obj-$(CONFIG_SENSORS_LIS3LV02D) += lis3lv02d.o | |||
10 | 10 | ||
11 | # APCI drivers | 11 | # APCI drivers |
12 | obj-$(CONFIG_SENSORS_ATK0110) += asus_atk0110.o | 12 | obj-$(CONFIG_SENSORS_ATK0110) += asus_atk0110.o |
13 | obj-$(CONFIG_HP_ACCEL) += hp_accel.o | ||
14 | 13 | ||
15 | # Native drivers | 14 | # Native drivers |
16 | # asb100, then w83781d go first, as they can override other drivers' addresses. | 15 | # asb100, then w83781d go first, as they can override other drivers' addresses. |
diff --git a/drivers/hwmon/hp_accel.c b/drivers/hwmon/hp_accel.c deleted file mode 100644 index 3d21fa2b97cd..000000000000 --- a/drivers/hwmon/hp_accel.c +++ /dev/null | |||
@@ -1,405 +0,0 @@ | |||
1 | /* | ||
2 | * hp_accel.c - Interface between LIS3LV02DL driver and HP ACPI BIOS | ||
3 | * | ||
4 | * Copyright (C) 2007-2008 Yan Burman | ||
5 | * Copyright (C) 2008 Eric Piel | ||
6 | * Copyright (C) 2008-2009 Pavel Machek | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | |||
23 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
24 | |||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/dmi.h> | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/types.h> | ||
30 | #include <linux/platform_device.h> | ||
31 | #include <linux/interrupt.h> | ||
32 | #include <linux/delay.h> | ||
33 | #include <linux/wait.h> | ||
34 | #include <linux/poll.h> | ||
35 | #include <linux/freezer.h> | ||
36 | #include <linux/uaccess.h> | ||
37 | #include <linux/leds.h> | ||
38 | #include <acpi/acpi_drivers.h> | ||
39 | #include <asm/atomic.h> | ||
40 | #include "lis3lv02d.h" | ||
41 | |||
42 | #define DRIVER_NAME "lis3lv02d" | ||
43 | #define ACPI_MDPS_CLASS "accelerometer" | ||
44 | |||
45 | /* Delayed LEDs infrastructure ------------------------------------ */ | ||
46 | |||
47 | /* Special LED class that can defer work */ | ||
48 | struct delayed_led_classdev { | ||
49 | struct led_classdev led_classdev; | ||
50 | struct work_struct work; | ||
51 | enum led_brightness new_brightness; | ||
52 | |||
53 | unsigned int led; /* For driver */ | ||
54 | void (*set_brightness)(struct delayed_led_classdev *data, enum led_brightness value); | ||
55 | }; | ||
56 | |||
57 | static inline void delayed_set_status_worker(struct work_struct *work) | ||
58 | { | ||
59 | struct delayed_led_classdev *data = | ||
60 | container_of(work, struct delayed_led_classdev, work); | ||
61 | |||
62 | data->set_brightness(data, data->new_brightness); | ||
63 | } | ||
64 | |||
65 | static inline void delayed_sysfs_set(struct led_classdev *led_cdev, | ||
66 | enum led_brightness brightness) | ||
67 | { | ||
68 | struct delayed_led_classdev *data = container_of(led_cdev, | ||
69 | struct delayed_led_classdev, led_classdev); | ||
70 | data->new_brightness = brightness; | ||
71 | schedule_work(&data->work); | ||
72 | } | ||
73 | |||
74 | /* HP-specific accelerometer driver ------------------------------------ */ | ||
75 | |||
76 | /* For automatic insertion of the module */ | ||
77 | static struct acpi_device_id lis3lv02d_device_ids[] = { | ||
78 | {"HPQ0004", 0}, /* HP Mobile Data Protection System PNP */ | ||
79 | {"", 0}, | ||
80 | }; | ||
81 | MODULE_DEVICE_TABLE(acpi, lis3lv02d_device_ids); | ||
82 | |||
83 | |||
84 | /** | ||
85 | * lis3lv02d_acpi_init - ACPI _INI method: initialize the device. | ||
86 | * @lis3: pointer to the device struct | ||
87 | * | ||
88 | * Returns 0 on success. | ||
89 | */ | ||
90 | int lis3lv02d_acpi_init(struct lis3lv02d *lis3) | ||
91 | { | ||
92 | struct acpi_device *dev = lis3->bus_priv; | ||
93 | if (acpi_evaluate_object(dev->handle, METHOD_NAME__INI, | ||
94 | NULL, NULL) != AE_OK) | ||
95 | return -EINVAL; | ||
96 | |||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | /** | ||
101 | * lis3lv02d_acpi_read - ACPI ALRD method: read a register | ||
102 | * @lis3: pointer to the device struct | ||
103 | * @reg: the register to read | ||
104 | * @ret: result of the operation | ||
105 | * | ||
106 | * Returns 0 on success. | ||
107 | */ | ||
108 | int lis3lv02d_acpi_read(struct lis3lv02d *lis3, int reg, u8 *ret) | ||
109 | { | ||
110 | struct acpi_device *dev = lis3->bus_priv; | ||
111 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; | ||
112 | struct acpi_object_list args = { 1, &arg0 }; | ||
113 | unsigned long long lret; | ||
114 | acpi_status status; | ||
115 | |||
116 | arg0.integer.value = reg; | ||
117 | |||
118 | status = acpi_evaluate_integer(dev->handle, "ALRD", &args, &lret); | ||
119 | *ret = lret; | ||
120 | return (status != AE_OK) ? -EINVAL : 0; | ||
121 | } | ||
122 | |||
123 | /** | ||
124 | * lis3lv02d_acpi_write - ACPI ALWR method: write to a register | ||
125 | * @lis3: pointer to the device struct | ||
126 | * @reg: the register to write to | ||
127 | * @val: the value to write | ||
128 | * | ||
129 | * Returns 0 on success. | ||
130 | */ | ||
131 | int lis3lv02d_acpi_write(struct lis3lv02d *lis3, int reg, u8 val) | ||
132 | { | ||
133 | struct acpi_device *dev = lis3->bus_priv; | ||
134 | unsigned long long ret; /* Not used when writting */ | ||
135 | union acpi_object in_obj[2]; | ||
136 | struct acpi_object_list args = { 2, in_obj }; | ||
137 | |||
138 | in_obj[0].type = ACPI_TYPE_INTEGER; | ||
139 | in_obj[0].integer.value = reg; | ||
140 | in_obj[1].type = ACPI_TYPE_INTEGER; | ||
141 | in_obj[1].integer.value = val; | ||
142 | |||
143 | if (acpi_evaluate_integer(dev->handle, "ALWR", &args, &ret) != AE_OK) | ||
144 | return -EINVAL; | ||
145 | |||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static int lis3lv02d_dmi_matched(const struct dmi_system_id *dmi) | ||
150 | { | ||
151 | lis3_dev.ac = *((union axis_conversion *)dmi->driver_data); | ||
152 | pr_info("hardware type %s found\n", dmi->ident); | ||
153 | |||
154 | return 1; | ||
155 | } | ||
156 | |||
157 | /* Represents, for each axis seen by userspace, the corresponding hw axis (+1). | ||
158 | * If the value is negative, the opposite of the hw value is used. */ | ||
159 | #define DEFINE_CONV(name, x, y, z) \ | ||
160 | static union axis_conversion lis3lv02d_axis_##name = \ | ||
161 | { .as_array = { x, y, z } } | ||
162 | DEFINE_CONV(normal, 1, 2, 3); | ||
163 | DEFINE_CONV(y_inverted, 1, -2, 3); | ||
164 | DEFINE_CONV(x_inverted, -1, 2, 3); | ||
165 | DEFINE_CONV(z_inverted, 1, 2, -3); | ||
166 | DEFINE_CONV(xy_swap, 2, 1, 3); | ||
167 | DEFINE_CONV(xy_rotated_left, -2, 1, 3); | ||
168 | DEFINE_CONV(xy_rotated_left_usd, -2, 1, -3); | ||
169 | DEFINE_CONV(xy_swap_inverted, -2, -1, 3); | ||
170 | DEFINE_CONV(xy_rotated_right, 2, -1, 3); | ||
171 | DEFINE_CONV(xy_swap_yz_inverted, 2, -1, -3); | ||
172 | |||
173 | #define AXIS_DMI_MATCH(_ident, _name, _axis) { \ | ||
174 | .ident = _ident, \ | ||
175 | .callback = lis3lv02d_dmi_matched, \ | ||
176 | .matches = { \ | ||
177 | DMI_MATCH(DMI_PRODUCT_NAME, _name) \ | ||
178 | }, \ | ||
179 | .driver_data = &lis3lv02d_axis_##_axis \ | ||
180 | } | ||
181 | |||
182 | #define AXIS_DMI_MATCH2(_ident, _class1, _name1, \ | ||
183 | _class2, _name2, \ | ||
184 | _axis) { \ | ||
185 | .ident = _ident, \ | ||
186 | .callback = lis3lv02d_dmi_matched, \ | ||
187 | .matches = { \ | ||
188 | DMI_MATCH(DMI_##_class1, _name1), \ | ||
189 | DMI_MATCH(DMI_##_class2, _name2), \ | ||
190 | }, \ | ||
191 | .driver_data = &lis3lv02d_axis_##_axis \ | ||
192 | } | ||
193 | static struct dmi_system_id lis3lv02d_dmi_ids[] = { | ||
194 | /* product names are truncated to match all kinds of a same model */ | ||
195 | AXIS_DMI_MATCH("NC64x0", "HP Compaq nc64", x_inverted), | ||
196 | AXIS_DMI_MATCH("NC84x0", "HP Compaq nc84", z_inverted), | ||
197 | AXIS_DMI_MATCH("NX9420", "HP Compaq nx9420", x_inverted), | ||
198 | AXIS_DMI_MATCH("NW9440", "HP Compaq nw9440", x_inverted), | ||
199 | AXIS_DMI_MATCH("NC2510", "HP Compaq 2510", y_inverted), | ||
200 | AXIS_DMI_MATCH("NC2710", "HP Compaq 2710", xy_swap), | ||
201 | AXIS_DMI_MATCH("NC8510", "HP Compaq 8510", xy_swap_inverted), | ||
202 | AXIS_DMI_MATCH("HP2133", "HP 2133", xy_rotated_left), | ||
203 | AXIS_DMI_MATCH("HP2140", "HP 2140", xy_swap_inverted), | ||
204 | AXIS_DMI_MATCH("NC653x", "HP Compaq 653", xy_rotated_left_usd), | ||
205 | AXIS_DMI_MATCH("NC6730b", "HP Compaq 6730b", xy_rotated_left_usd), | ||
206 | AXIS_DMI_MATCH("NC6730s", "HP Compaq 6730s", xy_swap), | ||
207 | AXIS_DMI_MATCH("NC651xx", "HP Compaq 651", xy_rotated_right), | ||
208 | AXIS_DMI_MATCH("NC6710x", "HP Compaq 6710", xy_swap_yz_inverted), | ||
209 | AXIS_DMI_MATCH("NC6715x", "HP Compaq 6715", y_inverted), | ||
210 | AXIS_DMI_MATCH("NC693xx", "HP EliteBook 693", xy_rotated_right), | ||
211 | AXIS_DMI_MATCH("NC693xx", "HP EliteBook 853", xy_swap), | ||
212 | /* Intel-based HP Pavilion dv5 */ | ||
213 | AXIS_DMI_MATCH2("HPDV5_I", | ||
214 | PRODUCT_NAME, "HP Pavilion dv5", | ||
215 | BOARD_NAME, "3603", | ||
216 | x_inverted), | ||
217 | /* AMD-based HP Pavilion dv5 */ | ||
218 | AXIS_DMI_MATCH2("HPDV5_A", | ||
219 | PRODUCT_NAME, "HP Pavilion dv5", | ||
220 | BOARD_NAME, "3600", | ||
221 | y_inverted), | ||
222 | AXIS_DMI_MATCH("DV7", "HP Pavilion dv7", x_inverted), | ||
223 | AXIS_DMI_MATCH("HP8710", "HP Compaq 8710", y_inverted), | ||
224 | AXIS_DMI_MATCH("HDX18", "HP HDX 18", x_inverted), | ||
225 | AXIS_DMI_MATCH("HPB432x", "HP ProBook 432", xy_rotated_left), | ||
226 | AXIS_DMI_MATCH("HPB442x", "HP ProBook 442", xy_rotated_left), | ||
227 | AXIS_DMI_MATCH("HPB452x", "HP ProBook 452", y_inverted), | ||
228 | AXIS_DMI_MATCH("HPB522x", "HP ProBook 522", xy_swap), | ||
229 | AXIS_DMI_MATCH("HPB532x", "HP ProBook 532", y_inverted), | ||
230 | AXIS_DMI_MATCH("Mini510x", "HP Mini 510", xy_rotated_left_usd), | ||
231 | { NULL, } | ||
232 | /* Laptop models without axis info (yet): | ||
233 | * "NC6910" "HP Compaq 6910" | ||
234 | * "NC2400" "HP Compaq nc2400" | ||
235 | * "NX74x0" "HP Compaq nx74" | ||
236 | * "NX6325" "HP Compaq nx6325" | ||
237 | * "NC4400" "HP Compaq nc4400" | ||
238 | */ | ||
239 | }; | ||
240 | |||
241 | static void hpled_set(struct delayed_led_classdev *led_cdev, enum led_brightness value) | ||
242 | { | ||
243 | struct acpi_device *dev = lis3_dev.bus_priv; | ||
244 | unsigned long long ret; /* Not used when writing */ | ||
245 | union acpi_object in_obj[1]; | ||
246 | struct acpi_object_list args = { 1, in_obj }; | ||
247 | |||
248 | in_obj[0].type = ACPI_TYPE_INTEGER; | ||
249 | in_obj[0].integer.value = !!value; | ||
250 | |||
251 | acpi_evaluate_integer(dev->handle, "ALED", &args, &ret); | ||
252 | } | ||
253 | |||
254 | static struct delayed_led_classdev hpled_led = { | ||
255 | .led_classdev = { | ||
256 | .name = "hp::hddprotect", | ||
257 | .default_trigger = "none", | ||
258 | .brightness_set = delayed_sysfs_set, | ||
259 | .flags = LED_CORE_SUSPENDRESUME, | ||
260 | }, | ||
261 | .set_brightness = hpled_set, | ||
262 | }; | ||
263 | |||
264 | static acpi_status | ||
265 | lis3lv02d_get_resource(struct acpi_resource *resource, void *context) | ||
266 | { | ||
267 | if (resource->type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) { | ||
268 | struct acpi_resource_extended_irq *irq; | ||
269 | u32 *device_irq = context; | ||
270 | |||
271 | irq = &resource->data.extended_irq; | ||
272 | *device_irq = irq->interrupts[0]; | ||
273 | } | ||
274 | |||
275 | return AE_OK; | ||
276 | } | ||
277 | |||
278 | static void lis3lv02d_enum_resources(struct acpi_device *device) | ||
279 | { | ||
280 | acpi_status status; | ||
281 | |||
282 | status = acpi_walk_resources(device->handle, METHOD_NAME__CRS, | ||
283 | lis3lv02d_get_resource, &lis3_dev.irq); | ||
284 | if (ACPI_FAILURE(status)) | ||
285 | printk(KERN_DEBUG DRIVER_NAME ": Error getting resources\n"); | ||
286 | } | ||
287 | |||
288 | static int lis3lv02d_add(struct acpi_device *device) | ||
289 | { | ||
290 | int ret; | ||
291 | |||
292 | if (!device) | ||
293 | return -EINVAL; | ||
294 | |||
295 | lis3_dev.bus_priv = device; | ||
296 | lis3_dev.init = lis3lv02d_acpi_init; | ||
297 | lis3_dev.read = lis3lv02d_acpi_read; | ||
298 | lis3_dev.write = lis3lv02d_acpi_write; | ||
299 | strcpy(acpi_device_name(device), DRIVER_NAME); | ||
300 | strcpy(acpi_device_class(device), ACPI_MDPS_CLASS); | ||
301 | device->driver_data = &lis3_dev; | ||
302 | |||
303 | /* obtain IRQ number of our device from ACPI */ | ||
304 | lis3lv02d_enum_resources(device); | ||
305 | |||
306 | /* If possible use a "standard" axes order */ | ||
307 | if (lis3_dev.ac.x && lis3_dev.ac.y && lis3_dev.ac.z) { | ||
308 | pr_info("Using custom axes %d,%d,%d\n", | ||
309 | lis3_dev.ac.x, lis3_dev.ac.y, lis3_dev.ac.z); | ||
310 | } else if (dmi_check_system(lis3lv02d_dmi_ids) == 0) { | ||
311 | pr_info("laptop model unknown, using default axes configuration\n"); | ||
312 | lis3_dev.ac = lis3lv02d_axis_normal; | ||
313 | } | ||
314 | |||
315 | /* call the core layer do its init */ | ||
316 | ret = lis3lv02d_init_device(&lis3_dev); | ||
317 | if (ret) | ||
318 | return ret; | ||
319 | |||
320 | INIT_WORK(&hpled_led.work, delayed_set_status_worker); | ||
321 | ret = led_classdev_register(NULL, &hpled_led.led_classdev); | ||
322 | if (ret) { | ||
323 | lis3lv02d_joystick_disable(); | ||
324 | lis3lv02d_poweroff(&lis3_dev); | ||
325 | flush_work(&hpled_led.work); | ||
326 | return ret; | ||
327 | } | ||
328 | |||
329 | return ret; | ||
330 | } | ||
331 | |||
332 | static int lis3lv02d_remove(struct acpi_device *device, int type) | ||
333 | { | ||
334 | if (!device) | ||
335 | return -EINVAL; | ||
336 | |||
337 | lis3lv02d_joystick_disable(); | ||
338 | lis3lv02d_poweroff(&lis3_dev); | ||
339 | |||
340 | led_classdev_unregister(&hpled_led.led_classdev); | ||
341 | flush_work(&hpled_led.work); | ||
342 | |||
343 | return lis3lv02d_remove_fs(&lis3_dev); | ||
344 | } | ||
345 | |||
346 | |||
347 | #ifdef CONFIG_PM | ||
348 | static int lis3lv02d_suspend(struct acpi_device *device, pm_message_t state) | ||
349 | { | ||
350 | /* make sure the device is off when we suspend */ | ||
351 | lis3lv02d_poweroff(&lis3_dev); | ||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | static int lis3lv02d_resume(struct acpi_device *device) | ||
356 | { | ||
357 | lis3lv02d_poweron(&lis3_dev); | ||
358 | return 0; | ||
359 | } | ||
360 | #else | ||
361 | #define lis3lv02d_suspend NULL | ||
362 | #define lis3lv02d_resume NULL | ||
363 | #endif | ||
364 | |||
365 | /* For the HP MDPS aka 3D Driveguard */ | ||
366 | static struct acpi_driver lis3lv02d_driver = { | ||
367 | .name = DRIVER_NAME, | ||
368 | .class = ACPI_MDPS_CLASS, | ||
369 | .ids = lis3lv02d_device_ids, | ||
370 | .ops = { | ||
371 | .add = lis3lv02d_add, | ||
372 | .remove = lis3lv02d_remove, | ||
373 | .suspend = lis3lv02d_suspend, | ||
374 | .resume = lis3lv02d_resume, | ||
375 | } | ||
376 | }; | ||
377 | |||
378 | static int __init lis3lv02d_init_module(void) | ||
379 | { | ||
380 | int ret; | ||
381 | |||
382 | if (acpi_disabled) | ||
383 | return -ENODEV; | ||
384 | |||
385 | ret = acpi_bus_register_driver(&lis3lv02d_driver); | ||
386 | if (ret < 0) | ||
387 | return ret; | ||
388 | |||
389 | pr_info("driver loaded\n"); | ||
390 | |||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | static void __exit lis3lv02d_exit_module(void) | ||
395 | { | ||
396 | acpi_bus_unregister_driver(&lis3lv02d_driver); | ||
397 | } | ||
398 | |||
399 | MODULE_DESCRIPTION("Glue between LIS3LV02Dx and HP ACPI BIOS and support for disk protection LED."); | ||
400 | MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek"); | ||
401 | MODULE_LICENSE("GPL"); | ||
402 | |||
403 | module_init(lis3lv02d_init_module); | ||
404 | module_exit(lis3lv02d_exit_module); | ||
405 | |||