LIS3LV02D: separate the core from HP ACPI API

The sensor can be accessed via various buses. In particular, SPI, I²C
and, on HP laptops, via a specific ACPI API (the only one currently
supported). Separate this latest platform from the core of the sensor
driver to allow support for the other bus type. The second, and more
direct goal is actually to be able to merge this part with the
hp-disk-leds driver, which has the same ACPI PNP number.

Signed-off-by: Pavel Machek <pavel@suse.cz>
Signed-off-by: Eric Piel <eric.piel@tremplin-utc.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Eric Piel and committed by
Linus Torvalds
cfce41a6 8e961870

+324 -251
+1 -1
drivers/hwmon/Makefile
··· 49 49 obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o 50 50 obj-$(CONFIG_SENSORS_IT87) += it87.o 51 51 obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o 52 - obj-$(CONFIG_SENSORS_LIS3LV02D) += lis3lv02d.o 52 + obj-$(CONFIG_SENSORS_LIS3LV02D) += lis3lv02d.o hp_accel.o 53 53 obj-$(CONFIG_SENSORS_LM63) += lm63.o 54 54 obj-$(CONFIG_SENSORS_LM70) += lm70.o 55 55 obj-$(CONFIG_SENSORS_LM75) += lm75.o
+265
drivers/hwmon/hp_accel.c
··· 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 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 + #include <linux/kernel.h> 24 + #include <linux/init.h> 25 + #include <linux/dmi.h> 26 + #include <linux/module.h> 27 + #include <linux/types.h> 28 + #include <linux/platform_device.h> 29 + #include <linux/interrupt.h> 30 + #include <linux/input.h> 31 + #include <linux/kthread.h> 32 + #include <linux/semaphore.h> 33 + #include <linux/delay.h> 34 + #include <linux/wait.h> 35 + #include <linux/poll.h> 36 + #include <linux/freezer.h> 37 + #include <linux/version.h> 38 + #include <linux/uaccess.h> 39 + #include <acpi/acpi_drivers.h> 40 + #include <asm/atomic.h> 41 + #include "lis3lv02d.h" 42 + 43 + #define DRIVER_NAME "lis3lv02d" 44 + #define ACPI_MDPS_CLASS "accelerometer" 45 + 46 + 47 + /* For automatic insertion of the module */ 48 + static struct acpi_device_id lis3lv02d_device_ids[] = { 49 + {"HPQ0004", 0}, /* HP Mobile Data Protection System PNP */ 50 + {"", 0}, 51 + }; 52 + MODULE_DEVICE_TABLE(acpi, lis3lv02d_device_ids); 53 + 54 + 55 + /** 56 + * lis3lv02d_acpi_init - ACPI _INI method: initialize the device. 57 + * @handle: the handle of the device 58 + * 59 + * Returns AE_OK on success. 60 + */ 61 + acpi_status lis3lv02d_acpi_init(acpi_handle handle) 62 + { 63 + return acpi_evaluate_object(handle, METHOD_NAME__INI, NULL, NULL); 64 + } 65 + 66 + /** 67 + * lis3lv02d_acpi_read - ACPI ALRD method: read a register 68 + * @handle: the handle of the device 69 + * @reg: the register to read 70 + * @ret: result of the operation 71 + * 72 + * Returns AE_OK on success. 73 + */ 74 + acpi_status lis3lv02d_acpi_read(acpi_handle handle, int reg, u8 *ret) 75 + { 76 + union acpi_object arg0 = { ACPI_TYPE_INTEGER }; 77 + struct acpi_object_list args = { 1, &arg0 }; 78 + unsigned long long lret; 79 + acpi_status status; 80 + 81 + arg0.integer.value = reg; 82 + 83 + status = acpi_evaluate_integer(handle, "ALRD", &args, &lret); 84 + *ret = lret; 85 + return status; 86 + } 87 + 88 + /** 89 + * lis3lv02d_acpi_write - ACPI ALWR method: write to a register 90 + * @handle: the handle of the device 91 + * @reg: the register to write to 92 + * @val: the value to write 93 + * 94 + * Returns AE_OK on success. 95 + */ 96 + acpi_status lis3lv02d_acpi_write(acpi_handle handle, int reg, u8 val) 97 + { 98 + unsigned long long ret; /* Not used when writting */ 99 + union acpi_object in_obj[2]; 100 + struct acpi_object_list args = { 2, in_obj }; 101 + 102 + in_obj[0].type = ACPI_TYPE_INTEGER; 103 + in_obj[0].integer.value = reg; 104 + in_obj[1].type = ACPI_TYPE_INTEGER; 105 + in_obj[1].integer.value = val; 106 + 107 + return acpi_evaluate_integer(handle, "ALWR", &args, &ret); 108 + } 109 + 110 + static int lis3lv02d_dmi_matched(const struct dmi_system_id *dmi) 111 + { 112 + adev.ac = *((struct axis_conversion *)dmi->driver_data); 113 + printk(KERN_INFO DRIVER_NAME ": hardware type %s found.\n", dmi->ident); 114 + 115 + return 1; 116 + } 117 + 118 + /* Represents, for each axis seen by userspace, the corresponding hw axis (+1). 119 + * If the value is negative, the opposite of the hw value is used. */ 120 + static struct axis_conversion lis3lv02d_axis_normal = {1, 2, 3}; 121 + static struct axis_conversion lis3lv02d_axis_y_inverted = {1, -2, 3}; 122 + static struct axis_conversion lis3lv02d_axis_x_inverted = {-1, 2, 3}; 123 + static struct axis_conversion lis3lv02d_axis_z_inverted = {1, 2, -3}; 124 + static struct axis_conversion lis3lv02d_axis_xy_rotated_left = {-2, 1, 3}; 125 + static struct axis_conversion lis3lv02d_axis_xy_swap_inverted = {-2, -1, 3}; 126 + 127 + #define AXIS_DMI_MATCH(_ident, _name, _axis) { \ 128 + .ident = _ident, \ 129 + .callback = lis3lv02d_dmi_matched, \ 130 + .matches = { \ 131 + DMI_MATCH(DMI_PRODUCT_NAME, _name) \ 132 + }, \ 133 + .driver_data = &lis3lv02d_axis_##_axis \ 134 + } 135 + static struct dmi_system_id lis3lv02d_dmi_ids[] = { 136 + /* product names are truncated to match all kinds of a same model */ 137 + AXIS_DMI_MATCH("NC64x0", "HP Compaq nc64", x_inverted), 138 + AXIS_DMI_MATCH("NC84x0", "HP Compaq nc84", z_inverted), 139 + AXIS_DMI_MATCH("NX9420", "HP Compaq nx9420", x_inverted), 140 + AXIS_DMI_MATCH("NW9440", "HP Compaq nw9440", x_inverted), 141 + AXIS_DMI_MATCH("NC2510", "HP Compaq 2510", y_inverted), 142 + AXIS_DMI_MATCH("NC8510", "HP Compaq 8510", xy_swap_inverted), 143 + AXIS_DMI_MATCH("HP2133", "HP 2133", xy_rotated_left), 144 + { NULL, } 145 + /* Laptop models without axis info (yet): 146 + * "NC651xx" "HP Compaq 651" 147 + * "NC671xx" "HP Compaq 671" 148 + * "NC6910" "HP Compaq 6910" 149 + * HP Compaq 8710x Notebook PC / Mobile Workstation 150 + * "NC2400" "HP Compaq nc2400" 151 + * "NX74x0" "HP Compaq nx74" 152 + * "NX6325" "HP Compaq nx6325" 153 + * "NC4400" "HP Compaq nc4400" 154 + */ 155 + }; 156 + 157 + 158 + static int lis3lv02d_add(struct acpi_device *device) 159 + { 160 + u8 val; 161 + 162 + if (!device) 163 + return -EINVAL; 164 + 165 + adev.device = device; 166 + adev.init = lis3lv02d_acpi_init; 167 + adev.read = lis3lv02d_acpi_read; 168 + adev.write = lis3lv02d_acpi_write; 169 + strcpy(acpi_device_name(device), DRIVER_NAME); 170 + strcpy(acpi_device_class(device), ACPI_MDPS_CLASS); 171 + device->driver_data = &adev; 172 + 173 + lis3lv02d_acpi_read(device->handle, WHO_AM_I, &val); 174 + if ((val != LIS3LV02DL_ID) && (val != LIS302DL_ID)) { 175 + printk(KERN_ERR DRIVER_NAME 176 + ": Accelerometer chip not LIS3LV02D{L,Q}\n"); 177 + } 178 + 179 + /* If possible use a "standard" axes order */ 180 + if (dmi_check_system(lis3lv02d_dmi_ids) == 0) { 181 + printk(KERN_INFO DRIVER_NAME ": laptop model unknown, " 182 + "using default axes configuration\n"); 183 + adev.ac = lis3lv02d_axis_normal; 184 + } 185 + 186 + return lis3lv02d_init_device(&adev); 187 + } 188 + 189 + static int lis3lv02d_remove(struct acpi_device *device, int type) 190 + { 191 + if (!device) 192 + return -EINVAL; 193 + 194 + lis3lv02d_joystick_disable(); 195 + lis3lv02d_poweroff(device->handle); 196 + 197 + return lis3lv02d_remove_fs(); 198 + } 199 + 200 + 201 + #ifdef CONFIG_PM 202 + static int lis3lv02d_suspend(struct acpi_device *device, pm_message_t state) 203 + { 204 + /* make sure the device is off when we suspend */ 205 + lis3lv02d_poweroff(device->handle); 206 + return 0; 207 + } 208 + 209 + static int lis3lv02d_resume(struct acpi_device *device) 210 + { 211 + /* put back the device in the right state (ACPI might turn it on) */ 212 + mutex_lock(&adev.lock); 213 + if (adev.usage > 0) 214 + lis3lv02d_poweron(device->handle); 215 + else 216 + lis3lv02d_poweroff(device->handle); 217 + mutex_unlock(&adev.lock); 218 + return 0; 219 + } 220 + #else 221 + #define lis3lv02d_suspend NULL 222 + #define lis3lv02d_resume NULL 223 + #endif 224 + 225 + /* For the HP MDPS aka 3D Driveguard */ 226 + static struct acpi_driver lis3lv02d_driver = { 227 + .name = DRIVER_NAME, 228 + .class = ACPI_MDPS_CLASS, 229 + .ids = lis3lv02d_device_ids, 230 + .ops = { 231 + .add = lis3lv02d_add, 232 + .remove = lis3lv02d_remove, 233 + .suspend = lis3lv02d_suspend, 234 + .resume = lis3lv02d_resume, 235 + } 236 + }; 237 + 238 + static int __init lis3lv02d_init_module(void) 239 + { 240 + int ret; 241 + 242 + if (acpi_disabled) 243 + return -ENODEV; 244 + 245 + ret = acpi_bus_register_driver(&lis3lv02d_driver); 246 + if (ret < 0) 247 + return ret; 248 + 249 + printk(KERN_INFO DRIVER_NAME " driver loaded.\n"); 250 + 251 + return 0; 252 + } 253 + 254 + static void __exit lis3lv02d_exit_module(void) 255 + { 256 + acpi_bus_unregister_driver(&lis3lv02d_driver); 257 + } 258 + 259 + MODULE_DESCRIPTION("Glue between LIS3LV02Dx and HP ACPI BIOS"); 260 + MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek"); 261 + MODULE_LICENSE("GPL"); 262 + 263 + module_init(lis3lv02d_init_module); 264 + module_exit(lis3lv02d_exit_module); 265 +
+24 -249
drivers/hwmon/lis3lv02d.c
··· 3 3 * 4 4 * Copyright (C) 2007-2008 Yan Burman 5 5 * Copyright (C) 2008 Eric Piel 6 + * Copyright (C) 2008 Pavel Machek 6 7 * 7 8 * This program is free software; you can redistribute it and/or modify 8 9 * it under the terms of the GNU General Public License as published by ··· 40 39 #include "lis3lv02d.h" 41 40 42 41 #define DRIVER_NAME "lis3lv02d" 43 - #define ACPI_MDPS_CLASS "accelerometer" 44 42 45 43 /* joystick device poll interval in milliseconds */ 46 44 #define MDPS_POLL_INTERVAL 50 ··· 55 55 /* Maximum value our axis may get for the input device (signed 12 bits) */ 56 56 #define MDPS_MAX_VAL 2048 57 57 58 - struct axis_conversion { 59 - s8 x; 60 - s8 y; 61 - s8 z; 62 - }; 58 + struct acpi_lis3lv02d adev; 59 + EXPORT_SYMBOL_GPL(adev); 63 60 64 - struct acpi_lis3lv02d { 65 - struct acpi_device *device; /* The ACPI device */ 66 - struct input_dev *idev; /* input device */ 67 - struct task_struct *kthread; /* kthread for input */ 68 - struct mutex lock; 69 - struct platform_device *pdev; /* platform device */ 70 - atomic_t count; /* interrupt count after last read */ 71 - int xcalib; /* calibrated null value for x */ 72 - int ycalib; /* calibrated null value for y */ 73 - int zcalib; /* calibrated null value for z */ 74 - unsigned char is_on; /* whether the device is on or off */ 75 - unsigned char usage; /* usage counter */ 76 - struct axis_conversion ac; /* hw -> logical axis */ 77 - }; 78 - 79 - static struct acpi_lis3lv02d adev; 80 - 81 - static int lis3lv02d_remove_fs(void); 82 61 static int lis3lv02d_add_fs(struct acpi_device *device); 83 - 84 - /* For automatic insertion of the module */ 85 - static struct acpi_device_id lis3lv02d_device_ids[] = { 86 - {"HPQ0004", 0}, /* HP Mobile Data Protection System PNP */ 87 - {"", 0}, 88 - }; 89 - MODULE_DEVICE_TABLE(acpi, lis3lv02d_device_ids); 90 - 91 - /** 92 - * lis3lv02d_acpi_init - ACPI _INI method: initialize the device. 93 - * @handle: the handle of the device 94 - * 95 - * Returns AE_OK on success. 96 - */ 97 - static inline acpi_status lis3lv02d_acpi_init(acpi_handle handle) 98 - { 99 - return acpi_evaluate_object(handle, METHOD_NAME__INI, NULL, NULL); 100 - } 101 - 102 - /** 103 - * lis3lv02d_acpi_read - ACPI ALRD method: read a register 104 - * @handle: the handle of the device 105 - * @reg: the register to read 106 - * @ret: result of the operation 107 - * 108 - * Returns AE_OK on success. 109 - */ 110 - static acpi_status lis3lv02d_acpi_read(acpi_handle handle, int reg, u8 *ret) 111 - { 112 - union acpi_object arg0 = { ACPI_TYPE_INTEGER }; 113 - struct acpi_object_list args = { 1, &arg0 }; 114 - unsigned long long lret; 115 - acpi_status status; 116 - 117 - arg0.integer.value = reg; 118 - 119 - status = acpi_evaluate_integer(handle, "ALRD", &args, &lret); 120 - *ret = lret; 121 - return status; 122 - } 123 - 124 - /** 125 - * lis3lv02d_acpi_write - ACPI ALWR method: write to a register 126 - * @handle: the handle of the device 127 - * @reg: the register to write to 128 - * @val: the value to write 129 - * 130 - * Returns AE_OK on success. 131 - */ 132 - static acpi_status lis3lv02d_acpi_write(acpi_handle handle, int reg, u8 val) 133 - { 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 - return acpi_evaluate_integer(handle, "ALWR", &args, &ret); 144 - } 145 62 146 63 static s16 lis3lv02d_read_16(acpi_handle handle, int reg) 147 64 { 148 65 u8 lo, hi; 149 66 150 - lis3lv02d_acpi_read(handle, reg, &lo); 151 - lis3lv02d_acpi_read(handle, reg + 1, &hi); 67 + adev.read(handle, reg, &lo); 68 + adev.read(handle, reg + 1, &hi); 152 69 /* In "12 bit right justified" mode, bit 6, bit 7, bit 8 = bit 5 */ 153 70 return (s16)((hi << 8) | lo); 154 71 } ··· 107 190 *z = lis3lv02d_get_axis(adev.ac.z, position); 108 191 } 109 192 110 - static inline void lis3lv02d_poweroff(acpi_handle handle) 193 + void lis3lv02d_poweroff(acpi_handle handle) 111 194 { 112 195 adev.is_on = 0; 113 196 /* disable X,Y,Z axis and power down */ 114 - lis3lv02d_acpi_write(handle, CTRL_REG1, 0x00); 197 + adev.write(handle, CTRL_REG1, 0x00); 115 198 } 199 + EXPORT_SYMBOL_GPL(lis3lv02d_poweroff); 116 200 117 - static void lis3lv02d_poweron(acpi_handle handle) 201 + void lis3lv02d_poweron(acpi_handle handle) 118 202 { 119 203 u8 val; 120 204 121 205 adev.is_on = 1; 122 - lis3lv02d_acpi_init(handle); 123 - lis3lv02d_acpi_write(handle, FF_WU_CFG, 0); 206 + adev.init(handle); 207 + adev.write(handle, FF_WU_CFG, 0); 124 208 /* 125 209 * BDU: LSB and MSB values are not updated until both have been read. 126 210 * So the value read will always be correct. 127 211 * IEN: Interrupt for free-fall and DD, not for data-ready. 128 212 */ 129 - lis3lv02d_acpi_read(handle, CTRL_REG2, &val); 213 + adev.read(handle, CTRL_REG2, &val); 130 214 val |= CTRL2_BDU | CTRL2_IEN; 131 - lis3lv02d_acpi_write(handle, CTRL_REG2, val); 215 + adev.write(handle, CTRL_REG2, val); 132 216 } 133 - 134 - #ifdef CONFIG_PM 135 - static int lis3lv02d_suspend(struct acpi_device *device, pm_message_t state) 136 - { 137 - /* make sure the device is off when we suspend */ 138 - lis3lv02d_poweroff(device->handle); 139 - return 0; 140 - } 141 - 142 - static int lis3lv02d_resume(struct acpi_device *device) 143 - { 144 - /* put back the device in the right state (ACPI might turn it on) */ 145 - mutex_lock(&adev.lock); 146 - if (adev.usage > 0) 147 - lis3lv02d_poweron(device->handle); 148 - else 149 - lis3lv02d_poweroff(device->handle); 150 - mutex_unlock(&adev.lock); 151 - return 0; 152 - } 153 - #else 154 - #define lis3lv02d_suspend NULL 155 - #define lis3lv02d_resume NULL 156 - #endif 157 - 217 + EXPORT_SYMBOL_GPL(lis3lv02d_poweron); 158 218 159 219 /* 160 220 * To be called before starting to use the device. It makes sure that the ··· 209 315 lis3lv02d_get_xyz(adev.device->handle, &adev.xcalib, &adev.ycalib, &adev.zcalib); 210 316 } 211 317 212 - static int lis3lv02d_joystick_enable(void) 318 + int lis3lv02d_joystick_enable(void) 213 319 { 214 320 int err; 215 321 ··· 243 349 244 350 return err; 245 351 } 352 + EXPORT_SYMBOL_GPL(lis3lv02d_joystick_enable); 246 353 247 - static void lis3lv02d_joystick_disable(void) 354 + void lis3lv02d_joystick_disable(void) 248 355 { 249 356 if (!adev.idev) 250 357 return; ··· 253 358 input_unregister_device(adev.idev); 254 359 adev.idev = NULL; 255 360 } 256 - 361 + EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable); 257 362 258 363 /* 259 364 * Initialise the accelerometer and the various subsystems. 260 365 * Should be rather independant of the bus system. 261 366 */ 262 - static int lis3lv02d_init_device(struct acpi_lis3lv02d *dev) 367 + int lis3lv02d_init_device(struct acpi_lis3lv02d *dev) 263 368 { 264 369 mutex_init(&dev->lock); 265 370 lis3lv02d_add_fs(dev->device); ··· 271 376 lis3lv02d_decrease_use(dev); 272 377 return 0; 273 378 } 274 - 275 - static int lis3lv02d_dmi_matched(const struct dmi_system_id *dmi) 276 - { 277 - adev.ac = *((struct axis_conversion *)dmi->driver_data); 278 - printk(KERN_INFO DRIVER_NAME ": hardware type %s found.\n", dmi->ident); 279 - 280 - return 1; 281 - } 282 - 283 - /* Represents, for each axis seen by userspace, the corresponding hw axis (+1). 284 - * If the value is negative, the opposite of the hw value is used. */ 285 - static struct axis_conversion lis3lv02d_axis_normal = {1, 2, 3}; 286 - static struct axis_conversion lis3lv02d_axis_y_inverted = {1, -2, 3}; 287 - static struct axis_conversion lis3lv02d_axis_x_inverted = {-1, 2, 3}; 288 - static struct axis_conversion lis3lv02d_axis_z_inverted = {1, 2, -3}; 289 - static struct axis_conversion lis3lv02d_axis_xy_rotated_left = {-2, 1, 3}; 290 - static struct axis_conversion lis3lv02d_axis_xy_swap_inverted = {-2, -1, 3}; 291 - 292 - #define AXIS_DMI_MATCH(_ident, _name, _axis) { \ 293 - .ident = _ident, \ 294 - .callback = lis3lv02d_dmi_matched, \ 295 - .matches = { \ 296 - DMI_MATCH(DMI_PRODUCT_NAME, _name) \ 297 - }, \ 298 - .driver_data = &lis3lv02d_axis_##_axis \ 299 - } 300 - static struct dmi_system_id lis3lv02d_dmi_ids[] = { 301 - /* product names are truncated to match all kinds of a same model */ 302 - AXIS_DMI_MATCH("NC64x0", "HP Compaq nc64", x_inverted), 303 - AXIS_DMI_MATCH("NC84x0", "HP Compaq nc84", z_inverted), 304 - AXIS_DMI_MATCH("NX9420", "HP Compaq nx9420", x_inverted), 305 - AXIS_DMI_MATCH("NW9440", "HP Compaq nw9440", x_inverted), 306 - AXIS_DMI_MATCH("NC2510", "HP Compaq 2510", y_inverted), 307 - AXIS_DMI_MATCH("NC8510", "HP Compaq 8510", xy_swap_inverted), 308 - AXIS_DMI_MATCH("HP2133", "HP 2133", xy_rotated_left), 309 - { NULL, } 310 - /* Laptop models without axis info (yet): 311 - * "NC651xx" "HP Compaq 651" 312 - * "NC671xx" "HP Compaq 671" 313 - * "NC6910" "HP Compaq 6910" 314 - * HP Compaq 8710x Notebook PC / Mobile Workstation 315 - * "NC2400" "HP Compaq nc2400" 316 - * "NX74x0" "HP Compaq nx74" 317 - * "NX6325" "HP Compaq nx6325" 318 - * "NC4400" "HP Compaq nc4400" 319 - */ 320 - }; 321 - 322 - static int lis3lv02d_add(struct acpi_device *device) 323 - { 324 - u8 val; 325 - 326 - if (!device) 327 - return -EINVAL; 328 - 329 - adev.device = device; 330 - strcpy(acpi_device_name(device), DRIVER_NAME); 331 - strcpy(acpi_device_class(device), ACPI_MDPS_CLASS); 332 - device->driver_data = &adev; 333 - 334 - lis3lv02d_acpi_read(device->handle, WHO_AM_I, &val); 335 - if ((val != LIS3LV02DL_ID) && (val != LIS302DL_ID)) { 336 - printk(KERN_ERR DRIVER_NAME 337 - ": Accelerometer chip not LIS3LV02D{L,Q}\n"); 338 - } 339 - 340 - /* If possible use a "standard" axes order */ 341 - if (dmi_check_system(lis3lv02d_dmi_ids) == 0) { 342 - printk(KERN_INFO DRIVER_NAME ": laptop model unknown, " 343 - "using default axes configuration\n"); 344 - adev.ac = lis3lv02d_axis_normal; 345 - } 346 - 347 - return lis3lv02d_init_device(&adev); 348 - } 349 - 350 - static int lis3lv02d_remove(struct acpi_device *device, int type) 351 - { 352 - if (!device) 353 - return -EINVAL; 354 - 355 - lis3lv02d_joystick_disable(); 356 - lis3lv02d_poweroff(device->handle); 357 - 358 - return lis3lv02d_remove_fs(); 359 - } 360 - 379 + EXPORT_SYMBOL_GPL(lis3lv02d_init_device); 361 380 362 381 /* Sysfs stuff */ 363 382 static ssize_t lis3lv02d_position_show(struct device *dev, ··· 310 501 int val; 311 502 312 503 lis3lv02d_increase_use(&adev); 313 - lis3lv02d_acpi_read(adev.device->handle, CTRL_REG1, &ctrl); 504 + adev.read(adev.device->handle, CTRL_REG1, &ctrl); 314 505 lis3lv02d_decrease_use(&adev); 315 506 val = (ctrl & (CTRL1_DF0 | CTRL1_DF1)) >> 4; 316 507 return sprintf(buf, "%d\n", lis3lv02dl_df_val[val]); ··· 332 523 .attrs = lis3lv02d_attributes 333 524 }; 334 525 526 + 335 527 static int lis3lv02d_add_fs(struct acpi_device *device) 336 528 { 337 529 adev.pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0); ··· 342 532 return sysfs_create_group(&adev.pdev->dev.kobj, &lis3lv02d_attribute_group); 343 533 } 344 534 345 - static int lis3lv02d_remove_fs(void) 535 + int lis3lv02d_remove_fs(void) 346 536 { 347 537 sysfs_remove_group(&adev.pdev->dev.kobj, &lis3lv02d_attribute_group); 348 538 platform_device_unregister(adev.pdev); 349 539 return 0; 350 540 } 351 - 352 - /* For the HP MDPS aka 3D Driveguard */ 353 - static struct acpi_driver lis3lv02d_driver = { 354 - .name = DRIVER_NAME, 355 - .class = ACPI_MDPS_CLASS, 356 - .ids = lis3lv02d_device_ids, 357 - .ops = { 358 - .add = lis3lv02d_add, 359 - .remove = lis3lv02d_remove, 360 - .suspend = lis3lv02d_suspend, 361 - .resume = lis3lv02d_resume, 362 - } 363 - }; 364 - 365 - static int __init lis3lv02d_init_module(void) 366 - { 367 - int ret; 368 - 369 - if (acpi_disabled) 370 - return -ENODEV; 371 - 372 - ret = acpi_bus_register_driver(&lis3lv02d_driver); 373 - if (ret < 0) 374 - return ret; 375 - 376 - printk(KERN_INFO DRIVER_NAME " driver loaded.\n"); 377 - 378 - return 0; 379 - } 380 - 381 - static void __exit lis3lv02d_exit_module(void) 382 - { 383 - acpi_bus_unregister_driver(&lis3lv02d_driver); 384 - } 541 + EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs); 385 542 386 543 MODULE_DESCRIPTION("ST LIS3LV02Dx three-axis digital accelerometer driver"); 387 544 MODULE_AUTHOR("Yan Burman and Eric Piel"); 388 545 MODULE_LICENSE("GPL"); 389 546 390 - module_init(lis3lv02d_init_module); 391 - module_exit(lis3lv02d_exit_module);
+34 -1
drivers/hwmon/lis3lv02d.h
··· 23 23 * The actual chip is STMicroelectronics LIS3LV02DL or LIS3LV02DQ that seems to 24 24 * be connected via SPI. There exists also several similar chips (such as LIS302DL or 25 25 * LIS3L02DQ) but not in the HP laptops and they have slightly different registers. 26 - * They can also be connected via I²C. 26 + * They can also be connected via I²C. 27 27 */ 28 28 29 29 #define LIS3LV02DL_ID 0x3A /* Also the LIS3LV02DQ */ ··· 147 147 DD_SRC_IA = 0x40, 148 148 }; 149 149 150 + struct axis_conversion { 151 + s8 x; 152 + s8 y; 153 + s8 z; 154 + }; 155 + 156 + struct acpi_lis3lv02d { 157 + struct acpi_device *device; /* The ACPI device */ 158 + acpi_status (*init) (acpi_handle handle); 159 + acpi_status (*write) (acpi_handle handle, int reg, u8 val); 160 + acpi_status (*read) (acpi_handle handle, int reg, u8 *ret); 161 + 162 + struct input_dev *idev; /* input device */ 163 + struct task_struct *kthread; /* kthread for input */ 164 + struct mutex lock; 165 + struct platform_device *pdev; /* platform device */ 166 + atomic_t count; /* interrupt count after last read */ 167 + int xcalib; /* calibrated null value for x */ 168 + int ycalib; /* calibrated null value for y */ 169 + int zcalib; /* calibrated null value for z */ 170 + unsigned char is_on; /* whether the device is on or off */ 171 + unsigned char usage; /* usage counter */ 172 + struct axis_conversion ac; /* hw -> logical axis */ 173 + }; 174 + 175 + int lis3lv02d_init_device(struct acpi_lis3lv02d *dev); 176 + int lis3lv02d_joystick_enable(void); 177 + void lis3lv02d_joystick_disable(void); 178 + void lis3lv02d_poweroff(acpi_handle handle); 179 + void lis3lv02d_poweron(acpi_handle handle); 180 + int lis3lv02d_remove_fs(void); 181 + 182 + extern struct acpi_lis3lv02d adev;