aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/hwmon/lis3lv02d.c67
-rw-r--r--drivers/hwmon/lis3lv02d.h14
-rw-r--r--include/linux/lis3lv02d.h3
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
138static 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, &reg);
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 */
182fail:
183 mutex_unlock(&lis3->mutex);
184 return ret;
185}
186
136void lis3lv02d_poweroff(struct lis3lv02d *lis3) 187void 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)
365EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable); 416EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable);
366 417
367/* Sysfs stuff */ 418/* Sysfs stuff */
419static 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
368static ssize_t lis3lv02d_position_show(struct device *dev, 430static 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
459static DEVICE_ATTR(selftest, S_IRUSR, lis3lv02d_selftest_show, NULL);
397static DEVICE_ATTR(position, S_IRUGO, lis3lv02d_position_show, NULL); 460static DEVICE_ATTR(position, S_IRUGO, lis3lv02d_position_show, NULL);
398static DEVICE_ATTR(calibrate, S_IRUGO|S_IWUSR, lis3lv02d_calibrate_show, 461static DEVICE_ATTR(calibrate, S_IRUGO|S_IWUSR, lis3lv02d_calibrate_show,
399 lis3lv02d_calibrate_store); 462 lis3lv02d_calibrate_store);
400static DEVICE_ATTR(rate, S_IRUGO, lis3lv02d_rate_show, NULL); 463static DEVICE_ATTR(rate, S_IRUGO, lis3lv02d_rate_show, NULL);
401 464
402static struct attribute *lis3lv02d_attributes[] = { 465static 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);
507MODULE_DESCRIPTION("ST LIS3LV02Dx three-axis digital accelerometer driver"); 573MODULE_DESCRIPTION("ST LIS3LV02Dx three-axis digital accelerometer driver");
508MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek"); 574MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek");
509MODULE_LICENSE("GPL"); 575MODULE_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
101enum lis3lv02d_ctrl1 { 101enum 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 */
113enum 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
112enum lis3lv02d_ctrl2 { 121enum 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
223int lis3lv02d_init_device(struct lis3lv02d *lis3); 233int 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_ */