aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hwmon')
-rw-r--r--drivers/hwmon/Kconfig19
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/hp_accel.c405
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
1305config 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
1324endif # ACPI 1305endif # ACPI
1325 1306
1326endif # HWMON 1307endif # 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
12obj-$(CONFIG_SENSORS_ATK0110) += asus_atk0110.o 12obj-$(CONFIG_SENSORS_ATK0110) += asus_atk0110.o
13obj-$(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 */
48struct 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
57static 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
65static 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 */
77static struct acpi_device_id lis3lv02d_device_ids[] = {
78 {"HPQ0004", 0}, /* HP Mobile Data Protection System PNP */
79 {"", 0},
80};
81MODULE_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 */
90int 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 */
108int 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 */
131int 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
149static 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 } }
162DEFINE_CONV(normal, 1, 2, 3);
163DEFINE_CONV(y_inverted, 1, -2, 3);
164DEFINE_CONV(x_inverted, -1, 2, 3);
165DEFINE_CONV(z_inverted, 1, 2, -3);
166DEFINE_CONV(xy_swap, 2, 1, 3);
167DEFINE_CONV(xy_rotated_left, -2, 1, 3);
168DEFINE_CONV(xy_rotated_left_usd, -2, 1, -3);
169DEFINE_CONV(xy_swap_inverted, -2, -1, 3);
170DEFINE_CONV(xy_rotated_right, 2, -1, 3);
171DEFINE_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}
193static 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
241static 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
254static 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
264static acpi_status
265lis3lv02d_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
278static 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
288static 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
332static 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
348static 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
355static 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 */
366static 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
378static 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
394static void __exit lis3lv02d_exit_module(void)
395{
396 acpi_bus_unregister_driver(&lis3lv02d_driver);
397}
398
399MODULE_DESCRIPTION("Glue between LIS3LV02Dx and HP ACPI BIOS and support for disk protection LED.");
400MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek");
401MODULE_LICENSE("GPL");
402
403module_init(lis3lv02d_init_module);
404module_exit(lis3lv02d_exit_module);
405