lis3lv02d.c 14.4 KB
Newer Older
P
Pavel Machek 已提交
1 2 3 4 5
/*
 *  lis3lv02d.c - ST LIS3LV02DL accelerometer driver
 *
 *  Copyright (C) 2007-2008 Yan Burman
 *  Copyright (C) 2008 Eric Piel
6
 *  Copyright (C) 2008-2009 Pavel Machek
P
Pavel Machek 已提交
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/dmi.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
E
Eric Piel 已提交
30
#include <linux/input-polldev.h>
P
Pavel Machek 已提交
31 32 33 34 35
#include <linux/delay.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/freezer.h>
#include <linux/uaccess.h>
36
#include <linux/miscdevice.h>
P
Pavel Machek 已提交
37 38 39 40 41 42 43 44 45
#include <asm/atomic.h>
#include "lis3lv02d.h"

#define DRIVER_NAME     "lis3lv02d"

/* joystick device poll interval in milliseconds */
#define MDPS_POLL_INTERVAL 50
/*
 * The sensor can also generate interrupts (DRDY) but it's pretty pointless
46
 * because they are generated even if the data do not change. So it's better
P
Pavel Machek 已提交
47 48 49 50 51 52
 * to keep the interrupt for the free-fall event. The values are updated at
 * 40Hz (at the lowest frequency), but as it can be pretty time consuming on
 * some low processor, we poll the sensor only at 20Hz... enough for the
 * joystick.
 */

S
Samu Onkalo 已提交
53 54 55
#define LIS3_PWRON_DELAY_WAI_12B	(5000)
#define LIS3_PWRON_DELAY_WAI_8B		(3000)

56
struct lis3lv02d lis3_dev = {
57
	.misc_wait   = __WAIT_QUEUE_HEAD_INITIALIZER(lis3_dev.misc_wait),
58 59
};

60
EXPORT_SYMBOL_GPL(lis3_dev);
P
Pavel Machek 已提交
61

62 63 64 65 66 67 68 69 70
static s16 lis3lv02d_read_8(struct lis3lv02d *lis3, int reg)
{
	s8 lo;
	if (lis3->read(lis3, reg, &lo) < 0)
		return 0;

	return lo;
}

71
static s16 lis3lv02d_read_12(struct lis3lv02d *lis3, int reg)
72 73 74
{
	u8 lo, hi;

75 76
	lis3->read(lis3, reg - 1, &lo);
	lis3->read(lis3, reg, &hi);
77 78 79 80
	/* In "12 bit right justified" mode, bit 6, bit 7, bit 8 = bit 5 */
	return (s16)((hi << 8) | lo);
}

P
Pavel Machek 已提交
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
/**
 * lis3lv02d_get_axis - For the given axis, give the value converted
 * @axis:      1,2,3 - can also be negative
 * @hw_values: raw values returned by the hardware
 *
 * Returns the converted value.
 */
static inline int lis3lv02d_get_axis(s8 axis, int hw_values[3])
{
	if (axis > 0)
		return hw_values[axis - 1];
	else
		return -hw_values[-axis - 1];
}

/**
 * lis3lv02d_get_xyz - Get X, Y and Z axis values from the accelerometer
98 99 100 101
 * @lis3: pointer to the device struct
 * @x:    where to store the X axis value
 * @y:    where to store the Y axis value
 * @z:    where to store the Z axis value
P
Pavel Machek 已提交
102 103 104
 *
 * Note that 40Hz input device can eat up about 10% CPU at 800MHZ
 */
105
static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z)
P
Pavel Machek 已提交
106 107 108
{
	int position[3];

S
Samu Onkalo 已提交
109
	mutex_lock(&lis3->mutex);
110 111 112
	position[0] = lis3->read_data(lis3, OUTX);
	position[1] = lis3->read_data(lis3, OUTY);
	position[2] = lis3->read_data(lis3, OUTZ);
S
Samu Onkalo 已提交
113
	mutex_unlock(&lis3->mutex);
P
Pavel Machek 已提交
114

115 116 117
	*x = lis3lv02d_get_axis(lis3->ac.x, position);
	*y = lis3lv02d_get_axis(lis3->ac.y, position);
	*z = lis3lv02d_get_axis(lis3->ac.z, position);
P
Pavel Machek 已提交
118 119
}

S
Samu Onkalo 已提交
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
/* conversion btw sampling rate and the register values */
static int lis3_12_rates[4] = {40, 160, 640, 2560};
static int lis3_8_rates[2] = {100, 400};

static int lis3lv02d_get_odr(void)
{
	u8 ctrl;
	int val;

	lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl);

	if (lis3_dev.whoami == WAI_12B)
		val = lis3_12_rates[(ctrl & (CTRL1_DF0 | CTRL1_DF1)) >> 4];
	else
		val = lis3_8_rates[(ctrl & CTRL1_DR) >> 7];
	return val;
}

S
Samu Onkalo 已提交
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
{
	u8 reg;
	s16 x, y, z;
	u8 selftest;
	int ret;

	mutex_lock(&lis3->mutex);
	if (lis3_dev.whoami == WAI_12B)
		selftest = CTRL1_ST;
	else
		selftest = CTRL1_STP;

	lis3->read(lis3, CTRL_REG1, &reg);
	lis3->write(lis3, CTRL_REG1, (reg | selftest));
	msleep(lis3->pwron_delay / lis3lv02d_get_odr());

	/* Read directly to avoid axis remap */
	x = lis3->read_data(lis3, OUTX);
	y = lis3->read_data(lis3, OUTY);
	z = lis3->read_data(lis3, OUTZ);

	/* back to normal settings */
	lis3->write(lis3, CTRL_REG1, reg);
	msleep(lis3->pwron_delay / lis3lv02d_get_odr());

	results[0] = x - lis3->read_data(lis3, OUTX);
	results[1] = y - lis3->read_data(lis3, OUTY);
	results[2] = z - lis3->read_data(lis3, OUTZ);

	ret = 0;
	if (lis3->pdata) {
		int i;
		for (i = 0; i < 3; i++) {
			/* Check against selftest acceptance limits */
			if ((results[i] < lis3->pdata->st_min_limits[i]) ||
			    (results[i] > lis3->pdata->st_max_limits[i])) {
				ret = -EIO;
				goto fail;
			}
		}
	}

	/* test passed */
fail:
	mutex_unlock(&lis3->mutex);
	return ret;
}

187
void lis3lv02d_poweroff(struct lis3lv02d *lis3)
P
Pavel Machek 已提交
188
{
189 190
	/* disable X,Y,Z axis and power down */
	lis3->write(lis3, CTRL_REG1, 0x00);
P
Pavel Machek 已提交
191
}
192
EXPORT_SYMBOL_GPL(lis3lv02d_poweroff);
P
Pavel Machek 已提交
193

194
void lis3lv02d_poweron(struct lis3lv02d *lis3)
P
Pavel Machek 已提交
195
{
196
	u8 reg;
P
Pavel Machek 已提交
197

198
	lis3->init(lis3);
P
Pavel Machek 已提交
199

S
Samu Onkalo 已提交
200 201 202
	/* LIS3 power on delay is quite long */
	msleep(lis3->pwron_delay / lis3lv02d_get_odr());

203 204
	/*
	 * Common configuration
É
Éric Piel 已提交
205 206
	 * BDU: (12 bits sensors only) LSB and MSB values are not updated until
	 *      both have been read. So the value read will always be correct.
207
	 */
É
Éric Piel 已提交
208 209 210 211 212
	if (lis3->whoami ==  WAI_12B) {
		lis3->read(lis3, CTRL_REG2, &reg);
		reg |= CTRL2_BDU;
		lis3->write(lis3, CTRL_REG2, reg);
	}
P
Pavel Machek 已提交
213
}
214 215
EXPORT_SYMBOL_GPL(lis3lv02d_poweron);

P
Pavel Machek 已提交
216

217 218 219 220 221 222 223
static irqreturn_t lis302dl_interrupt(int irq, void *dummy)
{
	/*
	 * Be careful: on some HP laptops the bios force DD when on battery and
	 * the lid is closed. This leads to interrupts as soon as a little move
	 * is done.
	 */
224
	atomic_inc(&lis3_dev.count);
225

226 227
	wake_up_interruptible(&lis3_dev.misc_wait);
	kill_fasync(&lis3_dev.async_queue, SIGIO, POLL_IN);
228 229 230 231 232 233 234
	return IRQ_HANDLED;
}

static int lis3lv02d_misc_open(struct inode *inode, struct file *file)
{
	int ret;

235
	if (test_and_set_bit(0, &lis3_dev.misc_opened))
236 237
		return -EBUSY; /* already open */

238
	atomic_set(&lis3_dev.count, 0);
239 240 241 242 243 244 245 246 247 248 249 250

	/*
	 * The sensor can generate interrupts for free-fall and direction
	 * detection (distinguishable with FF_WU_SRC and DD_SRC) but to keep
	 * the things simple and _fast_ we activate it only for free-fall, so
	 * no need to read register (very slow with ACPI). For the same reason,
	 * we forbid shared interrupts.
	 *
	 * IRQF_TRIGGER_RISING seems pointless on HP laptops because the
	 * io-apic is not configurable (and generates a warning) but I keep it
	 * in case of support for other hardware.
	 */
251 252
	ret = request_irq(lis3_dev.irq, lis302dl_interrupt, IRQF_TRIGGER_RISING,
			  DRIVER_NAME, &lis3_dev);
253 254

	if (ret) {
255 256
		clear_bit(0, &lis3_dev.misc_opened);
		printk(KERN_ERR DRIVER_NAME ": IRQ%d allocation failed\n", lis3_dev.irq);
257 258 259 260 261 262 263
		return -EBUSY;
	}
	return 0;
}

static int lis3lv02d_misc_release(struct inode *inode, struct file *file)
{
264 265 266
	fasync_helper(-1, file, 0, &lis3_dev.async_queue);
	free_irq(lis3_dev.irq, &lis3_dev);
	clear_bit(0, &lis3_dev.misc_opened); /* release the device */
267 268 269 270 271 272 273 274 275 276 277 278 279 280
	return 0;
}

static ssize_t lis3lv02d_misc_read(struct file *file, char __user *buf,
				size_t count, loff_t *pos)
{
	DECLARE_WAITQUEUE(wait, current);
	u32 data;
	unsigned char byte_data;
	ssize_t retval = 1;

	if (count < 1)
		return -EINVAL;

281
	add_wait_queue(&lis3_dev.misc_wait, &wait);
282 283
	while (true) {
		set_current_state(TASK_INTERRUPTIBLE);
284
		data = atomic_xchg(&lis3_dev.count, 0);
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
		if (data)
			break;

		if (file->f_flags & O_NONBLOCK) {
			retval = -EAGAIN;
			goto out;
		}

		if (signal_pending(current)) {
			retval = -ERESTARTSYS;
			goto out;
		}

		schedule();
	}

	if (data < 255)
		byte_data = data;
	else
		byte_data = 255;

	/* make sure we are not going into copy_to_user() with
	 * TASK_INTERRUPTIBLE state */
	set_current_state(TASK_RUNNING);
	if (copy_to_user(buf, &byte_data, sizeof(byte_data)))
		retval = -EFAULT;

out:
	__set_current_state(TASK_RUNNING);
314
	remove_wait_queue(&lis3_dev.misc_wait, &wait);
315 316 317 318 319 320

	return retval;
}

static unsigned int lis3lv02d_misc_poll(struct file *file, poll_table *wait)
{
321 322
	poll_wait(file, &lis3_dev.misc_wait, wait);
	if (atomic_read(&lis3_dev.count))
323 324 325 326 327 328
		return POLLIN | POLLRDNORM;
	return 0;
}

static int lis3lv02d_misc_fasync(int fd, struct file *file, int on)
{
329
	return fasync_helper(fd, file, on, &lis3_dev.async_queue);
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
}

static const struct file_operations lis3lv02d_misc_fops = {
	.owner   = THIS_MODULE,
	.llseek  = no_llseek,
	.read    = lis3lv02d_misc_read,
	.open    = lis3lv02d_misc_open,
	.release = lis3lv02d_misc_release,
	.poll    = lis3lv02d_misc_poll,
	.fasync  = lis3lv02d_misc_fasync,
};

static struct miscdevice lis3lv02d_misc_device = {
	.minor   = MISC_DYNAMIC_MINOR,
	.name    = "freefall",
	.fops    = &lis3lv02d_misc_fops,
};

E
Eric Piel 已提交
348
static void lis3lv02d_joystick_poll(struct input_polled_dev *pidev)
P
Pavel Machek 已提交
349 350 351
{
	int x, y, z;

E
Eric Piel 已提交
352
	lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
353 354 355
	input_report_abs(pidev->input, ABS_X, x);
	input_report_abs(pidev->input, ABS_Y, y);
	input_report_abs(pidev->input, ABS_Z, z);
S
Samu Onkalo 已提交
356
	input_sync(pidev->input);
P
Pavel Machek 已提交
357 358
}

359
int lis3lv02d_joystick_enable(void)
P
Pavel Machek 已提交
360
{
E
Eric Piel 已提交
361
	struct input_dev *input_dev;
P
Pavel Machek 已提交
362 363
	int err;

364
	if (lis3_dev.idev)
P
Pavel Machek 已提交
365 366
		return -EINVAL;

E
Eric Piel 已提交
367
	lis3_dev.idev = input_allocate_polled_device();
368
	if (!lis3_dev.idev)
P
Pavel Machek 已提交
369 370
		return -ENOMEM;

E
Eric Piel 已提交
371 372 373 374 375 376 377 378 379
	lis3_dev.idev->poll = lis3lv02d_joystick_poll;
	lis3_dev.idev->poll_interval = MDPS_POLL_INTERVAL;
	input_dev = lis3_dev.idev->input;

	input_dev->name       = "ST LIS3LV02DL Accelerometer";
	input_dev->phys       = DRIVER_NAME "/input0";
	input_dev->id.bustype = BUS_HOST;
	input_dev->id.vendor  = 0;
	input_dev->dev.parent = &lis3_dev.pdev->dev;
P
Pavel Machek 已提交
380

E
Eric Piel 已提交
381 382 383 384
	set_bit(EV_ABS, input_dev->evbit);
	input_set_abs_params(input_dev, ABS_X, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3);
	input_set_abs_params(input_dev, ABS_Y, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3);
	input_set_abs_params(input_dev, ABS_Z, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3);
P
Pavel Machek 已提交
385

E
Eric Piel 已提交
386
	err = input_register_polled_device(lis3_dev.idev);
P
Pavel Machek 已提交
387
	if (err) {
E
Eric Piel 已提交
388
		input_free_polled_device(lis3_dev.idev);
389
		lis3_dev.idev = NULL;
P
Pavel Machek 已提交
390 391 392 393
	}

	return err;
}
394
EXPORT_SYMBOL_GPL(lis3lv02d_joystick_enable);
P
Pavel Machek 已提交
395

396
void lis3lv02d_joystick_disable(void)
P
Pavel Machek 已提交
397
{
398
	if (!lis3_dev.idev)
P
Pavel Machek 已提交
399 400
		return;

401 402
	if (lis3_dev.irq)
		misc_deregister(&lis3lv02d_misc_device);
E
Eric Piel 已提交
403
	input_unregister_polled_device(lis3_dev.idev);
404
	input_free_polled_device(lis3_dev.idev);
405
	lis3_dev.idev = NULL;
P
Pavel Machek 已提交
406
}
407
EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable);
P
Pavel Machek 已提交
408 409

/* Sysfs stuff */
S
Samu Onkalo 已提交
410 411 412 413 414 415 416 417 418 419 420
static ssize_t lis3lv02d_selftest_show(struct device *dev,
				struct device_attribute *attr, char *buf)
{
	int result;
	s16 values[3];

	result = lis3lv02d_selftest(&lis3_dev, values);
	return sprintf(buf, "%s %d %d %d\n", result == 0 ? "OK" : "FAIL",
		values[0], values[1], values[2]);
}

P
Pavel Machek 已提交
421 422 423 424 425
static ssize_t lis3lv02d_position_show(struct device *dev,
				struct device_attribute *attr, char *buf)
{
	int x, y, z;

426
	lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
P
Pavel Machek 已提交
427 428 429 430 431 432
	return sprintf(buf, "(%d,%d,%d)\n", x, y, z);
}

static ssize_t lis3lv02d_rate_show(struct device *dev,
			struct device_attribute *attr, char *buf)
{
S
Samu Onkalo 已提交
433
	return sprintf(buf, "%d\n", lis3lv02d_get_odr());
P
Pavel Machek 已提交
434 435
}

S
Samu Onkalo 已提交
436
static DEVICE_ATTR(selftest, S_IRUSR, lis3lv02d_selftest_show, NULL);
P
Pavel Machek 已提交
437 438 439 440
static DEVICE_ATTR(position, S_IRUGO, lis3lv02d_position_show, NULL);
static DEVICE_ATTR(rate, S_IRUGO, lis3lv02d_rate_show, NULL);

static struct attribute *lis3lv02d_attributes[] = {
S
Samu Onkalo 已提交
441
	&dev_attr_selftest.attr,
P
Pavel Machek 已提交
442 443 444 445 446 447 448 449 450
	&dev_attr_position.attr,
	&dev_attr_rate.attr,
	NULL
};

static struct attribute_group lis3lv02d_attribute_group = {
	.attrs = lis3lv02d_attributes
};

451

452
static int lis3lv02d_add_fs(struct lis3lv02d *lis3)
P
Pavel Machek 已提交
453
{
454 455 456
	lis3->pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
	if (IS_ERR(lis3->pdev))
		return PTR_ERR(lis3->pdev);
P
Pavel Machek 已提交
457

458
	return sysfs_create_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group);
P
Pavel Machek 已提交
459 460
}

461
int lis3lv02d_remove_fs(struct lis3lv02d *lis3)
P
Pavel Machek 已提交
462
{
463 464
	sysfs_remove_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group);
	platform_device_unregister(lis3->pdev);
P
Pavel Machek 已提交
465 466
	return 0;
}
467
EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs);
P
Pavel Machek 已提交
468

469 470
/*
 * Initialise the accelerometer and the various subsystems.
471
 * Should be rather independent of the bus system.
472
 */
473
int lis3lv02d_init_device(struct lis3lv02d *dev)
474
{
475 476 477
	dev->whoami = lis3lv02d_read_8(dev, WHO_AM_I);

	switch (dev->whoami) {
478 479 480
	case WAI_12B:
		printk(KERN_INFO DRIVER_NAME ": 12 bits sensor found\n");
		dev->read_data = lis3lv02d_read_12;
481
		dev->mdps_max_val = 2048;
S
Samu Onkalo 已提交
482
		dev->pwron_delay = LIS3_PWRON_DELAY_WAI_12B;
483
		break;
484 485
	case WAI_8B:
		printk(KERN_INFO DRIVER_NAME ": 8 bits sensor found\n");
486 487
		dev->read_data = lis3lv02d_read_8;
		dev->mdps_max_val = 128;
S
Samu Onkalo 已提交
488
		dev->pwron_delay = LIS3_PWRON_DELAY_WAI_8B;
489 490 491
		break;
	default:
		printk(KERN_ERR DRIVER_NAME
492
			": unknown sensor type 0x%X\n", dev->whoami);
493 494 495
		return -EINVAL;
	}

S
Samu Onkalo 已提交
496 497
	mutex_init(&dev->mutex);

498
	lis3lv02d_add_fs(dev);
499
	lis3lv02d_poweron(dev);
500 501 502 503

	if (lis3lv02d_joystick_enable())
		printk(KERN_ERR DRIVER_NAME ": joystick initialization failed\n");

D
Daniel Mack 已提交
504 505 506 507 508
	/* passing in platform specific data is purely optional and only
	 * used by the SPI transport layer at the moment */
	if (dev->pdata) {
		struct lis3lv02d_platform_data *p = dev->pdata;

509
		if (p->click_flags && (dev->whoami == WAI_8B)) {
D
Daniel Mack 已提交
510 511 512 513 514 515 516 517 518 519
			dev->write(dev, CLICK_CFG, p->click_flags);
			dev->write(dev, CLICK_TIMELIMIT, p->click_time_limit);
			dev->write(dev, CLICK_LATENCY, p->click_latency);
			dev->write(dev, CLICK_WINDOW, p->click_window);
			dev->write(dev, CLICK_THSZ, p->click_thresh_z & 0xf);
			dev->write(dev, CLICK_THSY_X,
					(p->click_thresh_x & 0xf) |
					(p->click_thresh_y << 4));
		}

520
		if (p->wakeup_flags && (dev->whoami == WAI_8B)) {
521 522 523 524 525 526 527 528
			dev->write(dev, FF_WU_CFG_1, p->wakeup_flags);
			dev->write(dev, FF_WU_THS_1, p->wakeup_thresh & 0x7f);
			/* default to 2.5ms for now */
			dev->write(dev, FF_WU_DURATION_1, 1);
			/* enable high pass filter for both free-fall units */
			dev->write(dev, CTRL_REG2, HP_FF_WU1 | HP_FF_WU2);
		}

D
Daniel Mack 已提交
529 530 531 532
		if (p->irq_cfg)
			dev->write(dev, CTRL_REG3, p->irq_cfg);
	}

533
	/* bail if we did not get an IRQ from the bus layer */
534 535
	if (!dev->irq) {
		printk(KERN_ERR DRIVER_NAME
536
			": No IRQ. Disabling /dev/freefall\n");
537 538 539 540 541 542 543 544 545 546
		goto out;
	}

	if (misc_register(&lis3lv02d_misc_device))
		printk(KERN_ERR DRIVER_NAME ": misc_register failed\n");
out:
	return 0;
}
EXPORT_SYMBOL_GPL(lis3lv02d_init_device);

P
Pavel Machek 已提交
547
MODULE_DESCRIPTION("ST LIS3LV02Dx three-axis digital accelerometer driver");
548
MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek");
P
Pavel Machek 已提交
549
MODULE_LICENSE("GPL");