Blame view

drivers/hwmon/hp_accel.c 11.7 KB
cfce41a6d   Eric Piel   LIS3LV02D: separa...
1
2
3
4
5
  /*
   *  hp_accel.c - Interface between LIS3LV02DL driver and HP ACPI BIOS
   *
   *  Copyright (C) 2007-2008 Yan Burman
   *  Copyright (C) 2008 Eric Piel
9e1c9d865   Pavel Machek   hp_accel: do not ...
6
   *  Copyright (C) 2008-2009 Pavel Machek
cfce41a6d   Eric Piel   LIS3LV02D: separa...
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
   *
   *  This program is free software; you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License as published by
   *  the Free Software Foundation; either version 2 of the License, or
   *  (at your option) any later version.
   *
   *  This program is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU General Public License for more details.
   *
   *  You should have received a copy of the GNU General Public License
   *  along with this program; if not, write to the Free Software
   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   */
  
  #include <linux/kernel.h>
  #include <linux/init.h>
  #include <linux/dmi.h>
  #include <linux/module.h>
  #include <linux/types.h>
  #include <linux/platform_device.h>
  #include <linux/interrupt.h>
cfce41a6d   Eric Piel   LIS3LV02D: separa...
30
31
32
33
  #include <linux/delay.h>
  #include <linux/wait.h>
  #include <linux/poll.h>
  #include <linux/freezer.h>
cfce41a6d   Eric Piel   LIS3LV02D: separa...
34
  #include <linux/uaccess.h>
9e0c79782   Eric Piel   lis3lv02d: merge ...
35
  #include <linux/leds.h>
cfce41a6d   Eric Piel   LIS3LV02D: separa...
36
37
38
39
40
41
  #include <acpi/acpi_drivers.h>
  #include <asm/atomic.h>
  #include "lis3lv02d.h"
  
  #define DRIVER_NAME     "lis3lv02d"
  #define ACPI_MDPS_CLASS "accelerometer"
9e1c9d865   Pavel Machek   hp_accel: do not ...
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
  /* Delayed LEDs infrastructure ------------------------------------ */
  
  /* Special LED class that can defer work */
  struct delayed_led_classdev {
  	struct led_classdev led_classdev;
  	struct work_struct work;
  	enum led_brightness new_brightness;
  
  	unsigned int led;		/* For driver */
  	void (*set_brightness)(struct delayed_led_classdev *data, enum led_brightness value);
  };
  
  static inline void delayed_set_status_worker(struct work_struct *work)
  {
  	struct delayed_led_classdev *data =
  			container_of(work, struct delayed_led_classdev, work);
  
  	data->set_brightness(data, data->new_brightness);
  }
  
  static inline void delayed_sysfs_set(struct led_classdev *led_cdev,
  			      enum led_brightness brightness)
  {
  	struct delayed_led_classdev *data = container_of(led_cdev,
  			     struct delayed_led_classdev, led_classdev);
  	data->new_brightness = brightness;
  	schedule_work(&data->work);
  }
  
  /* HP-specific accelerometer driver ------------------------------------ */
cfce41a6d   Eric Piel   LIS3LV02D: separa...
72
73
74
75
76
77
78
79
80
81
82
  
  /* For automatic insertion of the module */
  static struct acpi_device_id lis3lv02d_device_ids[] = {
  	{"HPQ0004", 0}, /* HP Mobile Data Protection System PNP */
  	{"", 0},
  };
  MODULE_DEVICE_TABLE(acpi, lis3lv02d_device_ids);
  
  
  /**
   * lis3lv02d_acpi_init - ACPI _INI method: initialize the device.
a38da2ed7   Daniel Mack   lis3: solve depen...
83
   * @lis3: pointer to the device struct
cfce41a6d   Eric Piel   LIS3LV02D: separa...
84
   *
a38da2ed7   Daniel Mack   lis3: solve depen...
85
   * Returns 0 on success.
cfce41a6d   Eric Piel   LIS3LV02D: separa...
86
   */
a38da2ed7   Daniel Mack   lis3: solve depen...
87
  int lis3lv02d_acpi_init(struct lis3lv02d *lis3)
cfce41a6d   Eric Piel   LIS3LV02D: separa...
88
  {
a38da2ed7   Daniel Mack   lis3: solve depen...
89
90
91
92
93
94
  	struct acpi_device *dev = lis3->bus_priv;
  	if (acpi_evaluate_object(dev->handle, METHOD_NAME__INI,
  				 NULL, NULL) != AE_OK)
  		return -EINVAL;
  
  	return 0;
cfce41a6d   Eric Piel   LIS3LV02D: separa...
95
96
97
98
  }
  
  /**
   * lis3lv02d_acpi_read - ACPI ALRD method: read a register
a38da2ed7   Daniel Mack   lis3: solve depen...
99
   * @lis3: pointer to the device struct
cfce41a6d   Eric Piel   LIS3LV02D: separa...
100
101
102
   * @reg:    the register to read
   * @ret:    result of the operation
   *
a38da2ed7   Daniel Mack   lis3: solve depen...
103
   * Returns 0 on success.
cfce41a6d   Eric Piel   LIS3LV02D: separa...
104
   */
a38da2ed7   Daniel Mack   lis3: solve depen...
105
  int lis3lv02d_acpi_read(struct lis3lv02d *lis3, int reg, u8 *ret)
cfce41a6d   Eric Piel   LIS3LV02D: separa...
106
  {
a38da2ed7   Daniel Mack   lis3: solve depen...
107
  	struct acpi_device *dev = lis3->bus_priv;
cfce41a6d   Eric Piel   LIS3LV02D: separa...
108
109
110
111
112
113
  	union acpi_object arg0 = { ACPI_TYPE_INTEGER };
  	struct acpi_object_list args = { 1, &arg0 };
  	unsigned long long lret;
  	acpi_status status;
  
  	arg0.integer.value = reg;
a38da2ed7   Daniel Mack   lis3: solve depen...
114
  	status = acpi_evaluate_integer(dev->handle, "ALRD", &args, &lret);
cfce41a6d   Eric Piel   LIS3LV02D: separa...
115
  	*ret = lret;
a38da2ed7   Daniel Mack   lis3: solve depen...
116
  	return (status != AE_OK) ? -EINVAL : 0;
cfce41a6d   Eric Piel   LIS3LV02D: separa...
117
118
119
120
  }
  
  /**
   * lis3lv02d_acpi_write - ACPI ALWR method: write to a register
a38da2ed7   Daniel Mack   lis3: solve depen...
121
   * @lis3: pointer to the device struct
cfce41a6d   Eric Piel   LIS3LV02D: separa...
122
123
124
   * @reg:    the register to write to
   * @val:    the value to write
   *
a38da2ed7   Daniel Mack   lis3: solve depen...
125
   * Returns 0 on success.
cfce41a6d   Eric Piel   LIS3LV02D: separa...
126
   */
a38da2ed7   Daniel Mack   lis3: solve depen...
127
  int lis3lv02d_acpi_write(struct lis3lv02d *lis3, int reg, u8 val)
cfce41a6d   Eric Piel   LIS3LV02D: separa...
128
  {
a38da2ed7   Daniel Mack   lis3: solve depen...
129
  	struct acpi_device *dev = lis3->bus_priv;
cfce41a6d   Eric Piel   LIS3LV02D: separa...
130
131
132
133
134
135
136
137
  	unsigned long long ret; /* Not used when writting */
  	union acpi_object in_obj[2];
  	struct acpi_object_list args = { 2, in_obj };
  
  	in_obj[0].type          = ACPI_TYPE_INTEGER;
  	in_obj[0].integer.value = reg;
  	in_obj[1].type          = ACPI_TYPE_INTEGER;
  	in_obj[1].integer.value = val;
a38da2ed7   Daniel Mack   lis3: solve depen...
138
139
140
141
  	if (acpi_evaluate_integer(dev->handle, "ALWR", &args, &ret) != AE_OK)
  		return -EINVAL;
  
  	return 0;
cfce41a6d   Eric Piel   LIS3LV02D: separa...
142
143
144
145
  }
  
  static int lis3lv02d_dmi_matched(const struct dmi_system_id *dmi)
  {
be84cfc58   Pavel Machek   hp_accel: adev is...
146
  	lis3_dev.ac = *((struct axis_conversion *)dmi->driver_data);
cfce41a6d   Eric Piel   LIS3LV02D: separa...
147
148
149
150
151
152
153
154
155
156
157
158
  	printk(KERN_INFO DRIVER_NAME ": hardware type %s found.
  ", dmi->ident);
  
  	return 1;
  }
  
  /* Represents, for each axis seen by userspace, the corresponding hw axis (+1).
   * If the value is negative, the opposite of the hw value is used. */
  static struct axis_conversion lis3lv02d_axis_normal = {1, 2, 3};
  static struct axis_conversion lis3lv02d_axis_y_inverted = {1, -2, 3};
  static struct axis_conversion lis3lv02d_axis_x_inverted = {-1, 2, 3};
  static struct axis_conversion lis3lv02d_axis_z_inverted = {1, 2, -3};
0093716e6   Eric Piel   lis3: add three n...
159
  static struct axis_conversion lis3lv02d_axis_xy_swap = {2, 1, 3};
cfce41a6d   Eric Piel   LIS3LV02D: separa...
160
  static struct axis_conversion lis3lv02d_axis_xy_rotated_left = {-2, 1, 3};
80eda5fb5   Eric Piel   lis3lv02d: add ax...
161
  static struct axis_conversion lis3lv02d_axis_xy_rotated_left_usd = {-2, 1, -3};
cfce41a6d   Eric Piel   LIS3LV02D: separa...
162
  static struct axis_conversion lis3lv02d_axis_xy_swap_inverted = {-2, -1, 3};
6bfef2b3c   Jiri Tersel   lis3lv02d: add ax...
163
  static struct axis_conversion lis3lv02d_axis_xy_rotated_right = {2, -1, 3};
87357d277   Martin Kebert   lis3lv02d: add ax...
164
  static struct axis_conversion lis3lv02d_axis_xy_swap_yz_inverted = {2, -1, -3};
cfce41a6d   Eric Piel   LIS3LV02D: separa...
165
166
167
168
169
170
171
172
173
  
  #define AXIS_DMI_MATCH(_ident, _name, _axis) {		\
  	.ident = _ident,				\
  	.callback = lis3lv02d_dmi_matched,		\
  	.matches = {					\
  		DMI_MATCH(DMI_PRODUCT_NAME, _name)	\
  	},						\
  	.driver_data = &lis3lv02d_axis_##_axis		\
  }
9ccf3b5e8   Giuseppe Bilotta   lis3lv02d: add ax...
174
175
176
177
178
179
180
181
182
183
184
185
  
  #define AXIS_DMI_MATCH2(_ident, _class1, _name1,	\
  				_class2, _name2,	\
  				_axis) {		\
  	.ident = _ident,				\
  	.callback = lis3lv02d_dmi_matched,		\
  	.matches = {					\
  		DMI_MATCH(DMI_##_class1, _name1),	\
  		DMI_MATCH(DMI_##_class2, _name2),	\
  	},						\
  	.driver_data = &lis3lv02d_axis_##_axis		\
  }
cfce41a6d   Eric Piel   LIS3LV02D: separa...
186
187
188
189
190
191
192
  static struct dmi_system_id lis3lv02d_dmi_ids[] = {
  	/* product names are truncated to match all kinds of a same model */
  	AXIS_DMI_MATCH("NC64x0", "HP Compaq nc64", x_inverted),
  	AXIS_DMI_MATCH("NC84x0", "HP Compaq nc84", z_inverted),
  	AXIS_DMI_MATCH("NX9420", "HP Compaq nx9420", x_inverted),
  	AXIS_DMI_MATCH("NW9440", "HP Compaq nw9440", x_inverted),
  	AXIS_DMI_MATCH("NC2510", "HP Compaq 2510", y_inverted),
0093716e6   Eric Piel   lis3: add three n...
193
  	AXIS_DMI_MATCH("NC2710", "HP Compaq 2710", xy_swap),
cfce41a6d   Eric Piel   LIS3LV02D: separa...
194
195
  	AXIS_DMI_MATCH("NC8510", "HP Compaq 8510", xy_swap_inverted),
  	AXIS_DMI_MATCH("HP2133", "HP 2133", xy_rotated_left),
9d7639d33   Pavel Machek   hp_accel: add two...
196
  	AXIS_DMI_MATCH("HP2140", "HP 2140", xy_swap_inverted),
80eda5fb5   Eric Piel   lis3lv02d: add ax...
197
  	AXIS_DMI_MATCH("NC653x", "HP Compaq 653", xy_rotated_left_usd),
a03018ff7   Pavel Herrmann   lis3: better supp...
198
199
  	AXIS_DMI_MATCH("NC6730b", "HP Compaq 6730b", xy_rotated_left_usd),
  	AXIS_DMI_MATCH("NC6730s", "HP Compaq 6730s", xy_swap),
6bfef2b3c   Jiri Tersel   lis3lv02d: add ax...
200
  	AXIS_DMI_MATCH("NC651xx", "HP Compaq 651", xy_rotated_right),
0093716e6   Eric Piel   lis3: add three n...
201
202
203
  	AXIS_DMI_MATCH("NC6710x", "HP Compaq 6710", xy_swap_yz_inverted),
  	AXIS_DMI_MATCH("NC6715x", "HP Compaq 6715", y_inverted),
  	AXIS_DMI_MATCH("NC693xx", "HP EliteBook 693", xy_rotated_right),
af19611c4   Éric Piel   lis3: add support...
204
  	AXIS_DMI_MATCH("NC693xx", "HP EliteBook 853", xy_swap),
9ccf3b5e8   Giuseppe Bilotta   lis3lv02d: add ax...
205
206
207
208
209
210
211
212
213
214
  	/* Intel-based HP Pavilion dv5 */
  	AXIS_DMI_MATCH2("HPDV5_I",
  			PRODUCT_NAME, "HP Pavilion dv5",
  			BOARD_NAME, "3603",
  			x_inverted),
  	/* AMD-based HP Pavilion dv5 */
  	AXIS_DMI_MATCH2("HPDV5_A",
  			PRODUCT_NAME, "HP Pavilion dv5",
  			BOARD_NAME, "3600",
  			y_inverted),
9d7639d33   Pavel Machek   hp_accel: add two...
215
  	AXIS_DMI_MATCH("DV7", "HP Pavilion dv7", x_inverted),
12a324b6a   Luca Cappa   hp_accel: axis co...
216
  	AXIS_DMI_MATCH("HP8710", "HP Compaq 8710", y_inverted),
2545f038f   Ian E. Morgan   lis3: add support...
217
  	AXIS_DMI_MATCH("HDX18", "HP HDX 18", x_inverted),
9bd14a839   Takashi Iwai   lis3: add support...
218
219
220
221
  	AXIS_DMI_MATCH("HPB432x", "HP ProBook 432", xy_rotated_left),
  	AXIS_DMI_MATCH("HPB442x", "HP ProBook 442", xy_rotated_left),
  	AXIS_DMI_MATCH("HPB452x", "HP ProBook 452", y_inverted),
  	AXIS_DMI_MATCH("HPB522x", "HP ProBook 522", xy_swap),
4e70598c3   Takashi Iwai   hp_accel: add qui...
222
223
  	AXIS_DMI_MATCH("HPB532x", "HP ProBook 532", y_inverted),
  	AXIS_DMI_MATCH("Mini5102", "HP Mini 5102", xy_rotated_left_usd),
cfce41a6d   Eric Piel   LIS3LV02D: separa...
224
225
  	{ NULL, }
  /* Laptop models without axis info (yet):
cfce41a6d   Eric Piel   LIS3LV02D: separa...
226
   * "NC6910" "HP Compaq 6910"
cfce41a6d   Eric Piel   LIS3LV02D: separa...
227
228
229
230
231
232
   * "NC2400" "HP Compaq nc2400"
   * "NX74x0" "HP Compaq nx74"
   * "NX6325" "HP Compaq nx6325"
   * "NC4400" "HP Compaq nc4400"
   */
  };
9e1c9d865   Pavel Machek   hp_accel: do not ...
233
  static void hpled_set(struct delayed_led_classdev *led_cdev, enum led_brightness value)
9e0c79782   Eric Piel   lis3lv02d: merge ...
234
  {
a38da2ed7   Daniel Mack   lis3: solve depen...
235
  	struct acpi_device *dev = lis3_dev.bus_priv;
9e0c79782   Eric Piel   lis3lv02d: merge ...
236
237
238
239
240
  	unsigned long long ret; /* Not used when writing */
  	union acpi_object in_obj[1];
  	struct acpi_object_list args = { 1, in_obj };
  
  	in_obj[0].type          = ACPI_TYPE_INTEGER;
9e1c9d865   Pavel Machek   hp_accel: do not ...
241
  	in_obj[0].integer.value = !!value;
9e0c79782   Eric Piel   lis3lv02d: merge ...
242

a38da2ed7   Daniel Mack   lis3: solve depen...
243
  	acpi_evaluate_integer(dev->handle, "ALED", &args, &ret);
9e0c79782   Eric Piel   lis3lv02d: merge ...
244
  }
9e1c9d865   Pavel Machek   hp_accel: do not ...
245
246
247
248
249
250
251
252
  static struct delayed_led_classdev hpled_led = {
  	.led_classdev = {
  		.name			= "hp::hddprotect",
  		.default_trigger	= "none",
  		.brightness_set		= delayed_sysfs_set,
  		.flags                  = LED_CORE_SUSPENDRESUME,
  	},
  	.set_brightness = hpled_set,
9e0c79782   Eric Piel   lis3lv02d: merge ...
253
  };
cfce41a6d   Eric Piel   LIS3LV02D: separa...
254

ef2cfc790   Pavel Machek   hp accelerometer:...
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
  static acpi_status
  lis3lv02d_get_resource(struct acpi_resource *resource, void *context)
  {
  	if (resource->type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) {
  		struct acpi_resource_extended_irq *irq;
  		u32 *device_irq = context;
  
  		irq = &resource->data.extended_irq;
  		*device_irq = irq->interrupts[0];
  	}
  
  	return AE_OK;
  }
  
  static void lis3lv02d_enum_resources(struct acpi_device *device)
  {
  	acpi_status status;
  
  	status = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
be84cfc58   Pavel Machek   hp_accel: adev is...
274
  					lis3lv02d_get_resource, &lis3_dev.irq);
ef2cfc790   Pavel Machek   hp accelerometer:...
275
276
277
278
  	if (ACPI_FAILURE(status))
  		printk(KERN_DEBUG DRIVER_NAME ": Error getting resources
  ");
  }
cfce41a6d   Eric Piel   LIS3LV02D: separa...
279
280
  static int lis3lv02d_add(struct acpi_device *device)
  {
9e0c79782   Eric Piel   lis3lv02d: merge ...
281
  	int ret;
cfce41a6d   Eric Piel   LIS3LV02D: separa...
282
283
284
  
  	if (!device)
  		return -EINVAL;
a38da2ed7   Daniel Mack   lis3: solve depen...
285
  	lis3_dev.bus_priv = device;
be84cfc58   Pavel Machek   hp_accel: adev is...
286
287
288
  	lis3_dev.init = lis3lv02d_acpi_init;
  	lis3_dev.read = lis3lv02d_acpi_read;
  	lis3_dev.write = lis3lv02d_acpi_write;
cfce41a6d   Eric Piel   LIS3LV02D: separa...
289
290
  	strcpy(acpi_device_name(device), DRIVER_NAME);
  	strcpy(acpi_device_class(device), ACPI_MDPS_CLASS);
be84cfc58   Pavel Machek   hp_accel: adev is...
291
  	device->driver_data = &lis3_dev;
cfce41a6d   Eric Piel   LIS3LV02D: separa...
292

a38da2ed7   Daniel Mack   lis3: solve depen...
293
294
  	/* obtain IRQ number of our device from ACPI */
  	lis3lv02d_enum_resources(device);
cfce41a6d   Eric Piel   LIS3LV02D: separa...
295
296
297
298
299
300
  
  	/* If possible use a "standard" axes order */
  	if (dmi_check_system(lis3lv02d_dmi_ids) == 0) {
  		printk(KERN_INFO DRIVER_NAME ": laptop model unknown, "
  				 "using default axes configuration
  ");
be84cfc58   Pavel Machek   hp_accel: adev is...
301
  		lis3_dev.ac = lis3lv02d_axis_normal;
cfce41a6d   Eric Piel   LIS3LV02D: separa...
302
  	}
a38da2ed7   Daniel Mack   lis3: solve depen...
303
304
  	/* call the core layer do its init */
  	ret = lis3lv02d_init_device(&lis3_dev);
9e0c79782   Eric Piel   lis3lv02d: merge ...
305
306
  	if (ret)
  		return ret;
a38da2ed7   Daniel Mack   lis3: solve depen...
307
308
  	INIT_WORK(&hpled_led.work, delayed_set_status_worker);
  	ret = led_classdev_register(NULL, &hpled_led.led_classdev);
9e0c79782   Eric Piel   lis3lv02d: merge ...
309
  	if (ret) {
a38da2ed7   Daniel Mack   lis3: solve depen...
310
311
  		lis3lv02d_joystick_disable();
  		lis3lv02d_poweroff(&lis3_dev);
9e1c9d865   Pavel Machek   hp_accel: do not ...
312
  		flush_work(&hpled_led.work);
9e0c79782   Eric Piel   lis3lv02d: merge ...
313
314
315
316
  		return ret;
  	}
  
  	return ret;
cfce41a6d   Eric Piel   LIS3LV02D: separa...
317
318
319
320
321
322
323
324
  }
  
  static int lis3lv02d_remove(struct acpi_device *device, int type)
  {
  	if (!device)
  		return -EINVAL;
  
  	lis3lv02d_joystick_disable();
a38da2ed7   Daniel Mack   lis3: solve depen...
325
  	lis3lv02d_poweroff(&lis3_dev);
cfce41a6d   Eric Piel   LIS3LV02D: separa...
326

9e1c9d865   Pavel Machek   hp_accel: do not ...
327
  	led_classdev_unregister(&hpled_led.led_classdev);
06efbeb4a   Oliver Neukum   hp_accel: fix rac...
328
  	flush_work(&hpled_led.work);
9e0c79782   Eric Piel   lis3lv02d: merge ...
329

a002ee896   Eric Piel   lis3: remove auto...
330
  	return lis3lv02d_remove_fs(&lis3_dev);
cfce41a6d   Eric Piel   LIS3LV02D: separa...
331
332
333
334
335
336
337
  }
  
  
  #ifdef CONFIG_PM
  static int lis3lv02d_suspend(struct acpi_device *device, pm_message_t state)
  {
  	/* make sure the device is off when we suspend */
a38da2ed7   Daniel Mack   lis3: solve depen...
338
  	lis3lv02d_poweroff(&lis3_dev);
cfce41a6d   Eric Piel   LIS3LV02D: separa...
339
340
341
342
343
  	return 0;
  }
  
  static int lis3lv02d_resume(struct acpi_device *device)
  {
a002ee896   Eric Piel   lis3: remove auto...
344
  	lis3lv02d_poweron(&lis3_dev);
cfce41a6d   Eric Piel   LIS3LV02D: separa...
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
  	return 0;
  }
  #else
  #define lis3lv02d_suspend NULL
  #define lis3lv02d_resume NULL
  #endif
  
  /* For the HP MDPS aka 3D Driveguard */
  static struct acpi_driver lis3lv02d_driver = {
  	.name  = DRIVER_NAME,
  	.class = ACPI_MDPS_CLASS,
  	.ids   = lis3lv02d_device_ids,
  	.ops = {
  		.add     = lis3lv02d_add,
  		.remove  = lis3lv02d_remove,
  		.suspend = lis3lv02d_suspend,
  		.resume  = lis3lv02d_resume,
  	}
  };
  
  static int __init lis3lv02d_init_module(void)
  {
  	int ret;
  
  	if (acpi_disabled)
  		return -ENODEV;
  
  	ret = acpi_bus_register_driver(&lis3lv02d_driver);
  	if (ret < 0)
  		return ret;
  
  	printk(KERN_INFO DRIVER_NAME " driver loaded.
  ");
  
  	return 0;
  }
  
  static void __exit lis3lv02d_exit_module(void)
  {
  	acpi_bus_unregister_driver(&lis3lv02d_driver);
  }
9e0c79782   Eric Piel   lis3lv02d: merge ...
386
  MODULE_DESCRIPTION("Glue between LIS3LV02Dx and HP ACPI BIOS and support for disk protection LED.");
cfce41a6d   Eric Piel   LIS3LV02D: separa...
387
388
389
390
391
  MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek");
  MODULE_LICENSE("GPL");
  
  module_init(lis3lv02d_init_module);
  module_exit(lis3lv02d_exit_module);