diff options
Diffstat (limited to 'drivers/hwmon/hp_accel.c')
| -rw-r--r-- | drivers/hwmon/hp_accel.c | 85 |
1 files changed, 81 insertions, 4 deletions
diff --git a/drivers/hwmon/hp_accel.c b/drivers/hwmon/hp_accel.c index abf4dfc8ec22..29c83b5b9697 100644 --- a/drivers/hwmon/hp_accel.c +++ b/drivers/hwmon/hp_accel.c | |||
| @@ -166,6 +166,18 @@ static struct axis_conversion lis3lv02d_axis_xy_swap_yz_inverted = {2, -1, -3}; | |||
| 166 | }, \ | 166 | }, \ |
| 167 | .driver_data = &lis3lv02d_axis_##_axis \ | 167 | .driver_data = &lis3lv02d_axis_##_axis \ |
| 168 | } | 168 | } |
| 169 | |||
| 170 | #define AXIS_DMI_MATCH2(_ident, _class1, _name1, \ | ||
| 171 | _class2, _name2, \ | ||
| 172 | _axis) { \ | ||
| 173 | .ident = _ident, \ | ||
| 174 | .callback = lis3lv02d_dmi_matched, \ | ||
| 175 | .matches = { \ | ||
| 176 | DMI_MATCH(DMI_##_class1, _name1), \ | ||
| 177 | DMI_MATCH(DMI_##_class2, _name2), \ | ||
| 178 | }, \ | ||
| 179 | .driver_data = &lis3lv02d_axis_##_axis \ | ||
| 180 | } | ||
| 169 | static struct dmi_system_id lis3lv02d_dmi_ids[] = { | 181 | static struct dmi_system_id lis3lv02d_dmi_ids[] = { |
| 170 | /* product names are truncated to match all kinds of a same model */ | 182 | /* product names are truncated to match all kinds of a same model */ |
| 171 | AXIS_DMI_MATCH("NC64x0", "HP Compaq nc64", x_inverted), | 183 | AXIS_DMI_MATCH("NC64x0", "HP Compaq nc64", x_inverted), |
| @@ -179,6 +191,16 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = { | |||
| 179 | AXIS_DMI_MATCH("NC673x", "HP Compaq 673", xy_rotated_left_usd), | 191 | AXIS_DMI_MATCH("NC673x", "HP Compaq 673", xy_rotated_left_usd), |
| 180 | AXIS_DMI_MATCH("NC651xx", "HP Compaq 651", xy_rotated_right), | 192 | AXIS_DMI_MATCH("NC651xx", "HP Compaq 651", xy_rotated_right), |
| 181 | AXIS_DMI_MATCH("NC671xx", "HP Compaq 671", xy_swap_yz_inverted), | 193 | AXIS_DMI_MATCH("NC671xx", "HP Compaq 671", xy_swap_yz_inverted), |
| 194 | /* Intel-based HP Pavilion dv5 */ | ||
| 195 | AXIS_DMI_MATCH2("HPDV5_I", | ||
| 196 | PRODUCT_NAME, "HP Pavilion dv5", | ||
| 197 | BOARD_NAME, "3603", | ||
| 198 | x_inverted), | ||
| 199 | /* AMD-based HP Pavilion dv5 */ | ||
| 200 | AXIS_DMI_MATCH2("HPDV5_A", | ||
| 201 | PRODUCT_NAME, "HP Pavilion dv5", | ||
| 202 | BOARD_NAME, "3600", | ||
| 203 | y_inverted), | ||
| 182 | { NULL, } | 204 | { NULL, } |
| 183 | /* Laptop models without axis info (yet): | 205 | /* Laptop models without axis info (yet): |
| 184 | * "NC6910" "HP Compaq 6910" | 206 | * "NC6910" "HP Compaq 6910" |
| @@ -213,9 +235,49 @@ static struct delayed_led_classdev hpled_led = { | |||
| 213 | .set_brightness = hpled_set, | 235 | .set_brightness = hpled_set, |
| 214 | }; | 236 | }; |
| 215 | 237 | ||
| 238 | static acpi_status | ||
| 239 | lis3lv02d_get_resource(struct acpi_resource *resource, void *context) | ||
| 240 | { | ||
| 241 | if (resource->type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) { | ||
| 242 | struct acpi_resource_extended_irq *irq; | ||
| 243 | u32 *device_irq = context; | ||
| 244 | |||
| 245 | irq = &resource->data.extended_irq; | ||
| 246 | *device_irq = irq->interrupts[0]; | ||
| 247 | } | ||
| 248 | |||
| 249 | return AE_OK; | ||
| 250 | } | ||
| 251 | |||
| 252 | static void lis3lv02d_enum_resources(struct acpi_device *device) | ||
| 253 | { | ||
| 254 | acpi_status status; | ||
| 255 | |||
| 256 | status = acpi_walk_resources(device->handle, METHOD_NAME__CRS, | ||
| 257 | lis3lv02d_get_resource, &adev.irq); | ||
| 258 | if (ACPI_FAILURE(status)) | ||
| 259 | printk(KERN_DEBUG DRIVER_NAME ": Error getting resources\n"); | ||
| 260 | } | ||
| 261 | |||
| 262 | static s16 lis3lv02d_read_16(acpi_handle handle, int reg) | ||
| 263 | { | ||
| 264 | u8 lo, hi; | ||
| 265 | |||
| 266 | adev.read(handle, reg - 1, &lo); | ||
| 267 | adev.read(handle, reg, &hi); | ||
| 268 | /* In "12 bit right justified" mode, bit 6, bit 7, bit 8 = bit 5 */ | ||
| 269 | return (s16)((hi << 8) | lo); | ||
| 270 | } | ||
| 271 | |||
| 272 | static s16 lis3lv02d_read_8(acpi_handle handle, int reg) | ||
| 273 | { | ||
| 274 | s8 lo; | ||
| 275 | adev.read(handle, reg, &lo); | ||
| 276 | return lo; | ||
| 277 | } | ||
| 278 | |||
| 216 | static int lis3lv02d_add(struct acpi_device *device) | 279 | static int lis3lv02d_add(struct acpi_device *device) |
| 217 | { | 280 | { |
| 218 | u8 val; | ||
| 219 | int ret; | 281 | int ret; |
| 220 | 282 | ||
| 221 | if (!device) | 283 | if (!device) |
| @@ -229,10 +291,22 @@ static int lis3lv02d_add(struct acpi_device *device) | |||
| 229 | strcpy(acpi_device_class(device), ACPI_MDPS_CLASS); | 291 | strcpy(acpi_device_class(device), ACPI_MDPS_CLASS); |
| 230 | device->driver_data = &adev; | 292 | device->driver_data = &adev; |
| 231 | 293 | ||
| 232 | lis3lv02d_acpi_read(device->handle, WHO_AM_I, &val); | 294 | lis3lv02d_acpi_read(device->handle, WHO_AM_I, &adev.whoami); |
| 233 | if ((val != LIS3LV02DL_ID) && (val != LIS302DL_ID)) { | 295 | switch (adev.whoami) { |
| 296 | case LIS_DOUBLE_ID: | ||
| 297 | printk(KERN_INFO DRIVER_NAME ": 2-byte sensor found\n"); | ||
| 298 | adev.read_data = lis3lv02d_read_16; | ||
| 299 | adev.mdps_max_val = 2048; | ||
| 300 | break; | ||
| 301 | case LIS_SINGLE_ID: | ||
| 302 | printk(KERN_INFO DRIVER_NAME ": 1-byte sensor found\n"); | ||
| 303 | adev.read_data = lis3lv02d_read_8; | ||
| 304 | adev.mdps_max_val = 128; | ||
| 305 | break; | ||
| 306 | default: | ||
| 234 | printk(KERN_ERR DRIVER_NAME | 307 | printk(KERN_ERR DRIVER_NAME |
| 235 | ": Accelerometer chip not LIS3LV02D{L,Q}\n"); | 308 | ": unknown sensor type 0x%X\n", adev.whoami); |
| 309 | return -EINVAL; | ||
| 236 | } | 310 | } |
| 237 | 311 | ||
| 238 | /* If possible use a "standard" axes order */ | 312 | /* If possible use a "standard" axes order */ |
| @@ -247,6 +321,9 @@ static int lis3lv02d_add(struct acpi_device *device) | |||
| 247 | if (ret) | 321 | if (ret) |
| 248 | return ret; | 322 | return ret; |
| 249 | 323 | ||
| 324 | /* obtain IRQ number of our device from ACPI */ | ||
| 325 | lis3lv02d_enum_resources(adev.device); | ||
| 326 | |||
| 250 | ret = lis3lv02d_init_device(&adev); | 327 | ret = lis3lv02d_init_device(&adev); |
| 251 | if (ret) { | 328 | if (ret) { |
| 252 | flush_work(&hpled_led.work); | 329 | flush_work(&hpled_led.work); |
