diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/hwmon/lis3lv02d.c | 67 | ||||
| -rw-r--r-- | drivers/hwmon/lis3lv02d.h | 14 |
2 files changed, 78 insertions, 3 deletions
diff --git a/drivers/hwmon/lis3lv02d.c b/drivers/hwmon/lis3lv02d.c index 39b9ac8e18ed..55ec883e2026 100644 --- a/drivers/hwmon/lis3lv02d.c +++ b/drivers/hwmon/lis3lv02d.c | |||
| @@ -106,9 +106,11 @@ static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z) | |||
| 106 | { | 106 | { |
| 107 | int position[3]; | 107 | int position[3]; |
| 108 | 108 | ||
| 109 | mutex_lock(&lis3->mutex); | ||
| 109 | position[0] = lis3->read_data(lis3, OUTX); | 110 | position[0] = lis3->read_data(lis3, OUTX); |
| 110 | position[1] = lis3->read_data(lis3, OUTY); | 111 | position[1] = lis3->read_data(lis3, OUTY); |
| 111 | position[2] = lis3->read_data(lis3, OUTZ); | 112 | position[2] = lis3->read_data(lis3, OUTZ); |
| 113 | mutex_unlock(&lis3->mutex); | ||
| 112 | 114 | ||
| 113 | *x = lis3lv02d_get_axis(lis3->ac.x, position); | 115 | *x = lis3lv02d_get_axis(lis3->ac.x, position); |
| 114 | *y = lis3lv02d_get_axis(lis3->ac.y, position); | 116 | *y = lis3lv02d_get_axis(lis3->ac.y, position); |
| @@ -133,6 +135,55 @@ static int lis3lv02d_get_odr(void) | |||
| 133 | return val; | 135 | return val; |
| 134 | } | 136 | } |
| 135 | 137 | ||
| 138 | static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3]) | ||
| 139 | { | ||
| 140 | u8 reg; | ||
| 141 | s16 x, y, z; | ||
| 142 | u8 selftest; | ||
| 143 | int ret; | ||
| 144 | |||
| 145 | mutex_lock(&lis3->mutex); | ||
| 146 | if (lis3_dev.whoami == WAI_12B) | ||
| 147 | selftest = CTRL1_ST; | ||
| 148 | else | ||
| 149 | selftest = CTRL1_STP; | ||
| 150 | |||
| 151 | lis3->read(lis3, CTRL_REG1, ®); | ||
| 152 | lis3->write(lis3, CTRL_REG1, (reg | selftest)); | ||
| 153 | msleep(lis3->pwron_delay / lis3lv02d_get_odr()); | ||
| 154 | |||
| 155 | /* Read directly to avoid axis remap */ | ||
| 156 | x = lis3->read_data(lis3, OUTX); | ||
| 157 | y = lis3->read_data(lis3, OUTY); | ||
| 158 | z = lis3->read_data(lis3, OUTZ); | ||
| 159 | |||
| 160 | /* back to normal settings */ | ||
| 161 | lis3->write(lis3, CTRL_REG1, reg); | ||
| 162 | msleep(lis3->pwron_delay / lis3lv02d_get_odr()); | ||
| 163 | |||
| 164 | results[0] = x - lis3->read_data(lis3, OUTX); | ||
| 165 | results[1] = y - lis3->read_data(lis3, OUTY); | ||
| 166 | results[2] = z - lis3->read_data(lis3, OUTZ); | ||
| 167 | |||
| 168 | ret = 0; | ||
| 169 | if (lis3->pdata) { | ||
| 170 | int i; | ||
| 171 | for (i = 0; i < 3; i++) { | ||
| 172 | /* Check against selftest acceptance limits */ | ||
| 173 | if ((results[i] < lis3->pdata->st_min_limits[i]) || | ||
| 174 | (results[i] > lis3->pdata->st_max_limits[i])) { | ||
| 175 | ret = -EIO; | ||
| 176 | goto fail; | ||
| 177 | } | ||
| 178 | } | ||
| 179 | } | ||
| 180 | |||
| 181 | /* test passed */ | ||
| 182 | fail: | ||
| 183 | mutex_unlock(&lis3->mutex); | ||
| 184 | return ret; | ||
| 185 | } | ||
| 186 | |||
| 136 | void lis3lv02d_poweroff(struct lis3lv02d *lis3) | 187 | void lis3lv02d_poweroff(struct lis3lv02d *lis3) |
| 137 | { | 188 | { |
| 138 | /* disable X,Y,Z axis and power down */ | 189 | /* disable X,Y,Z axis and power down */ |
| @@ -365,6 +416,17 @@ void lis3lv02d_joystick_disable(void) | |||
| 365 | EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable); | 416 | EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable); |
| 366 | 417 | ||
| 367 | /* Sysfs stuff */ | 418 | /* Sysfs stuff */ |
| 419 | static ssize_t lis3lv02d_selftest_show(struct device *dev, | ||
| 420 | struct device_attribute *attr, char *buf) | ||
| 421 | { | ||
| 422 | int result; | ||
| 423 | s16 values[3]; | ||
| 424 | |||
| 425 | result = lis3lv02d_selftest(&lis3_dev, values); | ||
| 426 | return sprintf(buf, "%s %d %d %d\n", result == 0 ? "OK" : "FAIL", | ||
| 427 | values[0], values[1], values[2]); | ||
| 428 | } | ||
| 429 | |||
| 368 | static ssize_t lis3lv02d_position_show(struct device *dev, | 430 | static ssize_t lis3lv02d_position_show(struct device *dev, |
| 369 | struct device_attribute *attr, char *buf) | 431 | struct device_attribute *attr, char *buf) |
| 370 | { | 432 | { |
| @@ -394,12 +456,14 @@ static ssize_t lis3lv02d_rate_show(struct device *dev, | |||
| 394 | return sprintf(buf, "%d\n", lis3lv02d_get_odr()); | 456 | return sprintf(buf, "%d\n", lis3lv02d_get_odr()); |
| 395 | } | 457 | } |
| 396 | 458 | ||
| 459 | static DEVICE_ATTR(selftest, S_IRUSR, lis3lv02d_selftest_show, NULL); | ||
| 397 | static DEVICE_ATTR(position, S_IRUGO, lis3lv02d_position_show, NULL); | 460 | static DEVICE_ATTR(position, S_IRUGO, lis3lv02d_position_show, NULL); |
| 398 | static DEVICE_ATTR(calibrate, S_IRUGO|S_IWUSR, lis3lv02d_calibrate_show, | 461 | static DEVICE_ATTR(calibrate, S_IRUGO|S_IWUSR, lis3lv02d_calibrate_show, |
| 399 | lis3lv02d_calibrate_store); | 462 | lis3lv02d_calibrate_store); |
| 400 | static DEVICE_ATTR(rate, S_IRUGO, lis3lv02d_rate_show, NULL); | 463 | static DEVICE_ATTR(rate, S_IRUGO, lis3lv02d_rate_show, NULL); |
| 401 | 464 | ||
| 402 | static struct attribute *lis3lv02d_attributes[] = { | 465 | static struct attribute *lis3lv02d_attributes[] = { |
| 466 | &dev_attr_selftest.attr, | ||
| 403 | &dev_attr_position.attr, | 467 | &dev_attr_position.attr, |
| 404 | &dev_attr_calibrate.attr, | 468 | &dev_attr_calibrate.attr, |
| 405 | &dev_attr_rate.attr, | 469 | &dev_attr_rate.attr, |
| @@ -455,6 +519,8 @@ int lis3lv02d_init_device(struct lis3lv02d *dev) | |||
| 455 | return -EINVAL; | 519 | return -EINVAL; |
| 456 | } | 520 | } |
| 457 | 521 | ||
| 522 | mutex_init(&dev->mutex); | ||
| 523 | |||
| 458 | lis3lv02d_add_fs(dev); | 524 | lis3lv02d_add_fs(dev); |
| 459 | lis3lv02d_poweron(dev); | 525 | lis3lv02d_poweron(dev); |
| 460 | 526 | ||
| @@ -507,4 +573,3 @@ EXPORT_SYMBOL_GPL(lis3lv02d_init_device); | |||
| 507 | MODULE_DESCRIPTION("ST LIS3LV02Dx three-axis digital accelerometer driver"); | 573 | MODULE_DESCRIPTION("ST LIS3LV02Dx three-axis digital accelerometer driver"); |
| 508 | MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek"); | 574 | MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek"); |
| 509 | MODULE_LICENSE("GPL"); | 575 | MODULE_LICENSE("GPL"); |
| 510 | |||
diff --git a/drivers/hwmon/lis3lv02d.h b/drivers/hwmon/lis3lv02d.h index c57f21f45676..166794cb91a3 100644 --- a/drivers/hwmon/lis3lv02d.h +++ b/drivers/hwmon/lis3lv02d.h | |||
| @@ -98,7 +98,7 @@ enum lis3_who_am_i { | |||
| 98 | WAI_6B = 0x52, /* 6 bits: LIS331DLF - not supported */ | 98 | WAI_6B = 0x52, /* 6 bits: LIS331DLF - not supported */ |
| 99 | }; | 99 | }; |
| 100 | 100 | ||
| 101 | enum lis3lv02d_ctrl1 { | 101 | enum lis3lv02d_ctrl1_12b { |
| 102 | CTRL1_Xen = 0x01, | 102 | CTRL1_Xen = 0x01, |
| 103 | CTRL1_Yen = 0x02, | 103 | CTRL1_Yen = 0x02, |
| 104 | CTRL1_Zen = 0x04, | 104 | CTRL1_Zen = 0x04, |
| @@ -107,8 +107,17 @@ enum lis3lv02d_ctrl1 { | |||
| 107 | CTRL1_DF1 = 0x20, | 107 | CTRL1_DF1 = 0x20, |
| 108 | CTRL1_PD0 = 0x40, | 108 | CTRL1_PD0 = 0x40, |
| 109 | CTRL1_PD1 = 0x80, | 109 | CTRL1_PD1 = 0x80, |
| 110 | CTRL1_DR = 0x80, /* Data rate on 8 bits */ | ||
| 111 | }; | 110 | }; |
| 111 | |||
| 112 | /* Delta to ctrl1_12b version */ | ||
| 113 | enum lis3lv02d_ctrl1_8b { | ||
| 114 | CTRL1_STM = 0x08, | ||
| 115 | CTRL1_STP = 0x10, | ||
| 116 | CTRL1_FS = 0x20, | ||
| 117 | CTRL1_PD = 0x40, | ||
| 118 | CTRL1_DR = 0x80, | ||
| 119 | }; | ||
| 120 | |||
| 112 | enum lis3lv02d_ctrl2 { | 121 | enum lis3lv02d_ctrl2 { |
| 113 | CTRL2_DAS = 0x01, | 122 | CTRL2_DAS = 0x01, |
| 114 | CTRL2_SIM = 0x02, | 123 | CTRL2_SIM = 0x02, |
| @@ -218,6 +227,7 @@ struct lis3lv02d { | |||
| 218 | unsigned long misc_opened; /* bit0: whether the device is open */ | 227 | unsigned long misc_opened; /* bit0: whether the device is open */ |
| 219 | 228 | ||
| 220 | struct lis3lv02d_platform_data *pdata; /* for passing board config */ | 229 | struct lis3lv02d_platform_data *pdata; /* for passing board config */ |
| 230 | struct mutex mutex; /* Serialize poll and selftest */ | ||
| 221 | }; | 231 | }; |
| 222 | 232 | ||
| 223 | int lis3lv02d_init_device(struct lis3lv02d *lis3); | 233 | int lis3lv02d_init_device(struct lis3lv02d *lis3); |
