diff options
-rw-r--r-- | drivers/hwmon/lis3lv02d.c | 67 | ||||
-rw-r--r-- | drivers/hwmon/lis3lv02d.h | 14 | ||||
-rw-r--r-- | include/linux/lis3lv02d.h | 3 |
3 files changed, 81 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); |
diff --git a/include/linux/lis3lv02d.h b/include/linux/lis3lv02d.h index 89701355c74f..f1ca0dcc1628 100644 --- a/include/linux/lis3lv02d.h +++ b/include/linux/lis3lv02d.h | |||
@@ -55,6 +55,9 @@ struct lis3lv02d_platform_data { | |||
55 | s8 axis_z; | 55 | s8 axis_z; |
56 | int (*setup_resources)(void); | 56 | int (*setup_resources)(void); |
57 | int (*release_resources)(void); | 57 | int (*release_resources)(void); |
58 | /* Limits for selftest are specified in chip data sheet */ | ||
59 | s16 st_min_limits[3]; /* min pass limit x, y, z */ | ||
60 | s16 st_max_limits[3]; /* max pass limit x, y, z */ | ||
58 | }; | 61 | }; |
59 | 62 | ||
60 | #endif /* __LIS3LV02D_H_ */ | 63 | #endif /* __LIS3LV02D_H_ */ |