aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/lis3lv02d.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2009-12-16 12:33:49 -0500
committerIngo Molnar <mingo@elte.hu>2009-12-16 12:33:49 -0500
commitee1156c11a1121e118b0a7f2dec240f0d421b1fd (patch)
treeb8771cc5a9758af9d7410fc519227c036c222130 /drivers/hwmon/lis3lv02d.c
parentb9f8fcd55bbdb037e5332dbdb7b494f0b70861ac (diff)
parent8bea8672edfca7ec5f661cafb218f1205863b343 (diff)
Merge branch 'linus' into sched/urgent
Conflicts: kernel/sched_idletask.c Merge reason: resolve the conflicts, pick up latest changes. Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'drivers/hwmon/lis3lv02d.c')
-rw-r--r--drivers/hwmon/lis3lv02d.c231
1 files changed, 177 insertions, 54 deletions
diff --git a/drivers/hwmon/lis3lv02d.c b/drivers/hwmon/lis3lv02d.c
index cf5afb9a10ab..b2f2277cad3c 100644
--- a/drivers/hwmon/lis3lv02d.c
+++ b/drivers/hwmon/lis3lv02d.c
@@ -43,13 +43,30 @@
43#define MDPS_POLL_INTERVAL 50 43#define MDPS_POLL_INTERVAL 50
44/* 44/*
45 * The sensor can also generate interrupts (DRDY) but it's pretty pointless 45 * The sensor can also generate interrupts (DRDY) but it's pretty pointless
46 * because their are generated even if the data do not change. So it's better 46 * because they are generated even if the data do not change. So it's better
47 * to keep the interrupt for the free-fall event. The values are updated at 47 * to keep the interrupt for the free-fall event. The values are updated at
48 * 40Hz (at the lowest frequency), but as it can be pretty time consuming on 48 * 40Hz (at the lowest frequency), but as it can be pretty time consuming on
49 * some low processor, we poll the sensor only at 20Hz... enough for the 49 * some low processor, we poll the sensor only at 20Hz... enough for the
50 * joystick. 50 * joystick.
51 */ 51 */
52 52
53#define LIS3_PWRON_DELAY_WAI_12B (5000)
54#define LIS3_PWRON_DELAY_WAI_8B (3000)
55
56/*
57 * LIS3LV02D spec says 1024 LSBs corresponds 1 G -> 1LSB is 1000/1024 mG
58 * LIS302D spec says: 18 mG / digit
59 * LIS3_ACCURACY is used to increase accuracy of the intermediate
60 * calculation results.
61 */
62#define LIS3_ACCURACY 1024
63/* Sensitivity values for -2G +2G scale */
64#define LIS3_SENSITIVITY_12B ((LIS3_ACCURACY * 1000) / 1024)
65#define LIS3_SENSITIVITY_8B (18 * LIS3_ACCURACY)
66
67#define LIS3_DEFAULT_FUZZ 3
68#define LIS3_DEFAULT_FLAT 3
69
53struct lis3lv02d lis3_dev = { 70struct lis3lv02d lis3_dev = {
54 .misc_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lis3_dev.misc_wait), 71 .misc_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lis3_dev.misc_wait),
55}; 72};
@@ -65,7 +82,7 @@ static s16 lis3lv02d_read_8(struct lis3lv02d *lis3, int reg)
65 return lo; 82 return lo;
66} 83}
67 84
68static s16 lis3lv02d_read_16(struct lis3lv02d *lis3, int reg) 85static s16 lis3lv02d_read_12(struct lis3lv02d *lis3, int reg)
69{ 86{
70 u8 lo, hi; 87 u8 lo, hi;
71 88
@@ -102,16 +119,106 @@ static inline int lis3lv02d_get_axis(s8 axis, int hw_values[3])
102static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z) 119static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z)
103{ 120{
104 int position[3]; 121 int position[3];
122 int i;
105 123
124 mutex_lock(&lis3->mutex);
106 position[0] = lis3->read_data(lis3, OUTX); 125 position[0] = lis3->read_data(lis3, OUTX);
107 position[1] = lis3->read_data(lis3, OUTY); 126 position[1] = lis3->read_data(lis3, OUTY);
108 position[2] = lis3->read_data(lis3, OUTZ); 127 position[2] = lis3->read_data(lis3, OUTZ);
128 mutex_unlock(&lis3->mutex);
129
130 for (i = 0; i < 3; i++)
131 position[i] = (position[i] * lis3->scale) / LIS3_ACCURACY;
109 132
110 *x = lis3lv02d_get_axis(lis3->ac.x, position); 133 *x = lis3lv02d_get_axis(lis3->ac.x, position);
111 *y = lis3lv02d_get_axis(lis3->ac.y, position); 134 *y = lis3lv02d_get_axis(lis3->ac.y, position);
112 *z = lis3lv02d_get_axis(lis3->ac.z, position); 135 *z = lis3lv02d_get_axis(lis3->ac.z, position);
113} 136}
114 137
138/* conversion btw sampling rate and the register values */
139static int lis3_12_rates[4] = {40, 160, 640, 2560};
140static int lis3_8_rates[2] = {100, 400};
141
142/* ODR is Output Data Rate */
143static int lis3lv02d_get_odr(void)
144{
145 u8 ctrl;
146 int shift;
147
148 lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl);
149 ctrl &= lis3_dev.odr_mask;
150 shift = ffs(lis3_dev.odr_mask) - 1;
151 return lis3_dev.odrs[(ctrl >> shift)];
152}
153
154static int lis3lv02d_set_odr(int rate)
155{
156 u8 ctrl;
157 int i, len, shift;
158
159 lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl);
160 ctrl &= ~lis3_dev.odr_mask;
161 len = 1 << hweight_long(lis3_dev.odr_mask); /* # of possible values */
162 shift = ffs(lis3_dev.odr_mask) - 1;
163
164 for (i = 0; i < len; i++)
165 if (lis3_dev.odrs[i] == rate) {
166 lis3_dev.write(&lis3_dev, CTRL_REG1,
167 ctrl | (i << shift));
168 return 0;
169 }
170 return -EINVAL;
171}
172
173static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
174{
175 u8 reg;
176 s16 x, y, z;
177 u8 selftest;
178 int ret;
179
180 mutex_lock(&lis3->mutex);
181 if (lis3_dev.whoami == WAI_12B)
182 selftest = CTRL1_ST;
183 else
184 selftest = CTRL1_STP;
185
186 lis3->read(lis3, CTRL_REG1, &reg);
187 lis3->write(lis3, CTRL_REG1, (reg | selftest));
188 msleep(lis3->pwron_delay / lis3lv02d_get_odr());
189
190 /* Read directly to avoid axis remap */
191 x = lis3->read_data(lis3, OUTX);
192 y = lis3->read_data(lis3, OUTY);
193 z = lis3->read_data(lis3, OUTZ);
194
195 /* back to normal settings */
196 lis3->write(lis3, CTRL_REG1, reg);
197 msleep(lis3->pwron_delay / lis3lv02d_get_odr());
198
199 results[0] = x - lis3->read_data(lis3, OUTX);
200 results[1] = y - lis3->read_data(lis3, OUTY);
201 results[2] = z - lis3->read_data(lis3, OUTZ);
202
203 ret = 0;
204 if (lis3->pdata) {
205 int i;
206 for (i = 0; i < 3; i++) {
207 /* Check against selftest acceptance limits */
208 if ((results[i] < lis3->pdata->st_min_limits[i]) ||
209 (results[i] > lis3->pdata->st_max_limits[i])) {
210 ret = -EIO;
211 goto fail;
212 }
213 }
214 }
215
216 /* test passed */
217fail:
218 mutex_unlock(&lis3->mutex);
219 return ret;
220}
221
115void lis3lv02d_poweroff(struct lis3lv02d *lis3) 222void lis3lv02d_poweroff(struct lis3lv02d *lis3)
116{ 223{
117 /* disable X,Y,Z axis and power down */ 224 /* disable X,Y,Z axis and power down */
@@ -125,14 +232,19 @@ void lis3lv02d_poweron(struct lis3lv02d *lis3)
125 232
126 lis3->init(lis3); 233 lis3->init(lis3);
127 234
235 /* LIS3 power on delay is quite long */
236 msleep(lis3->pwron_delay / lis3lv02d_get_odr());
237
128 /* 238 /*
129 * Common configuration 239 * Common configuration
130 * BDU: LSB and MSB values are not updated until both have been read. 240 * BDU: (12 bits sensors only) LSB and MSB values are not updated until
131 * So the value read will always be correct. 241 * both have been read. So the value read will always be correct.
132 */ 242 */
133 lis3->read(lis3, CTRL_REG2, &reg); 243 if (lis3->whoami == WAI_12B) {
134 reg |= CTRL2_BDU; 244 lis3->read(lis3, CTRL_REG2, &reg);
135 lis3->write(lis3, CTRL_REG2, reg); 245 reg |= CTRL2_BDU;
246 lis3->write(lis3, CTRL_REG2, reg);
247 }
136} 248}
137EXPORT_SYMBOL_GPL(lis3lv02d_poweron); 249EXPORT_SYMBOL_GPL(lis3lv02d_poweron);
138 250
@@ -273,22 +385,17 @@ static void lis3lv02d_joystick_poll(struct input_polled_dev *pidev)
273 int x, y, z; 385 int x, y, z;
274 386
275 lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); 387 lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
276 input_report_abs(pidev->input, ABS_X, x - lis3_dev.xcalib); 388 input_report_abs(pidev->input, ABS_X, x);
277 input_report_abs(pidev->input, ABS_Y, y - lis3_dev.ycalib); 389 input_report_abs(pidev->input, ABS_Y, y);
278 input_report_abs(pidev->input, ABS_Z, z - lis3_dev.zcalib); 390 input_report_abs(pidev->input, ABS_Z, z);
279} 391 input_sync(pidev->input);
280
281
282static inline void lis3lv02d_calibrate_joystick(void)
283{
284 lis3lv02d_get_xyz(&lis3_dev,
285 &lis3_dev.xcalib, &lis3_dev.ycalib, &lis3_dev.zcalib);
286} 392}
287 393
288int lis3lv02d_joystick_enable(void) 394int lis3lv02d_joystick_enable(void)
289{ 395{
290 struct input_dev *input_dev; 396 struct input_dev *input_dev;
291 int err; 397 int err;
398 int max_val, fuzz, flat;
292 399
293 if (lis3_dev.idev) 400 if (lis3_dev.idev)
294 return -EINVAL; 401 return -EINVAL;
@@ -301,8 +408,6 @@ int lis3lv02d_joystick_enable(void)
301 lis3_dev.idev->poll_interval = MDPS_POLL_INTERVAL; 408 lis3_dev.idev->poll_interval = MDPS_POLL_INTERVAL;
302 input_dev = lis3_dev.idev->input; 409 input_dev = lis3_dev.idev->input;
303 410
304 lis3lv02d_calibrate_joystick();
305
306 input_dev->name = "ST LIS3LV02DL Accelerometer"; 411 input_dev->name = "ST LIS3LV02DL Accelerometer";
307 input_dev->phys = DRIVER_NAME "/input0"; 412 input_dev->phys = DRIVER_NAME "/input0";
308 input_dev->id.bustype = BUS_HOST; 413 input_dev->id.bustype = BUS_HOST;
@@ -310,9 +415,12 @@ int lis3lv02d_joystick_enable(void)
310 input_dev->dev.parent = &lis3_dev.pdev->dev; 415 input_dev->dev.parent = &lis3_dev.pdev->dev;
311 416
312 set_bit(EV_ABS, input_dev->evbit); 417 set_bit(EV_ABS, input_dev->evbit);
313 input_set_abs_params(input_dev, ABS_X, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3); 418 max_val = (lis3_dev.mdps_max_val * lis3_dev.scale) / LIS3_ACCURACY;
314 input_set_abs_params(input_dev, ABS_Y, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3); 419 fuzz = (LIS3_DEFAULT_FUZZ * lis3_dev.scale) / LIS3_ACCURACY;
315 input_set_abs_params(input_dev, ABS_Z, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3); 420 flat = (LIS3_DEFAULT_FLAT * lis3_dev.scale) / LIS3_ACCURACY;
421 input_set_abs_params(input_dev, ABS_X, -max_val, max_val, fuzz, flat);
422 input_set_abs_params(input_dev, ABS_Y, -max_val, max_val, fuzz, flat);
423 input_set_abs_params(input_dev, ABS_Z, -max_val, max_val, fuzz, flat);
316 424
317 err = input_register_polled_device(lis3_dev.idev); 425 err = input_register_polled_device(lis3_dev.idev);
318 if (err) { 426 if (err) {
@@ -332,11 +440,23 @@ void lis3lv02d_joystick_disable(void)
332 if (lis3_dev.irq) 440 if (lis3_dev.irq)
333 misc_deregister(&lis3lv02d_misc_device); 441 misc_deregister(&lis3lv02d_misc_device);
334 input_unregister_polled_device(lis3_dev.idev); 442 input_unregister_polled_device(lis3_dev.idev);
443 input_free_polled_device(lis3_dev.idev);
335 lis3_dev.idev = NULL; 444 lis3_dev.idev = NULL;
336} 445}
337EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable); 446EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable);
338 447
339/* Sysfs stuff */ 448/* Sysfs stuff */
449static ssize_t lis3lv02d_selftest_show(struct device *dev,
450 struct device_attribute *attr, char *buf)
451{
452 int result;
453 s16 values[3];
454
455 result = lis3lv02d_selftest(&lis3_dev, values);
456 return sprintf(buf, "%s %d %d %d\n", result == 0 ? "OK" : "FAIL",
457 values[0], values[1], values[2]);
458}
459
340static ssize_t lis3lv02d_position_show(struct device *dev, 460static ssize_t lis3lv02d_position_show(struct device *dev,
341 struct device_attribute *attr, char *buf) 461 struct device_attribute *attr, char *buf)
342{ 462{
@@ -346,41 +466,35 @@ static ssize_t lis3lv02d_position_show(struct device *dev,
346 return sprintf(buf, "(%d,%d,%d)\n", x, y, z); 466 return sprintf(buf, "(%d,%d,%d)\n", x, y, z);
347} 467}
348 468
349static ssize_t lis3lv02d_calibrate_show(struct device *dev, 469static ssize_t lis3lv02d_rate_show(struct device *dev,
350 struct device_attribute *attr, char *buf) 470 struct device_attribute *attr, char *buf)
351{ 471{
352 return sprintf(buf, "(%d,%d,%d)\n", lis3_dev.xcalib, lis3_dev.ycalib, lis3_dev.zcalib); 472 return sprintf(buf, "%d\n", lis3lv02d_get_odr());
353} 473}
354 474
355static ssize_t lis3lv02d_calibrate_store(struct device *dev, 475static ssize_t lis3lv02d_rate_set(struct device *dev,
356 struct device_attribute *attr, 476 struct device_attribute *attr, const char *buf,
357 const char *buf, size_t count) 477 size_t count)
358{ 478{
359 lis3lv02d_calibrate_joystick(); 479 unsigned long rate;
360 return count;
361}
362 480
363/* conversion btw sampling rate and the register values */ 481 if (strict_strtoul(buf, 0, &rate))
364static int lis3lv02dl_df_val[4] = {40, 160, 640, 2560}; 482 return -EINVAL;
365static ssize_t lis3lv02d_rate_show(struct device *dev,
366 struct device_attribute *attr, char *buf)
367{
368 u8 ctrl;
369 int val;
370 483
371 lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl); 484 if (lis3lv02d_set_odr(rate))
372 val = (ctrl & (CTRL1_DF0 | CTRL1_DF1)) >> 4; 485 return -EINVAL;
373 return sprintf(buf, "%d\n", lis3lv02dl_df_val[val]); 486
487 return count;
374} 488}
375 489
490static DEVICE_ATTR(selftest, S_IRUSR, lis3lv02d_selftest_show, NULL);
376static DEVICE_ATTR(position, S_IRUGO, lis3lv02d_position_show, NULL); 491static DEVICE_ATTR(position, S_IRUGO, lis3lv02d_position_show, NULL);
377static DEVICE_ATTR(calibrate, S_IRUGO|S_IWUSR, lis3lv02d_calibrate_show, 492static DEVICE_ATTR(rate, S_IRUGO | S_IWUSR, lis3lv02d_rate_show,
378 lis3lv02d_calibrate_store); 493 lis3lv02d_rate_set);
379static DEVICE_ATTR(rate, S_IRUGO, lis3lv02d_rate_show, NULL);
380 494
381static struct attribute *lis3lv02d_attributes[] = { 495static struct attribute *lis3lv02d_attributes[] = {
496 &dev_attr_selftest.attr,
382 &dev_attr_position.attr, 497 &dev_attr_position.attr,
383 &dev_attr_calibrate.attr,
384 &dev_attr_rate.attr, 498 &dev_attr_rate.attr,
385 NULL 499 NULL
386}; 500};
@@ -409,22 +523,30 @@ EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs);
409 523
410/* 524/*
411 * Initialise the accelerometer and the various subsystems. 525 * Initialise the accelerometer and the various subsystems.
412 * Should be rather independant of the bus system. 526 * Should be rather independent of the bus system.
413 */ 527 */
414int lis3lv02d_init_device(struct lis3lv02d *dev) 528int lis3lv02d_init_device(struct lis3lv02d *dev)
415{ 529{
416 dev->whoami = lis3lv02d_read_8(dev, WHO_AM_I); 530 dev->whoami = lis3lv02d_read_8(dev, WHO_AM_I);
417 531
418 switch (dev->whoami) { 532 switch (dev->whoami) {
419 case LIS_DOUBLE_ID: 533 case WAI_12B:
420 printk(KERN_INFO DRIVER_NAME ": 2-byte sensor found\n"); 534 printk(KERN_INFO DRIVER_NAME ": 12 bits sensor found\n");
421 dev->read_data = lis3lv02d_read_16; 535 dev->read_data = lis3lv02d_read_12;
422 dev->mdps_max_val = 2048; 536 dev->mdps_max_val = 2048;
537 dev->pwron_delay = LIS3_PWRON_DELAY_WAI_12B;
538 dev->odrs = lis3_12_rates;
539 dev->odr_mask = CTRL1_DF0 | CTRL1_DF1;
540 dev->scale = LIS3_SENSITIVITY_12B;
423 break; 541 break;
424 case LIS_SINGLE_ID: 542 case WAI_8B:
425 printk(KERN_INFO DRIVER_NAME ": 1-byte sensor found\n"); 543 printk(KERN_INFO DRIVER_NAME ": 8 bits sensor found\n");
426 dev->read_data = lis3lv02d_read_8; 544 dev->read_data = lis3lv02d_read_8;
427 dev->mdps_max_val = 128; 545 dev->mdps_max_val = 128;
546 dev->pwron_delay = LIS3_PWRON_DELAY_WAI_8B;
547 dev->odrs = lis3_8_rates;
548 dev->odr_mask = CTRL1_DR;
549 dev->scale = LIS3_SENSITIVITY_8B;
428 break; 550 break;
429 default: 551 default:
430 printk(KERN_ERR DRIVER_NAME 552 printk(KERN_ERR DRIVER_NAME
@@ -432,6 +554,8 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
432 return -EINVAL; 554 return -EINVAL;
433 } 555 }
434 556
557 mutex_init(&dev->mutex);
558
435 lis3lv02d_add_fs(dev); 559 lis3lv02d_add_fs(dev);
436 lis3lv02d_poweron(dev); 560 lis3lv02d_poweron(dev);
437 561
@@ -443,7 +567,7 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
443 if (dev->pdata) { 567 if (dev->pdata) {
444 struct lis3lv02d_platform_data *p = dev->pdata; 568 struct lis3lv02d_platform_data *p = dev->pdata;
445 569
446 if (p->click_flags && (dev->whoami == LIS_SINGLE_ID)) { 570 if (p->click_flags && (dev->whoami == WAI_8B)) {
447 dev->write(dev, CLICK_CFG, p->click_flags); 571 dev->write(dev, CLICK_CFG, p->click_flags);
448 dev->write(dev, CLICK_TIMELIMIT, p->click_time_limit); 572 dev->write(dev, CLICK_TIMELIMIT, p->click_time_limit);
449 dev->write(dev, CLICK_LATENCY, p->click_latency); 573 dev->write(dev, CLICK_LATENCY, p->click_latency);
@@ -454,7 +578,7 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
454 (p->click_thresh_y << 4)); 578 (p->click_thresh_y << 4));
455 } 579 }
456 580
457 if (p->wakeup_flags && (dev->whoami == LIS_SINGLE_ID)) { 581 if (p->wakeup_flags && (dev->whoami == WAI_8B)) {
458 dev->write(dev, FF_WU_CFG_1, p->wakeup_flags); 582 dev->write(dev, FF_WU_CFG_1, p->wakeup_flags);
459 dev->write(dev, FF_WU_THS_1, p->wakeup_thresh & 0x7f); 583 dev->write(dev, FF_WU_THS_1, p->wakeup_thresh & 0x7f);
460 /* default to 2.5ms for now */ 584 /* default to 2.5ms for now */
@@ -484,4 +608,3 @@ EXPORT_SYMBOL_GPL(lis3lv02d_init_device);
484MODULE_DESCRIPTION("ST LIS3LV02Dx three-axis digital accelerometer driver"); 608MODULE_DESCRIPTION("ST LIS3LV02Dx three-axis digital accelerometer driver");
485MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek"); 609MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek");
486MODULE_LICENSE("GPL"); 610MODULE_LICENSE("GPL");
487