[lm-sensors] Accelerometer driver for HP laptops

Pavel Machek pavel at suse.cz
Wed Oct 15 12:58:05 CEST 2008


Hi!

> > I took a look at the driver, and it seems to work for me... I'd like
> > to get it to the mainline...
> > 
> >>>> Attached is our work-in-progress version of the driver for a fourth take
> >>>> on the LKML (it used to be mdps). It works really fine, with lots of
> >>>> "goodies" (like automatically convert the axes to fit to a standard,
> >>>> automatic power-off of the device when not in used) excepted the
> >>>> interrupt support for free-fall detection.
> > 
> > I wonder if mdps was really a better name? Driver is HP-specific
> > (because of the ACPI usage), not really chip specific... and lis3lv02d
> > looks like an alphabet soup to me...
> > 
> > Ok, it is a bit chip-specific, too...
> Yes, the point is that several people got interested in adding to the
> driver SPI and I?C support last time I submitted the driver. I did my
> best to concentrate the ACPI stuff only to some 3 or 4 small functions,
> so that it can be be easily done.

Yes, I seen that. Nice.

> I've got already a changelog ready. Give me a couple of days to clean
> things up and I'll send it to akpm myself :-)

Ok, I'd like to help with cleaning... let me know if I can help some more.

* whitelist hp2133

* the driver has different name now.

* remove /** from comments that are not linuxdoc compliant.

* remove /dev/accel. We can reintroduce it when it works

Signed-off-by: Pavel Machek <pavel at suse.cz>
									Pavel

diff --git a/drivers/hwmon/lis3lv02d.c b/drivers/hwmon/lis3lv02d.c
index 3cdfb52..1d6ca17 100644
--- a/drivers/hwmon/lis3lv02d.c
+++ b/drivers/hwmon/lis3lv02d.c
@@ -1,5 +1,6 @@
 /*
- *  mdps.c - ST LIS3LV02DL accelerometer driver
+ *  lis3lv02d.c - ST LIS3LV02DL accelerometer driver used for HDD protection
+ *		  in HP notebooks
  *
  *  Copyright (C) 2007-2008 Yan Burman
  *  Copyright (C) 2008 Eric Piel
@@ -106,7 +107,7 @@ static struct acpi_device_id lis3lv02d_d
 };
 MODULE_DEVICE_TABLE(acpi, lis3lv02d_device_ids);
 
-/**
+/*
  * acpi_init - ACPI _INI method: initialize the device.
  * @handle the handle of the device
  *
@@ -161,7 +162,7 @@ static acpi_status lis3lv02d_acpi_write(
 	return acpi_evaluate_integer(handle, "ALWR", &args, &ret);
 }
 
-/**
+/*
  * Write a 16 bit word on a pair of registers
  * @handle the handle of the device
  * @reg the low register to write to
@@ -187,15 +188,8 @@ static s16 lis3lv02d_read_16(acpi_handle
 	return (s16)((hi << 8) | lo);
 }
 
-static void lis3lv02d_display_reg(int reg)
-{
-	u8 val;
-	lis3lv02d_acpi_read(adev.device->handle, reg, &val);
-	printk(DRIVER_NAME " reg %x : %.2x\n", reg, val);
-}
-
 /**
- * For the given axis, give the value converted
+ * lis3lv02d_get_axis For the given axis, give the value converted
  * @param axis 1,2,3 - can also be negative
  * @param hw_values raw values returned by the hardware
  *
@@ -277,12 +271,6 @@ #endif
 static int lis3lv02d_resume(struct acpi_device *device)
 {
 	/* make sure the device went online */
-	// TODO: check if the device could be automatically turned on by acpi
-	// If so, put the power_off timer back
-//	down(&adev.poff_sem);
-//	if (adev.usage > 0)
-//		lis3lv02d_poweron(device->handle);
-//	up(&adev.poff_sem);
 	printk(KERN_INFO DRIVER_NAME " Resuming device\n");
 	return 0;
 }
@@ -326,192 +314,6 @@ static void lis3lv02d_poweroff_timeout(u
 	printk(KERN_DEBUG DRIVER_NAME ": Turning off the device\n");
 }
 
-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.
-	 */
-	atomic_inc(&adev.count);
-
-	wake_up_interruptible(&adev.misc_wait);
-	kill_fasync(&adev.async_queue, SIGIO, POLL_IN);
-
-//	//lis3lv02d_display_reg(STATUS_REG);
-//	lis3lv02d_display_reg(FF_WU_SRC);
-//	lis3lv02d_display_reg(DD_SRC);
-//	//lis3lv02d_display_reg(CTRL_REG1);
-//	//lis3lv02d_display_reg(CTRL_REG2);
-//	//lis3lv02d_display_reg(CTRL_REG3);
-//	lis3lv02d_display_reg(FF_WU_ACK);
-//	lis3lv02d_display_reg(FF_WU_CFG);
-//	lis3lv02d_display_reg(DD_CFG);
-//	//lis3lv02d_display_reg(FF_WU_THS_L);
-//	//lis3lv02d_display_reg(FF_WU_THS_H);
-//	//lis3lv02d_display_reg(FF_WU_DURATION);
-//	//lis3lv02d_acpi_write(adev.device->handle, FF_WU_SRC, 0);
-//	printk(KERN_DEBUG DRIVER_NAME ": irq received\n");
-
-	return IRQ_HANDLED;
-}
-
-static int lis3lv02d_misc_open(struct inode *inode, struct file *file)
-{
-	int ret;
-
-	if (test_and_set_bit(0, &adev.misc_opened))
-		return -EBUSY; /* already open */
-
-	atomic_set(&adev.count, 0);
-
-	/*
-	 * 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.
-	 */
-	ret = request_irq(adev.irq, lis302dl_interrupt, IRQF_TRIGGER_RISING,
-			  DRIVER_NAME, &adev);
-	if (ret) {
-		clear_bit(0, &adev.misc_opened);
-		printk(KERN_ERR DRIVER_NAME ": IRQ%d allocation failed\n", adev.irq);
-		return -EBUSY;
-	}
-	lis3lv02d_increase_use(&adev);
-	// TODO: set up the registers correctly
-//	lis3lv02d_display_reg(STATUS_REG);
-//	lis3lv02d_display_reg(CTRL_REG1);
-//	lis3lv02d_display_reg(CTRL_REG2);
-//	lis3lv02d_display_reg(CTRL_REG3);
-	lis3lv02d_display_reg(FF_WU_CFG);
-//	lis3lv02d_display_reg(FF_WU_SRC);
-//	lis3lv02d_display_reg(FF_WU_THS_L);
-//	lis3lv02d_display_reg(FF_WU_THS_H);
-//	lis3lv02d_display_reg(FF_WU_DURATION);
-//	lis3lv02d_display_reg(DD_CFG);
-//	lis3lv02d_display_reg(DD_SRC);
-//	lis3lv02d_display_reg(DD_THSI_L);
-//	lis3lv02d_display_reg(DD_THSI_H);
-//	lis3lv02d_display_reg(DD_THSE_L);
-//	lis3lv02d_display_reg(DD_THSE_H);
-//	lis3lv02d_acpi_write(adev.device->handle, FF_WU_SRC, 0);
-	/* Threshold not too big (10) */
-//	lis3lv02d_write_16(adev.device->handle, FF_WU_THS_L, 10);
-//	/* 2 samples in a row before activation */
-//	lis3lv02d_acpi_write(adev.device->handle, FF_WU_DURATION, 2);
-//	/* detect every direction, don't wait for validation */
-	lis3lv02d_acpi_write(adev.device->handle, FF_WU_CFG, 0);
-//	lis3lv02d_acpi_write(adev.device->handle, FF_WU_CFG, FF_WU_CFG_XLIE | FF_WU_CFG_XHIE
-//					| FF_WU_CFG_YLIE | FF_WU_CFG_YHIE
-//					| FF_WU_CFG_ZLIE | FF_WU_CFG_ZHIE);
-	// TODO after turning on, this generates one useless interrupt just after set up, it shouldn't be passed to userspace
-//	lis3lv02d_display_reg(STATUS_REG);
-//	lis3lv02d_display_reg(CTRL_REG1);
-//	lis3lv02d_display_reg(CTRL_REG2);
-//	lis3lv02d_display_reg(CTRL_REG3);
-	lis3lv02d_display_reg(FF_WU_CFG);
-//	lis3lv02d_display_reg(FF_WU_SRC);
-//	lis3lv02d_display_reg(FF_WU_THS_L);
-//	lis3lv02d_display_reg(FF_WU_THS_H);
-//	lis3lv02d_display_reg(FF_WU_DURATION);
-//	lis3lv02d_display_reg(DD_CFG);
-//	lis3lv02d_display_reg(DD_SRC);
-//	lis3lv02d_display_reg(DD_THSI_L);
-//	lis3lv02d_display_reg(DD_THSI_H);
-//	lis3lv02d_display_reg(DD_THSE_L);
-//	lis3lv02d_display_reg(DD_THSE_H);
-
-	return 0;
-}
-
-static int lis3lv02d_misc_release(struct inode *inode, struct file *file)
-{
-	fasync_helper(-1, file, 0, &adev.async_queue);
-	lis3lv02d_acpi_write(adev.device->handle, FF_WU_CFG, 0);
-	lis3lv02d_decrease_use(&adev);
-	free_irq(adev.irq, &adev);
-	clear_bit(0, &adev.misc_opened); /* release the device */
-	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;
-	ssize_t retval = count;
-
-	if (count != sizeof(u32))
-		return -EINVAL;
-
-	add_wait_queue(&adev.misc_wait, &wait);
-	while (true) {
-		set_current_state(TASK_INTERRUPTIBLE);
-		data = atomic_xchg(&adev.count, 0);
-		if (data)
-			break;
-
-		if (file->f_flags & O_NONBLOCK) {
-			retval = -EAGAIN;
-			goto out;
-		}
-
-		if (signal_pending(current)) {
-			retval = -ERESTARTSYS;
-			goto out;
-		}
-
-		schedule();
-	}
-
-	/* make sure we are not going into copy_to_user() with
-	 * TASK_INTERRUPTIBLE state */
-	set_current_state(TASK_RUNNING);
-	if (copy_to_user(buf, &data, sizeof(data)))
-		retval = -EFAULT;
-
-out:
-	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(&adev.misc_wait, &wait);
-
-	return retval;
-}
-
-static unsigned int lis3lv02d_misc_poll(struct file *file, poll_table *wait)
-{
-	poll_wait(file, &adev.misc_wait, wait);
-	if (atomic_read(&adev.count))
-		return POLLIN | POLLRDNORM;
-	return 0;
-}
-
-static int lis3lv02d_misc_fasync(int fd, struct file *file, int on)
-{
-	return fasync_helper(fd, file, on, &adev.async_queue);
-}
-
-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    = "accel",
-	.fops    = &lis3lv02d_misc_fops,
-};
-
 /**
  * lis3lv02d_joystick_kthread - Kthread polling function
  * @param data unused - here to conform to threadfn prototype
@@ -644,16 +446,6 @@ static int lis3lv02d_init_device(struct 
 	/* obtain IRQ number of our device from ACPI */
 	lis3lv02d_enum_resources(dev->device);
 
-	/* if we did not get an IRQ from ACPI - we have nothing more to do */
-	if (!dev->irq) {
-		printk(KERN_ERR DRIVER_NAME
-			": No IRQ in ACPI. Disabling /dev/accel\n");
-		goto out;
-	}
-
-	if (misc_register(&lis3lv02d_misc_device))
-		printk(KERN_ERR DRIVER_NAME ": misc_register failed\n");
-out:
 	lis3lv02d_decrease_use(dev);
 	return 0;
 }
@@ -673,6 +465,7 @@ static struct axis_conversion lis3lv02d_
 static struct axis_conversion lis3lv02d_axis_x_inverted = {-1, 2, 3};
 static struct axis_conversion lis3lv02d_axis_z_inverted = {1, 2, -3};
 static struct axis_conversion lis3lv02d_axis_xy_swap_inverted = {-2, -1, 3};
+static struct axis_conversion lis3lv02d_axis_xy_swap_x_inverted = {-2, 1, 3};
 
 #define AXIS_DMI_MATCH(_ident, _name, _axis) {		\
 	.ident = _ident,				\
@@ -690,6 +483,7 @@ static struct dmi_system_id lis3lv02d_dm
 	AXIS_DMI_MATCH("NW9440", "HP Compaq nw9440", x_inverted),
 	AXIS_DMI_MATCH("NC2510", "HP Compaq 2510", y_inverted),
 	AXIS_DMI_MATCH("NC8510", "HP Compaq 8510", xy_swap_inverted),
+	AXIS_DMI_MATCH("HP2133", "HP 2133", xy_swap_x_inverted ),
 	{ NULL, }
 /* Laptop models without axis info (yet):
  * "NC651xx" "HP Compaq 651"
@@ -738,7 +532,6 @@ static int lis3lv02d_remove(struct acpi_
 	if (!device)
 		return -EINVAL;
 
-	misc_deregister(&lis3lv02d_misc_device);
 	lis3lv02d_joystick_disable();
 	del_timer(&adev.poff_timer);
 	lis3lv02d_poweroff(device->handle);


-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html




More information about the lm-sensors mailing list