diff options
Diffstat (limited to 'drivers/hwmon/ams')
-rw-r--r-- | drivers/hwmon/ams/ams-core.c | 82 | ||||
-rw-r--r-- | drivers/hwmon/ams/ams-i2c.c | 60 | ||||
-rw-r--r-- | drivers/hwmon/ams/ams-input.c | 63 | ||||
-rw-r--r-- | drivers/hwmon/ams/ams-pmu.c | 18 | ||||
-rw-r--r-- | drivers/hwmon/ams/ams.h | 6 |
5 files changed, 95 insertions, 134 deletions
diff --git a/drivers/hwmon/ams/ams-core.c b/drivers/hwmon/ams/ams-core.c index fbefa82a015c..6c9ace1b76f6 100644 --- a/drivers/hwmon/ams/ams-core.c +++ b/drivers/hwmon/ams/ams-core.c @@ -99,39 +99,31 @@ static struct pmf_irq_client ams_shock_client = { */ static void ams_worker(struct work_struct *work) { - mutex_lock(&ams_info.lock); - - if (ams_info.has_device) { - unsigned long flags; + unsigned long flags; + u8 irqs_to_clear; - spin_lock_irqsave(&ams_info.irq_lock, flags); + mutex_lock(&ams_info.lock); - if (ams_info.worker_irqs & AMS_IRQ_FREEFALL) { - if (verbose) - printk(KERN_INFO "ams: freefall detected!\n"); + spin_lock_irqsave(&ams_info.irq_lock, flags); + irqs_to_clear = ams_info.worker_irqs; - ams_info.worker_irqs &= ~AMS_IRQ_FREEFALL; + if (ams_info.worker_irqs & AMS_IRQ_FREEFALL) { + if (verbose) + printk(KERN_INFO "ams: freefall detected!\n"); - /* we must call this with interrupts enabled */ - spin_unlock_irqrestore(&ams_info.irq_lock, flags); - ams_info.clear_irq(AMS_IRQ_FREEFALL); - spin_lock_irqsave(&ams_info.irq_lock, flags); - } + ams_info.worker_irqs &= ~AMS_IRQ_FREEFALL; + } - if (ams_info.worker_irqs & AMS_IRQ_SHOCK) { - if (verbose) - printk(KERN_INFO "ams: shock detected!\n"); + if (ams_info.worker_irqs & AMS_IRQ_SHOCK) { + if (verbose) + printk(KERN_INFO "ams: shock detected!\n"); - ams_info.worker_irqs &= ~AMS_IRQ_SHOCK; + ams_info.worker_irqs &= ~AMS_IRQ_SHOCK; + } - /* we must call this with interrupts enabled */ - spin_unlock_irqrestore(&ams_info.irq_lock, flags); - ams_info.clear_irq(AMS_IRQ_SHOCK); - spin_lock_irqsave(&ams_info.irq_lock, flags); - } + spin_unlock_irqrestore(&ams_info.irq_lock, flags); - spin_unlock_irqrestore(&ams_info.irq_lock, flags); - } + ams_info.clear_irq(irqs_to_clear); mutex_unlock(&ams_info.lock); } @@ -223,34 +215,28 @@ int __init ams_init(void) void ams_exit(void) { - mutex_lock(&ams_info.lock); - - if (ams_info.has_device) { - /* Remove input device */ - ams_input_exit(); + /* Remove input device */ + ams_input_exit(); - /* Shut down implementation */ - ams_info.exit(); - - /* Flush interrupt worker - * - * We do this after ams_info.exit(), because an interrupt might - * have arrived before disabling them. - */ - flush_scheduled_work(); + /* Remove attributes */ + device_remove_file(&ams_info.of_dev->dev, &dev_attr_current); - /* Remove attributes */ - device_remove_file(&ams_info.of_dev->dev, &dev_attr_current); + /* Shut down implementation */ + ams_info.exit(); - /* Remove device */ - of_device_unregister(ams_info.of_dev); + /* Flush interrupt worker + * + * We do this after ams_info.exit(), because an interrupt might + * have arrived before disabling them. + */ + flush_scheduled_work(); - /* Remove handler */ - pmf_unregister_irq_client(&ams_shock_client); - pmf_unregister_irq_client(&ams_freefall_client); - } + /* Remove device */ + of_device_unregister(ams_info.of_dev); - mutex_unlock(&ams_info.lock); + /* Remove handler */ + pmf_unregister_irq_client(&ams_shock_client); + pmf_unregister_irq_client(&ams_freefall_client); } MODULE_AUTHOR("Stelian Pop, Michael Hanselmann"); diff --git a/drivers/hwmon/ams/ams-i2c.c b/drivers/hwmon/ams/ams-i2c.c index 957760536a4c..2cbf8a6506c7 100644 --- a/drivers/hwmon/ams/ams-i2c.c +++ b/drivers/hwmon/ams/ams-i2c.c @@ -60,26 +60,34 @@ enum ams_i2c_cmd { AMS_CMD_START, }; -static int ams_i2c_attach(struct i2c_adapter *adapter); -static int ams_i2c_detach(struct i2c_adapter *adapter); +static int ams_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id); +static int ams_i2c_remove(struct i2c_client *client); + +static const struct i2c_device_id ams_id[] = { + { "ams", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ams_id); static struct i2c_driver ams_i2c_driver = { .driver = { .name = "ams", .owner = THIS_MODULE, }, - .attach_adapter = ams_i2c_attach, - .detach_adapter = ams_i2c_detach, + .probe = ams_i2c_probe, + .remove = ams_i2c_remove, + .id_table = ams_id, }; static s32 ams_i2c_read(u8 reg) { - return i2c_smbus_read_byte_data(&ams_info.i2c_client, reg); + return i2c_smbus_read_byte_data(ams_info.i2c_client, reg); } static int ams_i2c_write(u8 reg, u8 value) { - return i2c_smbus_write_byte_data(&ams_info.i2c_client, reg, value); + return i2c_smbus_write_byte_data(ams_info.i2c_client, reg, value); } static int ams_i2c_cmd(enum ams_i2c_cmd cmd) @@ -152,9 +160,9 @@ static void ams_i2c_get_xyz(s8 *x, s8 *y, s8 *z) *z = ams_i2c_read(AMS_DATAZ); } -static int ams_i2c_attach(struct i2c_adapter *adapter) +static int ams_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) { - unsigned long bus; int vmaj, vmin; int result; @@ -162,17 +170,7 @@ static int ams_i2c_attach(struct i2c_adapter *adapter) if (unlikely(ams_info.has_device)) return -ENODEV; - if (strncmp(adapter->name, "uni-n", 5)) - return -ENODEV; - - bus = simple_strtoul(adapter->name + 6, NULL, 10); - if (bus != ams_info.i2c_bus) - return -ENODEV; - - ams_info.i2c_client.addr = ams_info.i2c_address; - ams_info.i2c_client.adapter = adapter; - ams_info.i2c_client.driver = &ams_i2c_driver; - strcpy(ams_info.i2c_client.name, "Apple Motion Sensor"); + ams_info.i2c_client = client; if (ams_i2c_cmd(AMS_CMD_RESET)) { printk(KERN_INFO "ams: Failed to reset the device\n"); @@ -237,7 +235,7 @@ static int ams_i2c_attach(struct i2c_adapter *adapter) return 0; } -static int ams_i2c_detach(struct i2c_adapter *adapter) +static int ams_i2c_remove(struct i2c_client *client) { if (ams_info.has_device) { /* Disable interrupts */ @@ -261,11 +259,7 @@ static void ams_i2c_exit(void) int __init ams_i2c_init(struct device_node *np) { - char *tmp_bus; int result; - const u32 *prop; - - mutex_lock(&ams_info.lock); /* Set implementation stuff */ ams_info.of_node = np; @@ -275,25 +269,7 @@ int __init ams_i2c_init(struct device_node *np) ams_info.clear_irq = ams_i2c_clear_irq; ams_info.bustype = BUS_I2C; - /* look for bus either using "reg" or by path */ - prop = of_get_property(ams_info.of_node, "reg", NULL); - if (!prop) { - result = -ENODEV; - - goto exit; - } - - tmp_bus = strstr(ams_info.of_node->full_name, "/i2c-bus@"); - if (tmp_bus) - ams_info.i2c_bus = *(tmp_bus + 9) - '0'; - else - ams_info.i2c_bus = ((*prop) >> 8) & 0x0f; - ams_info.i2c_address = ((*prop) & 0xff) >> 1; - result = i2c_add_driver(&ams_i2c_driver); -exit: - mutex_unlock(&ams_info.lock); - return result; } diff --git a/drivers/hwmon/ams/ams-input.c b/drivers/hwmon/ams/ams-input.c index 7b81e0c2c2d9..8a712392cd38 100644 --- a/drivers/hwmon/ams/ams-input.c +++ b/drivers/hwmon/ams/ams-input.c @@ -20,13 +20,15 @@ #include "ams.h" static unsigned int joystick; -module_param(joystick, bool, 0644); +module_param(joystick, bool, S_IRUGO); MODULE_PARM_DESC(joystick, "Enable the input class device on module load"); static unsigned int invert; -module_param(invert, bool, 0644); +module_param(invert, bool, S_IWUSR | S_IRUGO); MODULE_PARM_DESC(invert, "Invert input data on X and Y axis"); +static DEFINE_MUTEX(ams_input_mutex); + static void ams_idev_poll(struct input_polled_dev *dev) { struct input_dev *idev = dev->input; @@ -50,13 +52,11 @@ static void ams_idev_poll(struct input_polled_dev *dev) } /* Call with ams_info.lock held! */ -static void ams_input_enable(void) +static int ams_input_enable(void) { struct input_dev *input; s8 x, y, z; - - if (ams_info.idev) - return; + int error; ams_sensors(&x, &y, &z); ams_info.xcalib = x; @@ -65,7 +65,7 @@ static void ams_input_enable(void) ams_info.idev = input_allocate_polled_device(); if (!ams_info.idev) - return; + return -ENOMEM; ams_info.idev->poll = ams_idev_poll; ams_info.idev->poll_interval = 25; @@ -84,14 +84,18 @@ static void ams_input_enable(void) set_bit(EV_KEY, input->evbit); set_bit(BTN_TOUCH, input->keybit); - if (input_register_polled_device(ams_info.idev)) { + error = input_register_polled_device(ams_info.idev); + if (error) { input_free_polled_device(ams_info.idev); ams_info.idev = NULL; - return; + return error; } + + joystick = 1; + + return 0; } -/* Call with ams_info.lock held! */ static void ams_input_disable(void) { if (ams_info.idev) { @@ -99,6 +103,8 @@ static void ams_input_disable(void) input_free_polled_device(ams_info.idev); ams_info.idev = NULL; } + + joystick = 0; } static ssize_t ams_input_show_joystick(struct device *dev, @@ -110,39 +116,42 @@ static ssize_t ams_input_show_joystick(struct device *dev, static ssize_t ams_input_store_joystick(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - if (sscanf(buf, "%d\n", &joystick) != 1) + unsigned long enable; + int error = 0; + + if (strict_strtoul(buf, 0, &enable) || enable > 1) return -EINVAL; - mutex_lock(&ams_info.lock); + mutex_lock(&ams_input_mutex); - if (joystick) - ams_input_enable(); - else - ams_input_disable(); + if (enable != joystick) { + if (enable) + error = ams_input_enable(); + else + ams_input_disable(); + } - mutex_unlock(&ams_info.lock); + mutex_unlock(&ams_input_mutex); - return count; + return error ? error : count; } static DEVICE_ATTR(joystick, S_IRUGO | S_IWUSR, ams_input_show_joystick, ams_input_store_joystick); -/* Call with ams_info.lock held! */ int ams_input_init(void) { - int result; - - result = device_create_file(&ams_info.of_dev->dev, &dev_attr_joystick); - - if (!result && joystick) + if (joystick) ams_input_enable(); - return result; + + return device_create_file(&ams_info.of_dev->dev, &dev_attr_joystick); } -/* Call with ams_info.lock held! */ void ams_input_exit(void) { - ams_input_disable(); device_remove_file(&ams_info.of_dev->dev, &dev_attr_joystick); + + mutex_lock(&ams_input_mutex); + ams_input_disable(); + mutex_unlock(&ams_input_mutex); } diff --git a/drivers/hwmon/ams/ams-pmu.c b/drivers/hwmon/ams/ams-pmu.c index 9463e9768f6f..fb18b3d3162b 100644 --- a/drivers/hwmon/ams/ams-pmu.c +++ b/drivers/hwmon/ams/ams-pmu.c @@ -149,8 +149,6 @@ int __init ams_pmu_init(struct device_node *np) const u32 *prop; int result; - mutex_lock(&ams_info.lock); - /* Set implementation stuff */ ams_info.of_node = np; ams_info.exit = ams_pmu_exit; @@ -161,10 +159,9 @@ int __init ams_pmu_init(struct device_node *np) /* Get PMU command, should be 0x4e, but we can never know */ prop = of_get_property(ams_info.of_node, "reg", NULL); - if (!prop) { - result = -ENODEV; - goto exit; - } + if (!prop) + return -ENODEV; + ams_pmu_cmd = ((*prop) >> 8) & 0xff; /* Disable interrupts */ @@ -175,7 +172,7 @@ int __init ams_pmu_init(struct device_node *np) result = ams_sensor_attach(); if (result < 0) - goto exit; + return result; /* Set default values */ ams_pmu_set_register(AMS_FF_LOW_LIMIT, 0x15); @@ -198,10 +195,5 @@ int __init ams_pmu_init(struct device_node *np) printk(KERN_INFO "ams: Found PMU based motion sensor\n"); - result = 0; - -exit: - mutex_unlock(&ams_info.lock); - - return result; + return 0; } diff --git a/drivers/hwmon/ams/ams.h b/drivers/hwmon/ams/ams.h index a6221e5dd984..5ed387b0bd9a 100644 --- a/drivers/hwmon/ams/ams.h +++ b/drivers/hwmon/ams/ams.h @@ -4,7 +4,7 @@ #include <linux/mutex.h> #include <linux/spinlock.h> #include <linux/types.h> -#include <asm/of_device.h> +#include <linux/of_device.h> enum ams_irq { AMS_IRQ_FREEFALL = 0x01, @@ -46,9 +46,7 @@ struct ams { #ifdef CONFIG_SENSORS_AMS_I2C /* I2C properties */ - int i2c_bus; - int i2c_address; - struct i2c_client i2c_client; + struct i2c_client *i2c_client; #endif /* Joystick emulation */ |