diff options
Diffstat (limited to 'drivers/hwmon/lis3lv02d.c')
-rw-r--r-- | drivers/hwmon/lis3lv02d.c | 288 |
1 files changed, 162 insertions, 126 deletions
diff --git a/drivers/hwmon/lis3lv02d.c b/drivers/hwmon/lis3lv02d.c index 8bb2158f045..778eb779598 100644 --- a/drivers/hwmon/lis3lv02d.c +++ b/drivers/hwmon/lis3lv02d.c @@ -36,7 +36,6 @@ #include <linux/freezer.h> #include <linux/uaccess.h> #include <linux/miscdevice.h> -#include <acpi/acpi_drivers.h> #include <asm/atomic.h> #include "lis3lv02d.h" @@ -53,13 +52,30 @@ * joystick. */ -struct acpi_lis3lv02d adev = { - .misc_wait = __WAIT_QUEUE_HEAD_INITIALIZER(adev.misc_wait), +struct lis3lv02d lis3_dev = { + .misc_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lis3_dev.misc_wait), }; -EXPORT_SYMBOL_GPL(adev); +EXPORT_SYMBOL_GPL(lis3_dev); -static int lis3lv02d_add_fs(struct acpi_device *device); +static s16 lis3lv02d_read_8(struct lis3lv02d *lis3, int reg) +{ + s8 lo; + if (lis3->read(lis3, reg, &lo) < 0) + return 0; + + return lo; +} + +static s16 lis3lv02d_read_16(struct lis3lv02d *lis3, int reg) +{ + u8 lo, hi; + + lis3->read(lis3, reg - 1, &lo); + lis3->read(lis3, reg, &hi); + /* In "12 bit right justified" mode, bit 6, bit 7, bit 8 = bit 5 */ + return (s16)((hi << 8) | lo); +} /** * lis3lv02d_get_axis - For the given axis, give the value converted @@ -78,36 +94,36 @@ static inline int lis3lv02d_get_axis(s8 axis, int hw_values[3]) /** * lis3lv02d_get_xyz - Get X, Y and Z axis values from the accelerometer - * @handle: the handle to the device - * @x: where to store the X axis value - * @y: where to store the Y axis value - * @z: where to store the Z axis value + * @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 * * Note that 40Hz input device can eat up about 10% CPU at 800MHZ */ -static void lis3lv02d_get_xyz(acpi_handle handle, int *x, int *y, int *z) +static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z) { int position[3]; - position[0] = adev.read_data(handle, OUTX); - position[1] = adev.read_data(handle, OUTY); - position[2] = adev.read_data(handle, OUTZ); + position[0] = lis3_dev.read_data(lis3, OUTX); + position[1] = lis3_dev.read_data(lis3, OUTY); + position[2] = lis3_dev.read_data(lis3, OUTZ); - *x = lis3lv02d_get_axis(adev.ac.x, position); - *y = lis3lv02d_get_axis(adev.ac.y, position); - *z = lis3lv02d_get_axis(adev.ac.z, position); + *x = lis3lv02d_get_axis(lis3_dev.ac.x, position); + *y = lis3lv02d_get_axis(lis3_dev.ac.y, position); + *z = lis3lv02d_get_axis(lis3_dev.ac.z, position); } -void lis3lv02d_poweroff(acpi_handle handle) +void lis3lv02d_poweroff(struct lis3lv02d *lis3) { - adev.is_on = 0; + lis3_dev.is_on = 0; } EXPORT_SYMBOL_GPL(lis3lv02d_poweroff); -void lis3lv02d_poweron(acpi_handle handle) +void lis3lv02d_poweron(struct lis3lv02d *lis3) { - adev.is_on = 1; - adev.init(handle); + lis3_dev.is_on = 1; + lis3_dev.init(lis3); } EXPORT_SYMBOL_GPL(lis3lv02d_poweron); @@ -116,13 +132,13 @@ EXPORT_SYMBOL_GPL(lis3lv02d_poweron); * device will always be on until a call to lis3lv02d_decrease_use(). Not to be * used from interrupt context. */ -static void lis3lv02d_increase_use(struct acpi_lis3lv02d *dev) +static void lis3lv02d_increase_use(struct lis3lv02d *dev) { mutex_lock(&dev->lock); dev->usage++; if (dev->usage == 1) { if (!dev->is_on) - lis3lv02d_poweron(dev->device->handle); + lis3lv02d_poweron(dev); } mutex_unlock(&dev->lock); } @@ -131,12 +147,12 @@ static void lis3lv02d_increase_use(struct acpi_lis3lv02d *dev) * To be called whenever a usage of the device is stopped. * It will make sure to turn off the device when there is not usage. */ -static void lis3lv02d_decrease_use(struct acpi_lis3lv02d *dev) +static void lis3lv02d_decrease_use(struct lis3lv02d *dev) { mutex_lock(&dev->lock); dev->usage--; if (dev->usage == 0) - lis3lv02d_poweroff(dev->device->handle); + lis3lv02d_poweroff(dev); mutex_unlock(&dev->lock); } @@ -147,10 +163,10 @@ static irqreturn_t lis302dl_interrupt(int irq, void *dummy) * the lid is closed. This leads to interrupts as soon as a little move * is done. */ - atomic_inc(&adev.count); + atomic_inc(&lis3_dev.count); - wake_up_interruptible(&adev.misc_wait); - kill_fasync(&adev.async_queue, SIGIO, POLL_IN); + wake_up_interruptible(&lis3_dev.misc_wait); + kill_fasync(&lis3_dev.async_queue, SIGIO, POLL_IN); return IRQ_HANDLED; } @@ -158,10 +174,10 @@ static int lis3lv02d_misc_open(struct inode *inode, struct file *file) { int ret; - if (test_and_set_bit(0, &adev.misc_opened)) + if (test_and_set_bit(0, &lis3_dev.misc_opened)) return -EBUSY; /* already open */ - atomic_set(&adev.count, 0); + atomic_set(&lis3_dev.count, 0); /* * The sensor can generate interrupts for free-fall and direction @@ -174,25 +190,25 @@ static int lis3lv02d_misc_open(struct inode *inode, struct file *file) * 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); + ret = request_irq(lis3_dev.irq, lis302dl_interrupt, IRQF_TRIGGER_RISING, + DRIVER_NAME, &lis3_dev); if (ret) { - clear_bit(0, &adev.misc_opened); - printk(KERN_ERR DRIVER_NAME ": IRQ%d allocation failed\n", adev.irq); + clear_bit(0, &lis3_dev.misc_opened); + printk(KERN_ERR DRIVER_NAME ": IRQ%d allocation failed\n", lis3_dev.irq); return -EBUSY; } - lis3lv02d_increase_use(&adev); - printk("lis3: registered interrupt %d\n", adev.irq); + lis3lv02d_increase_use(&lis3_dev); + printk("lis3: registered interrupt %d\n", lis3_dev.irq); return 0; } static int lis3lv02d_misc_release(struct inode *inode, struct file *file) { - fasync_helper(-1, file, 0, &adev.async_queue); - lis3lv02d_decrease_use(&adev); - free_irq(adev.irq, &adev); - clear_bit(0, &adev.misc_opened); /* release the device */ + fasync_helper(-1, file, 0, &lis3_dev.async_queue); + lis3lv02d_decrease_use(&lis3_dev); + free_irq(lis3_dev.irq, &lis3_dev); + clear_bit(0, &lis3_dev.misc_opened); /* release the device */ return 0; } @@ -207,10 +223,10 @@ static ssize_t lis3lv02d_misc_read(struct file *file, char __user *buf, if (count < 1) return -EINVAL; - add_wait_queue(&adev.misc_wait, &wait); + add_wait_queue(&lis3_dev.misc_wait, &wait); while (true) { set_current_state(TASK_INTERRUPTIBLE); - data = atomic_xchg(&adev.count, 0); + data = atomic_xchg(&lis3_dev.count, 0); if (data) break; @@ -240,22 +256,22 @@ static ssize_t lis3lv02d_misc_read(struct file *file, char __user *buf, out: __set_current_state(TASK_RUNNING); - remove_wait_queue(&adev.misc_wait, &wait); + remove_wait_queue(&lis3_dev.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)) + poll_wait(file, &lis3_dev.misc_wait, wait); + if (atomic_read(&lis3_dev.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); + return fasync_helper(fd, file, on, &lis3_dev.async_queue); } static const struct file_operations lis3lv02d_misc_fops = { @@ -283,12 +299,12 @@ static int lis3lv02d_joystick_kthread(void *data) int x, y, z; while (!kthread_should_stop()) { - lis3lv02d_get_xyz(adev.device->handle, &x, &y, &z); - input_report_abs(adev.idev, ABS_X, x - adev.xcalib); - input_report_abs(adev.idev, ABS_Y, y - adev.ycalib); - input_report_abs(adev.idev, ABS_Z, z - adev.zcalib); + lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); + input_report_abs(lis3_dev.idev, ABS_X, x - lis3_dev.xcalib); + input_report_abs(lis3_dev.idev, ABS_Y, y - lis3_dev.ycalib); + input_report_abs(lis3_dev.idev, ABS_Z, z - lis3_dev.zcalib); - input_sync(adev.idev); + input_sync(lis3_dev.idev); try_to_freeze(); msleep_interruptible(MDPS_POLL_INTERVAL); @@ -299,11 +315,11 @@ static int lis3lv02d_joystick_kthread(void *data) static int lis3lv02d_joystick_open(struct input_dev *input) { - lis3lv02d_increase_use(&adev); - adev.kthread = kthread_run(lis3lv02d_joystick_kthread, NULL, "klis3lv02d"); - if (IS_ERR(adev.kthread)) { - lis3lv02d_decrease_use(&adev); - return PTR_ERR(adev.kthread); + lis3lv02d_increase_use(&lis3_dev); + lis3_dev.kthread = kthread_run(lis3lv02d_joystick_kthread, NULL, "klis3lv02d"); + if (IS_ERR(lis3_dev.kthread)) { + lis3lv02d_decrease_use(&lis3_dev); + return PTR_ERR(lis3_dev.kthread); } return 0; @@ -311,45 +327,46 @@ static int lis3lv02d_joystick_open(struct input_dev *input) static void lis3lv02d_joystick_close(struct input_dev *input) { - kthread_stop(adev.kthread); - lis3lv02d_decrease_use(&adev); + kthread_stop(lis3_dev.kthread); + lis3lv02d_decrease_use(&lis3_dev); } static inline void lis3lv02d_calibrate_joystick(void) { - lis3lv02d_get_xyz(adev.device->handle, &adev.xcalib, &adev.ycalib, &adev.zcalib); + lis3lv02d_get_xyz(&lis3_dev, + &lis3_dev.xcalib, &lis3_dev.ycalib, &lis3_dev.zcalib); } int lis3lv02d_joystick_enable(void) { int err; - if (adev.idev) + if (lis3_dev.idev) return -EINVAL; - adev.idev = input_allocate_device(); - if (!adev.idev) + lis3_dev.idev = input_allocate_device(); + if (!lis3_dev.idev) return -ENOMEM; lis3lv02d_calibrate_joystick(); - adev.idev->name = "ST LIS3LV02DL Accelerometer"; - adev.idev->phys = DRIVER_NAME "/input0"; - adev.idev->id.bustype = BUS_HOST; - adev.idev->id.vendor = 0; - adev.idev->dev.parent = &adev.pdev->dev; - adev.idev->open = lis3lv02d_joystick_open; - adev.idev->close = lis3lv02d_joystick_close; + lis3_dev.idev->name = "ST LIS3LV02DL Accelerometer"; + lis3_dev.idev->phys = DRIVER_NAME "/input0"; + lis3_dev.idev->id.bustype = BUS_HOST; + lis3_dev.idev->id.vendor = 0; + lis3_dev.idev->dev.parent = &lis3_dev.pdev->dev; + lis3_dev.idev->open = lis3lv02d_joystick_open; + lis3_dev.idev->close = lis3lv02d_joystick_close; - set_bit(EV_ABS, adev.idev->evbit); - input_set_abs_params(adev.idev, ABS_X, -adev.mdps_max_val, adev.mdps_max_val, 3, 3); - input_set_abs_params(adev.idev, ABS_Y, -adev.mdps_max_val, adev.mdps_max_val, 3, 3); - input_set_abs_params(adev.idev, ABS_Z, -adev.mdps_max_val, adev.mdps_max_val, 3, 3); + set_bit(EV_ABS, lis3_dev.idev->evbit); + input_set_abs_params(lis3_dev.idev, ABS_X, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3); + input_set_abs_params(lis3_dev.idev, ABS_Y, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3); + input_set_abs_params(lis3_dev.idev, ABS_Z, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3); - err = input_register_device(adev.idev); + err = input_register_device(lis3_dev.idev); if (err) { - input_free_device(adev.idev); - adev.idev = NULL; + input_free_device(lis3_dev.idev); + lis3_dev.idev = NULL; } return err; @@ -358,71 +375,40 @@ EXPORT_SYMBOL_GPL(lis3lv02d_joystick_enable); void lis3lv02d_joystick_disable(void) { - if (!adev.idev) + if (!lis3_dev.idev) return; misc_deregister(&lis3lv02d_misc_device); - input_unregister_device(adev.idev); - adev.idev = NULL; + input_unregister_device(lis3_dev.idev); + lis3_dev.idev = NULL; } EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable); -/* - * Initialise the accelerometer and the various subsystems. - * Should be rather independant of the bus system. - */ -int lis3lv02d_init_device(struct acpi_lis3lv02d *dev) -{ - mutex_init(&dev->lock); - lis3lv02d_add_fs(dev->device); - lis3lv02d_increase_use(dev); - - if (lis3lv02d_joystick_enable()) - printk(KERN_ERR DRIVER_NAME ": joystick initialization failed\n"); - - printk("lis3_init_device: irq %d\n", dev->irq); - - /* 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/freefall\n"); - goto out; - } - - printk("lis3: registering device\n"); - if (misc_register(&lis3lv02d_misc_device)) - printk(KERN_ERR DRIVER_NAME ": misc_register failed\n"); -out: - lis3lv02d_decrease_use(dev); - return 0; -} -EXPORT_SYMBOL_GPL(lis3lv02d_init_device); - /* Sysfs stuff */ static ssize_t lis3lv02d_position_show(struct device *dev, struct device_attribute *attr, char *buf) { int x, y, z; - lis3lv02d_increase_use(&adev); - lis3lv02d_get_xyz(adev.device->handle, &x, &y, &z); - lis3lv02d_decrease_use(&adev); + lis3lv02d_increase_use(&lis3_dev); + lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); + lis3lv02d_decrease_use(&lis3_dev); return sprintf(buf, "(%d,%d,%d)\n", x, y, z); } static ssize_t lis3lv02d_calibrate_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "(%d,%d,%d)\n", adev.xcalib, adev.ycalib, adev.zcalib); + return sprintf(buf, "(%d,%d,%d)\n", lis3_dev.xcalib, lis3_dev.ycalib, lis3_dev.zcalib); } static ssize_t lis3lv02d_calibrate_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - lis3lv02d_increase_use(&adev); + lis3lv02d_increase_use(&lis3_dev); lis3lv02d_calibrate_joystick(); - lis3lv02d_decrease_use(&adev); + lis3lv02d_decrease_use(&lis3_dev); return count; } @@ -434,9 +420,9 @@ static ssize_t lis3lv02d_rate_show(struct device *dev, u8 ctrl; int val; - lis3lv02d_increase_use(&adev); - adev.read(adev.device->handle, CTRL_REG1, &ctrl); - lis3lv02d_decrease_use(&adev); + lis3lv02d_increase_use(&lis3_dev); + lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl); + lis3lv02d_decrease_use(&lis3_dev); val = (ctrl & (CTRL1_DF0 | CTRL1_DF1)) >> 4; return sprintf(buf, "%d\n", lis3lv02dl_df_val[val]); } @@ -458,23 +444,73 @@ static struct attribute_group lis3lv02d_attribute_group = { }; -static int lis3lv02d_add_fs(struct acpi_device *device) +static int lis3lv02d_add_fs(struct lis3lv02d *lis3) { - adev.pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0); - if (IS_ERR(adev.pdev)) - return PTR_ERR(adev.pdev); + lis3_dev.pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0); + if (IS_ERR(lis3_dev.pdev)) + return PTR_ERR(lis3_dev.pdev); - return sysfs_create_group(&adev.pdev->dev.kobj, &lis3lv02d_attribute_group); + return sysfs_create_group(&lis3_dev.pdev->dev.kobj, &lis3lv02d_attribute_group); } int lis3lv02d_remove_fs(void) { - sysfs_remove_group(&adev.pdev->dev.kobj, &lis3lv02d_attribute_group); - platform_device_unregister(adev.pdev); + sysfs_remove_group(&lis3_dev.pdev->dev.kobj, &lis3lv02d_attribute_group); + platform_device_unregister(lis3_dev.pdev); return 0; } EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs); +/* + * Initialise the accelerometer and the various subsystems. + * Should be rather independant of the bus system. + */ +int lis3lv02d_init_device(struct lis3lv02d *dev) +{ + dev->whoami = lis3lv02d_read_8(dev, WHO_AM_I); + + switch (dev->whoami) { + case LIS_DOUBLE_ID: + printk(KERN_INFO DRIVER_NAME ": 2-byte sensor found\n"); + dev->read_data = lis3lv02d_read_16; + dev->mdps_max_val = 2048; + break; + case LIS_SINGLE_ID: + printk(KERN_INFO DRIVER_NAME ": 1-byte sensor found\n"); + dev->read_data = lis3lv02d_read_8; + dev->mdps_max_val = 128; + break; + default: + printk(KERN_ERR DRIVER_NAME + ": unknown sensor type 0x%X\n", lis3_dev.whoami); + return -EINVAL; + } + + mutex_init(&dev->lock); + lis3lv02d_add_fs(dev); + lis3lv02d_increase_use(dev); + + if (lis3lv02d_joystick_enable()) + printk(KERN_ERR DRIVER_NAME ": joystick initialization failed\n"); + + printk("lis3_init_device: irq %d\n", dev->irq); + + /* bail if we did not get an IRQ from the bus layer */ + if (!dev->irq) { + printk(KERN_ERR DRIVER_NAME + ": No IRQ. Disabling /dev/freefall\n"); + goto out; + } + + printk("lis3: registering device\n"); + if (misc_register(&lis3lv02d_misc_device)) + printk(KERN_ERR DRIVER_NAME ": misc_register failed\n"); +out: + lis3lv02d_decrease_use(dev); + return 0; +} +EXPORT_SYMBOL_GPL(lis3lv02d_init_device); + MODULE_DESCRIPTION("ST LIS3LV02Dx three-axis digital accelerometer driver"); MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek"); MODULE_LICENSE("GPL"); |