Skip to content

Commit

Permalink
lis3lv02d: support both one- and two-byte sensors
Browse files Browse the repository at this point in the history
Sensors responding with 0x3B to WHO_AM_I only have one data register per
direction, thus returning a signed byte from the position which is
occupied by the MSB in sensors responding with 0x3A.

Since multiple sensors share the reply to WHO_AM_I, we rename the defines
to better indicate what they identify (family of single and double
precision sensors).

We support both kind of sensors by checking for the sensor type on init
and defining appropriate data-access routines and sensor limits (for the
joystick) depending on what we find.

[akpm@linux-foundation.org: coding-style fixes]
Signed-off-by: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>
Acked-by: Eric Piel <Eric.Piel@tremplin-utc.net>
Cc: Pavel Machek <pavel@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Oblomov authored and torvalds committed Feb 18, 2009
1 parent ef2cfc7 commit 137bad3
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 26 deletions.
36 changes: 32 additions & 4 deletions drivers/hwmon/hp_accel.c
Original file line number Diff line number Diff line change
Expand Up @@ -237,9 +237,25 @@ static void lis3lv02d_enum_resources(struct acpi_device *device)
printk(KERN_DEBUG DRIVER_NAME ": Error getting resources\n");
}

static s16 lis3lv02d_read_16(acpi_handle handle, int reg)
{
u8 lo, hi;

adev.read(handle, reg - 1, &lo);
adev.read(handle, reg, &hi);
/* In "12 bit right justified" mode, bit 6, bit 7, bit 8 = bit 5 */
return (s16)((hi << 8) | lo);
}

static s16 lis3lv02d_read_8(acpi_handle handle, int reg)
{
s8 lo;
adev.read(handle, reg, &lo);
return lo;
}

static int lis3lv02d_add(struct acpi_device *device)
{
u8 val;
int ret;

if (!device)
Expand All @@ -253,10 +269,22 @@ static int lis3lv02d_add(struct acpi_device *device)
strcpy(acpi_device_class(device), ACPI_MDPS_CLASS);
device->driver_data = &adev;

lis3lv02d_acpi_read(device->handle, WHO_AM_I, &val);
if ((val != LIS3LV02DL_ID) && (val != LIS302DL_ID)) {
lis3lv02d_acpi_read(device->handle, WHO_AM_I, &adev.whoami);
switch (adev.whoami) {
case LIS_DOUBLE_ID:
printk(KERN_INFO DRIVER_NAME ": 2-byte sensor found\n");
adev.read_data = lis3lv02d_read_16;
adev.mdps_max_val = 2048;
break;
case LIS_SINGLE_ID:
printk(KERN_INFO DRIVER_NAME ": 1-byte sensor found\n");
adev.read_data = lis3lv02d_read_8;
adev.mdps_max_val = 128;
break;
default:
printk(KERN_ERR DRIVER_NAME
": Accelerometer chip not LIS3LV02D{L,Q}\n");
": unknown sensor type 0x%X\n", adev.whoami);
return -EINVAL;
}

/* If possible use a "standard" axes order */
Expand Down
25 changes: 6 additions & 19 deletions drivers/hwmon/lis3lv02d.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,6 @@
* joystick.
*/

/* Maximum value our axis may get for the input device (signed 12 bits) */
#define MDPS_MAX_VAL 2048

struct acpi_lis3lv02d adev = {
.misc_wait = __WAIT_QUEUE_HEAD_INITIALIZER(adev.misc_wait),
};
Expand All @@ -64,16 +61,6 @@ EXPORT_SYMBOL_GPL(adev);

static int lis3lv02d_add_fs(struct acpi_device *device);

static s16 lis3lv02d_read_16(acpi_handle handle, int reg)
{
u8 lo, hi;

adev.read(handle, reg, &lo);
adev.read(handle, reg + 1, &hi);
/* In "12 bit right justified" mode, bit 6, bit 7, bit 8 = bit 5 */
return (s16)((hi << 8) | lo);
}

/**
* lis3lv02d_get_axis - For the given axis, give the value converted
* @axis: 1,2,3 - can also be negative
Expand Down Expand Up @@ -102,9 +89,9 @@ static void lis3lv02d_get_xyz(acpi_handle handle, int *x, int *y, int *z)
{
int position[3];

position[0] = lis3lv02d_read_16(handle, OUTX_L);
position[1] = lis3lv02d_read_16(handle, OUTY_L);
position[2] = lis3lv02d_read_16(handle, OUTZ_L);
position[0] = adev.read_data(handle, OUTX);
position[1] = adev.read_data(handle, OUTY);
position[2] = adev.read_data(handle, OUTZ);

*x = lis3lv02d_get_axis(adev.ac.x, position);
*y = lis3lv02d_get_axis(adev.ac.y, position);
Expand Down Expand Up @@ -355,9 +342,9 @@ int lis3lv02d_joystick_enable(void)
adev.idev->close = lis3lv02d_joystick_close;

set_bit(EV_ABS, adev.idev->evbit);
input_set_abs_params(adev.idev, ABS_X, -MDPS_MAX_VAL, MDPS_MAX_VAL, 3, 3);
input_set_abs_params(adev.idev, ABS_Y, -MDPS_MAX_VAL, MDPS_MAX_VAL, 3, 3);
input_set_abs_params(adev.idev, ABS_Z, -MDPS_MAX_VAL, MDPS_MAX_VAL, 3, 3);
input_set_abs_params(adev.idev, ABS_X, -adev.mdps_max_val, adev.mdps_max_val, 3, 3);
input_set_abs_params(adev.idev, ABS_Y, -adev.mdps_max_val, adev.mdps_max_val, 3, 3);
input_set_abs_params(adev.idev, ABS_Z, -adev.mdps_max_val, adev.mdps_max_val, 3, 3);

err = input_register_device(adev.idev);
if (err) {
Expand Down
16 changes: 13 additions & 3 deletions drivers/hwmon/lis3lv02d.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,15 @@
/*
* The actual chip is STMicroelectronics LIS3LV02DL or LIS3LV02DQ that seems to
* be connected via SPI. There exists also several similar chips (such as LIS302DL or
* LIS3L02DQ) but not in the HP laptops and they have slightly different registers.
* LIS3L02DQ) and they have slightly different registers, but we can provide a
* common interface for all of them.
* They can also be connected via I²C.
*/

#define LIS3LV02DL_ID 0x3A /* Also the LIS3LV02DQ */
#define LIS302DL_ID 0x3B /* Also the LIS202DL! */
/* 2-byte registers */
#define LIS_DOUBLE_ID 0x3A /* LIS3LV02D[LQ] */
/* 1-byte registers */
#define LIS_SINGLE_ID 0x3B /* LIS[32]02DL and others */

enum lis3lv02d_reg {
WHO_AM_I = 0x0F,
Expand All @@ -44,10 +47,13 @@ enum lis3lv02d_reg {
STATUS_REG = 0x27,
OUTX_L = 0x28,
OUTX_H = 0x29,
OUTX = 0x29,
OUTY_L = 0x2A,
OUTY_H = 0x2B,
OUTY = 0x2B,
OUTZ_L = 0x2C,
OUTZ_H = 0x2D,
OUTZ = 0x2D,
FF_WU_CFG = 0x30,
FF_WU_SRC = 0x31,
FF_WU_ACK = 0x32,
Expand Down Expand Up @@ -159,6 +165,10 @@ struct acpi_lis3lv02d {
acpi_status (*write) (acpi_handle handle, int reg, u8 val);
acpi_status (*read) (acpi_handle handle, int reg, u8 *ret);

u8 whoami; /* 3Ah: 2-byte registries, 3Bh: 1-byte registries */
s16 (*read_data) (acpi_handle handle, int reg);
int mdps_max_val;

struct input_dev *idev; /* input device */
struct task_struct *kthread; /* kthread for input */
struct mutex lock;
Expand Down

0 comments on commit 137bad3

Please sign in to comment.