LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [RFC PATCHv2 0/5] lis3lv02d: Regulator fix & support for multiple devices  
@ 2011-04-05 14:45 Ilkka Koskinen
  2011-04-05 14:45 ` [RFC PATCHv2 1/5] hwmon: lis3: Free regulators if probe() fails Ilkka Koskinen
                   ` (4 more replies)
  0 siblings, 5 replies; 10+ messages in thread
From: Ilkka Koskinen @ 2011-04-05 14:45 UTC (permalink / raw)
  To: eric.piel, mjg
  Cc: linux-kernel, platform-driver-x86, samu.p.onkalo, ilkka.koskinen

The first patch fixes a bug in lis3 i2c driver when probe() fails.

The rest of the patches converts statically allocated lis3 device
to dynamically allocated one, which enables support for multiple
lis3 devices on board. In addition, this patch set makes it
possible to load both i2c and spi drivers so that they don't
disturb each other. hp_accel is hacked to work and, thus, doesn't
support multiple devices.

I have tested the i2c based driver on target device, but haven't
the other two.

Changes since v1:
The patches are rebased on top of 2.6.39-rc1 as requested. That is,
no code changes. Only the paths of the files were changed.

Cheers, Ilkka


Ilkka Koskinen (5):
  hwmon: lis3: Free regulators if probe() fails.
  hwmon: lis3: Change naming to consistent
  hwmon: lis3: Change exported function to use given device
  hwmon: lis3: Remove the referencies to the global variable in core
    driver
  hwmon: lis3: Register hwif and remove references to global variable

 drivers/misc/lis3lv02d/lis3lv02d.c     |  391 ++++++++++++++++++--------------
 drivers/misc/lis3lv02d/lis3lv02d.h     |   11 +-
 drivers/misc/lis3lv02d/lis3lv02d_i2c.c |   67 ++++---
 drivers/misc/lis3lv02d/lis3lv02d_spi.c |   35 ++-
 drivers/platform/x86/hp_accel.c        |   52 +++--
 5 files changed, 319 insertions(+), 237 deletions(-)


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [RFC PATCHv2 1/5] hwmon: lis3: Free regulators if probe() fails.
  2011-04-05 14:45 [RFC PATCHv2 0/5] lis3lv02d: Regulator fix & support for multiple devices Ilkka Koskinen
@ 2011-04-05 14:45 ` Ilkka Koskinen
  2011-04-05 14:45 ` [RFC PATCHv2 2/5] hwmon: lis3: Change naming to consistent Ilkka Koskinen
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 10+ messages in thread
From: Ilkka Koskinen @ 2011-04-05 14:45 UTC (permalink / raw)
  To: eric.piel, mjg
  Cc: linux-kernel, platform-driver-x86, samu.p.onkalo, ilkka.koskinen

Signed-off-by: Ilkka Koskinen <ilkka.koskinen@nokia.com>
---
 drivers/misc/lis3lv02d/lis3lv02d_i2c.c |    9 +++++++--
 1 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
index b20dfb4..ea9159c 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
+++ b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
@@ -161,8 +161,13 @@ static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client,
 	if (lis3_dev.reg_ctrl)
 		lis3_reg_ctrl(&lis3_dev, LIS3_REG_OFF);
 
-	if (ret == 0)
-		return 0;
+	if (ret)
+		goto fail2;
+	return 0;
+
+fail2:
+	regulator_bulk_free(ARRAY_SIZE(lis3_dev.regulators),
+				lis3_dev.regulators);
 fail:
 	if (pdata && pdata->release_resources)
 		pdata->release_resources();
-- 
1.7.0.4


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [RFC PATCHv2 2/5] hwmon: lis3: Change naming to consistent
  2011-04-05 14:45 [RFC PATCHv2 0/5] lis3lv02d: Regulator fix & support for multiple devices Ilkka Koskinen
  2011-04-05 14:45 ` [RFC PATCHv2 1/5] hwmon: lis3: Free regulators if probe() fails Ilkka Koskinen
@ 2011-04-05 14:45 ` Ilkka Koskinen
  2011-04-05 14:45 ` [RFC PATCHv2 3/5] hwmon: lis3: Change exported function to use given device Ilkka Koskinen
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 10+ messages in thread
From: Ilkka Koskinen @ 2011-04-05 14:45 UTC (permalink / raw)
  To: eric.piel, mjg
  Cc: linux-kernel, platform-driver-x86, samu.p.onkalo, ilkka.koskinen

Signed-off-by: Ilkka Koskinen <ilkka.koskinen@nokia.com>
---
 drivers/misc/lis3lv02d/lis3lv02d.c |  118 ++++++++++++++++++------------------
 1 files changed, 59 insertions(+), 59 deletions(-)

diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c
index b928bc1..cb32945 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d.c
+++ b/drivers/misc/lis3lv02d/lis3lv02d.c
@@ -811,23 +811,23 @@ int lis3lv02d_remove_fs(struct lis3lv02d *lis3)
 }
 EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs);
 
-static void lis3lv02d_8b_configure(struct lis3lv02d *dev,
+static void lis3lv02d_8b_configure(struct lis3lv02d *lis3,
 				struct lis3lv02d_platform_data *p)
 {
 	int err;
 	int ctrl2 = p->hipass_ctrl;
 
 	if (p->click_flags) {
-		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,
+		lis3->write(lis3, CLICK_CFG, p->click_flags);
+		lis3->write(lis3, CLICK_TIMELIMIT, p->click_time_limit);
+		lis3->write(lis3, CLICK_LATENCY, p->click_latency);
+		lis3->write(lis3, CLICK_WINDOW, p->click_window);
+		lis3->write(lis3, CLICK_THSZ, p->click_thresh_z & 0xf);
+		lis3->write(lis3, CLICK_THSY_X,
 			(p->click_thresh_x & 0xf) |
 			(p->click_thresh_y << 4));
 
-		if (dev->idev) {
+		if (lis3->idev) {
 			struct input_dev *input_dev = lis3_dev.idev->input;
 			input_set_capability(input_dev, EV_KEY, BTN_X);
 			input_set_capability(input_dev, EV_KEY, BTN_Y);
@@ -836,22 +836,22 @@ static void lis3lv02d_8b_configure(struct lis3lv02d *dev,
 	}
 
 	if (p->wakeup_flags) {
-		dev->write(dev, FF_WU_CFG_1, p->wakeup_flags);
-		dev->write(dev, FF_WU_THS_1, p->wakeup_thresh & 0x7f);
+		lis3->write(lis3, FF_WU_CFG_1, p->wakeup_flags);
+		lis3->write(lis3, FF_WU_THS_1, p->wakeup_thresh & 0x7f);
 		/* pdata value + 1 to keep this backward compatible*/
-		dev->write(dev, FF_WU_DURATION_1, p->duration1 + 1);
+		lis3->write(lis3, FF_WU_DURATION_1, p->duration1 + 1);
 		ctrl2 ^= HP_FF_WU1; /* Xor to keep compatible with old pdata*/
 	}
 
 	if (p->wakeup_flags2) {
-		dev->write(dev, FF_WU_CFG_2, p->wakeup_flags2);
-		dev->write(dev, FF_WU_THS_2, p->wakeup_thresh2 & 0x7f);
+		lis3->write(lis3, FF_WU_CFG_2, p->wakeup_flags2);
+		lis3->write(lis3, FF_WU_THS_2, p->wakeup_thresh2 & 0x7f);
 		/* pdata value + 1 to keep this backward compatible*/
-		dev->write(dev, FF_WU_DURATION_2, p->duration2 + 1);
+		lis3->write(lis3, FF_WU_DURATION_2, p->duration2 + 1);
 		ctrl2 ^= HP_FF_WU2; /* Xor to keep compatible with old pdata*/
 	}
 	/* Configure hipass filters */
-	dev->write(dev, CTRL_REG2, ctrl2);
+	lis3->write(lis3, CTRL_REG2, ctrl2);
 
 	if (p->irq2) {
 		err = request_threaded_irq(p->irq2,
@@ -869,68 +869,68 @@ static void lis3lv02d_8b_configure(struct lis3lv02d *dev,
  * Initialise the accelerometer and the various subsystems.
  * Should be rather independent of the bus system.
  */
-int lis3lv02d_init_device(struct lis3lv02d *dev)
+int lis3lv02d_init_device(struct lis3lv02d *lis3)
 {
 	int err;
 	irq_handler_t thread_fn;
 	int irq_flags = 0;
 
-	dev->whoami = lis3lv02d_read_8(dev, WHO_AM_I);
+	lis3->whoami = lis3lv02d_read_8(lis3, WHO_AM_I);
 
-	switch (dev->whoami) {
+	switch (lis3->whoami) {
 	case WAI_12B:
 		pr_info("12 bits sensor found\n");
-		dev->read_data = lis3lv02d_read_12;
-		dev->mdps_max_val = 2048;
-		dev->pwron_delay = LIS3_PWRON_DELAY_WAI_12B;
-		dev->odrs = lis3_12_rates;
-		dev->odr_mask = CTRL1_DF0 | CTRL1_DF1;
-		dev->scale = LIS3_SENSITIVITY_12B;
-		dev->regs = lis3_wai12_regs;
-		dev->regs_size = ARRAY_SIZE(lis3_wai12_regs);
+		lis3->read_data = lis3lv02d_read_12;
+		lis3->mdps_max_val = 2048;
+		lis3->pwron_delay = LIS3_PWRON_DELAY_WAI_12B;
+		lis3->odrs = lis3_12_rates;
+		lis3->odr_mask = CTRL1_DF0 | CTRL1_DF1;
+		lis3->scale = LIS3_SENSITIVITY_12B;
+		lis3->regs = lis3_wai12_regs;
+		lis3->regs_size = ARRAY_SIZE(lis3_wai12_regs);
 		break;
 	case WAI_8B:
 		pr_info("8 bits sensor found\n");
-		dev->read_data = lis3lv02d_read_8;
-		dev->mdps_max_val = 128;
-		dev->pwron_delay = LIS3_PWRON_DELAY_WAI_8B;
-		dev->odrs = lis3_8_rates;
-		dev->odr_mask = CTRL1_DR;
-		dev->scale = LIS3_SENSITIVITY_8B;
-		dev->regs = lis3_wai8_regs;
-		dev->regs_size = ARRAY_SIZE(lis3_wai8_regs);
+		lis3->read_data = lis3lv02d_read_8;
+		lis3->mdps_max_val = 128;
+		lis3->pwron_delay = LIS3_PWRON_DELAY_WAI_8B;
+		lis3->odrs = lis3_8_rates;
+		lis3->odr_mask = CTRL1_DR;
+		lis3->scale = LIS3_SENSITIVITY_8B;
+		lis3->regs = lis3_wai8_regs;
+		lis3->regs_size = ARRAY_SIZE(lis3_wai8_regs);
 		break;
 	case WAI_3DC:
 		pr_info("8 bits 3DC sensor found\n");
-		dev->read_data = lis3lv02d_read_8;
-		dev->mdps_max_val = 128;
-		dev->pwron_delay = LIS3_PWRON_DELAY_WAI_8B;
-		dev->odrs = lis3_3dc_rates;
-		dev->odr_mask = CTRL1_ODR0|CTRL1_ODR1|CTRL1_ODR2|CTRL1_ODR3;
-		dev->scale = LIS3_SENSITIVITY_8B;
+		lis3->read_data = lis3lv02d_read_8;
+		lis3->mdps_max_val = 128;
+		lis3->pwron_delay = LIS3_PWRON_DELAY_WAI_8B;
+		lis3->odrs = lis3_3dc_rates;
+		lis3->odr_mask = CTRL1_ODR0|CTRL1_ODR1|CTRL1_ODR2|CTRL1_ODR3;
+		lis3->scale = LIS3_SENSITIVITY_8B;
 		break;
 	default:
-		pr_err("unknown sensor type 0x%X\n", dev->whoami);
+		pr_err("unknown sensor type 0x%X\n", lis3->whoami);
 		return -EINVAL;
 	}
 
-	dev->reg_cache = kzalloc(max(sizeof(lis3_wai8_regs),
+	lis3->reg_cache = kzalloc(max(sizeof(lis3_wai8_regs),
 				     sizeof(lis3_wai12_regs)), GFP_KERNEL);
 
-	if (dev->reg_cache == NULL) {
+	if (lis3->reg_cache == NULL) {
 		printk(KERN_ERR DRIVER_NAME "out of memory\n");
 		return -ENOMEM;
 	}
 
-	mutex_init(&dev->mutex);
-	atomic_set(&dev->wake_thread, 0);
+	mutex_init(&lis3->mutex);
+	atomic_set(&lis3->wake_thread, 0);
 
-	lis3lv02d_add_fs(dev);
-	lis3lv02d_poweron(dev);
+	lis3lv02d_add_fs(lis3);
+	lis3lv02d_poweron(lis3);
 
-	if (dev->pm_dev) {
-		pm_runtime_set_active(dev->pm_dev);
-		pm_runtime_enable(dev->pm_dev);
+	if (lis3->pm_dev) {
+		pm_runtime_set_active(lis3->pm_dev);
+		pm_runtime_enable(lis3->pm_dev);
 	}
 
 	if (lis3lv02d_joystick_enable())
@@ -938,24 +938,24 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
 
 	/* 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;
+	if (lis3->pdata) {
+		struct lis3lv02d_platform_data *p = lis3->pdata;
 
-		if (dev->whoami == WAI_8B)
-			lis3lv02d_8b_configure(dev, p);
+		if (lis3->whoami == WAI_8B)
+			lis3lv02d_8b_configure(lis3, p);
 
 		irq_flags = p->irq_flags1 & IRQF_TRIGGER_MASK;
 
-		dev->irq_cfg = p->irq_cfg;
+		lis3->irq_cfg = p->irq_cfg;
 		if (p->irq_cfg)
-			dev->write(dev, CTRL_REG3, p->irq_cfg);
+			lis3->write(lis3, CTRL_REG3, p->irq_cfg);
 
 		if (p->default_rate)
 			lis3lv02d_set_odr(p->default_rate);
 	}
 
 	/* bail if we did not get an IRQ from the bus layer */
-	if (!dev->irq) {
+	if (!lis3->irq) {
 		pr_debug("No IRQ. Disabling /dev/freefall\n");
 		goto out;
 	}
@@ -971,12 +971,12 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
 	 * io-apic is not configurable (and generates a warning) but I keep it
 	 * in case of support for other hardware.
 	 */
-	if (dev->pdata && dev->whoami == WAI_8B)
+	if (lis3->pdata && lis3->whoami == WAI_8B)
 		thread_fn = lis302dl_interrupt_thread1_8b;
 	else
 		thread_fn = NULL;
 
-	err = request_threaded_irq(dev->irq, lis302dl_interrupt,
+	err = request_threaded_irq(lis3->irq, lis302dl_interrupt,
 				thread_fn,
 				IRQF_TRIGGER_RISING | IRQF_ONESHOT |
 				irq_flags,
-- 
1.7.0.4


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [RFC PATCHv2 3/5] hwmon: lis3: Change exported function to use given device
  2011-04-05 14:45 [RFC PATCHv2 0/5] lis3lv02d: Regulator fix & support for multiple devices Ilkka Koskinen
  2011-04-05 14:45 ` [RFC PATCHv2 1/5] hwmon: lis3: Free regulators if probe() fails Ilkka Koskinen
  2011-04-05 14:45 ` [RFC PATCHv2 2/5] hwmon: lis3: Change naming to consistent Ilkka Koskinen
@ 2011-04-05 14:45 ` Ilkka Koskinen
  2011-04-05 14:45 ` [RFC PATCHv2 4/5] hwmon: lis3: Remove the referencies to the global variable in core driver Ilkka Koskinen
  2011-04-05 14:45 ` [RFC PATCHv2 5/5] hwmon: lis3: Register hwif and remove references to global variable Ilkka Koskinen
  4 siblings, 0 replies; 10+ messages in thread
From: Ilkka Koskinen @ 2011-04-05 14:45 UTC (permalink / raw)
  To: eric.piel, mjg
  Cc: linux-kernel, platform-driver-x86, samu.p.onkalo, ilkka.koskinen

Change exported functions to use the device given as parameter
instead of the global one.

Signed-off-by: Ilkka Koskinen <ilkka.koskinen@nokia.com>
---
 drivers/misc/lis3lv02d/lis3lv02d.c     |    6 +++---
 drivers/misc/lis3lv02d/lis3lv02d.h     |    4 ++--
 drivers/misc/lis3lv02d/lis3lv02d_i2c.c |    2 +-
 drivers/misc/lis3lv02d/lis3lv02d_spi.c |    2 +-
 drivers/platform/x86/hp_accel.c        |    4 ++--
 5 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c
index cb32945..b548afc 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d.c
+++ b/drivers/misc/lis3lv02d/lis3lv02d.c
@@ -609,7 +609,7 @@ static struct miscdevice lis3lv02d_misc_device = {
 	.fops    = &lis3lv02d_misc_fops,
 };
 
-int lis3lv02d_joystick_enable(void)
+int lis3lv02d_joystick_enable(struct lis3lv02d *lis3)
 {
 	struct input_dev *input_dev;
 	int err;
@@ -667,7 +667,7 @@ int lis3lv02d_joystick_enable(void)
 }
 EXPORT_SYMBOL_GPL(lis3lv02d_joystick_enable);
 
-void lis3lv02d_joystick_disable(void)
+void lis3lv02d_joystick_disable(struct lis3lv02d *lis3)
 {
 	if (lis3_dev.irq)
 		free_irq(lis3_dev.irq, &lis3_dev);
@@ -933,7 +933,7 @@ int lis3lv02d_init_device(struct lis3lv02d *lis3)
 		pm_runtime_enable(lis3->pm_dev);
 	}
 
-	if (lis3lv02d_joystick_enable())
+	if (lis3lv02d_joystick_enable(lis3))
 		pr_err("joystick initialization failed\n");
 
 	/* passing in platform specific data is purely optional and only
diff --git a/drivers/misc/lis3lv02d/lis3lv02d.h b/drivers/misc/lis3lv02d/lis3lv02d.h
index a193958..49cb1f1 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d.h
+++ b/drivers/misc/lis3lv02d/lis3lv02d.h
@@ -282,8 +282,8 @@ struct lis3lv02d {
 };
 
 int lis3lv02d_init_device(struct lis3lv02d *lis3);
-int lis3lv02d_joystick_enable(void);
-void lis3lv02d_joystick_disable(void);
+int lis3lv02d_joystick_enable(struct lis3lv02d *lis3);
+void lis3lv02d_joystick_disable(struct lis3lv02d *lis3);
 void lis3lv02d_poweroff(struct lis3lv02d *lis3);
 void lis3lv02d_poweron(struct lis3lv02d *lis3);
 int lis3lv02d_remove_fs(struct lis3lv02d *lis3);
diff --git a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
index ea9159c..6cdc38f 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
+++ b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
@@ -182,7 +182,7 @@ static int __devexit lis3lv02d_i2c_remove(struct i2c_client *client)
 	if (pdata && pdata->release_resources)
 		pdata->release_resources();
 
-	lis3lv02d_joystick_disable();
+	lis3lv02d_joystick_disable(lis3);
 	lis3lv02d_remove_fs(&lis3_dev);
 
 	if (lis3_dev.reg_ctrl)
diff --git a/drivers/misc/lis3lv02d/lis3lv02d_spi.c b/drivers/misc/lis3lv02d/lis3lv02d_spi.c
index c1f8a8f..b2c1be1 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d_spi.c
+++ b/drivers/misc/lis3lv02d/lis3lv02d_spi.c
@@ -83,7 +83,7 @@ static int __devinit lis302dl_spi_probe(struct spi_device *spi)
 static int __devexit lis302dl_spi_remove(struct spi_device *spi)
 {
 	struct lis3lv02d *lis3 = spi_get_drvdata(spi);
-	lis3lv02d_joystick_disable();
+	lis3lv02d_joystick_disable(lis3);
 	lis3lv02d_poweroff(lis3);
 
 	return lis3lv02d_remove_fs(&lis3_dev);
diff --git a/drivers/platform/x86/hp_accel.c b/drivers/platform/x86/hp_accel.c
index 1b52d00..2148d77 100644
--- a/drivers/platform/x86/hp_accel.c
+++ b/drivers/platform/x86/hp_accel.c
@@ -320,7 +320,7 @@ static int lis3lv02d_add(struct acpi_device *device)
 	INIT_WORK(&hpled_led.work, delayed_set_status_worker);
 	ret = led_classdev_register(NULL, &hpled_led.led_classdev);
 	if (ret) {
-		lis3lv02d_joystick_disable();
+		lis3lv02d_joystick_disable(&lis3_dev);
 		lis3lv02d_poweroff(&lis3_dev);
 		flush_work(&hpled_led.work);
 		return ret;
@@ -334,7 +334,7 @@ static int lis3lv02d_remove(struct acpi_device *device, int type)
 	if (!device)
 		return -EINVAL;
 
-	lis3lv02d_joystick_disable();
+	lis3lv02d_joystick_disable(&lis3_dev);
 	lis3lv02d_poweroff(&lis3_dev);
 
 	led_classdev_unregister(&hpled_led.led_classdev);
-- 
1.7.0.4


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [RFC PATCHv2 4/5] hwmon: lis3: Remove the referencies to the global variable in core driver
  2011-04-05 14:45 [RFC PATCHv2 0/5] lis3lv02d: Regulator fix & support for multiple devices Ilkka Koskinen
                   ` (2 preceding siblings ...)
  2011-04-05 14:45 ` [RFC PATCHv2 3/5] hwmon: lis3: Change exported function to use given device Ilkka Koskinen
@ 2011-04-05 14:45 ` Ilkka Koskinen
  2011-04-05 15:50   ` Thadeu Lima de Souza Cascardo
  2011-04-05 14:45 ` [RFC PATCHv2 5/5] hwmon: lis3: Register hwif and remove references to global variable Ilkka Koskinen
  4 siblings, 1 reply; 10+ messages in thread
From: Ilkka Koskinen @ 2011-04-05 14:45 UTC (permalink / raw)
  To: eric.piel, mjg
  Cc: linux-kernel, platform-driver-x86, samu.p.onkalo, ilkka.koskinen

Signed-off-by: Ilkka Koskinen <ilkka.koskinen@nokia.com>
---
 drivers/misc/lis3lv02d/lis3lv02d.c |  237 ++++++++++++++++++++----------------
 drivers/misc/lis3lv02d/lis3lv02d.h |    3 +
 2 files changed, 135 insertions(+), 105 deletions(-)

diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c
index b548afc..11cbe57 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d.c
+++ b/drivers/misc/lis3lv02d/lis3lv02d.c
@@ -163,7 +163,7 @@ static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z)
 	int i;
 
 	if (lis3->blkread) {
-		if (lis3_dev.whoami == WAI_12B) {
+		if (lis3->whoami == WAI_12B) {
 			u16 data[3];
 			lis3->blkread(lis3, OUTX_L, 6, (u8 *)data);
 			for (i = 0; i < 3; i++)
@@ -195,18 +195,18 @@ static int lis3_8_rates[2] = {100, 400};
 static int lis3_3dc_rates[16] = {0, 1, 10, 25, 50, 100, 200, 400, 1600, 5000};
 
 /* ODR is Output Data Rate */
-static int lis3lv02d_get_odr(void)
+static int lis3lv02d_get_odr(struct lis3lv02d *lis3)
 {
 	u8 ctrl;
 	int shift;
 
-	lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl);
-	ctrl &= lis3_dev.odr_mask;
-	shift = ffs(lis3_dev.odr_mask) - 1;
-	return lis3_dev.odrs[(ctrl >> shift)];
+	lis3->read(lis3, CTRL_REG1, &ctrl);
+	ctrl &= lis3->odr_mask;
+	shift = ffs(lis3->odr_mask) - 1;
+	return lis3->odrs[(ctrl >> shift)];
 }
 
-static int lis3lv02d_set_odr(int rate)
+static int lis3lv02d_set_odr(struct lis3lv02d *lis3, int rate)
 {
 	u8 ctrl;
 	int i, len, shift;
@@ -214,14 +214,14 @@ static int lis3lv02d_set_odr(int rate)
 	if (!rate)
 		return -EINVAL;
 
-	lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl);
-	ctrl &= ~lis3_dev.odr_mask;
-	len = 1 << hweight_long(lis3_dev.odr_mask); /* # of possible values */
-	shift = ffs(lis3_dev.odr_mask) - 1;
+	lis3->read(lis3, CTRL_REG1, &ctrl);
+	ctrl &= ~lis3->odr_mask;
+	len = 1 << hweight_long(lis3->odr_mask); /* # of possible values */
+	shift = ffs(lis3->odr_mask) - 1;
 
 	for (i = 0; i < len; i++)
-		if (lis3_dev.odrs[i] == rate) {
-			lis3_dev.write(&lis3_dev, CTRL_REG1,
+		if (lis3->odrs[i] == rate) {
+			lis3->write(lis3, CTRL_REG1,
 					ctrl | (i << shift));
 			return 0;
 		}
@@ -240,12 +240,12 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
 	mutex_lock(&lis3->mutex);
 
 	irq_cfg = lis3->irq_cfg;
-	if (lis3_dev.whoami == WAI_8B) {
+	if (lis3->whoami == WAI_8B) {
 		lis3->data_ready_count[IRQ_LINE0] = 0;
 		lis3->data_ready_count[IRQ_LINE1] = 0;
 
 		/* Change interrupt cfg to data ready for selftest */
-		atomic_inc(&lis3_dev.wake_thread);
+		atomic_inc(&lis3->wake_thread);
 		lis3->irq_cfg = LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY;
 		lis3->read(lis3, CTRL_REG3, &ctrl_reg_data);
 		lis3->write(lis3, CTRL_REG3, (ctrl_reg_data &
@@ -253,12 +253,12 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
 				(LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY));
 	}
 
-	if (lis3_dev.whoami == WAI_3DC) {
+	if (lis3->whoami == WAI_3DC) {
 		ctlreg = CTRL_REG4;
 		selftest = CTRL4_ST0;
 	} else {
 		ctlreg = CTRL_REG1;
-		if (lis3_dev.whoami == WAI_12B)
+		if (lis3->whoami == WAI_12B)
 			selftest = CTRL1_ST;
 		else
 			selftest = CTRL1_STP;
@@ -266,7 +266,7 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
 
 	lis3->read(lis3, ctlreg, &reg);
 	lis3->write(lis3, ctlreg, (reg | selftest));
-	msleep(lis3->pwron_delay / lis3lv02d_get_odr());
+	msleep(lis3->pwron_delay / lis3lv02d_get_odr(lis3));
 
 	/* Read directly to avoid axis remap */
 	x = lis3->read_data(lis3, OUTX);
@@ -275,7 +275,7 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
 
 	/* back to normal settings */
 	lis3->write(lis3, ctlreg, reg);
-	msleep(lis3->pwron_delay / lis3lv02d_get_odr());
+	msleep(lis3->pwron_delay / lis3lv02d_get_odr(lis3));
 
 	results[0] = x - lis3->read_data(lis3, OUTX);
 	results[1] = y - lis3->read_data(lis3, OUTY);
@@ -283,9 +283,9 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
 
 	ret = 0;
 
-	if (lis3_dev.whoami == WAI_8B) {
+	if (lis3->whoami == WAI_8B) {
 		/* Restore original interrupt configuration */
-		atomic_dec(&lis3_dev.wake_thread);
+		atomic_dec(&lis3->wake_thread);
 		lis3->write(lis3, CTRL_REG3, ctrl_reg_data);
 		lis3->irq_cfg = irq_cfg;
 
@@ -383,7 +383,7 @@ void lis3lv02d_poweron(struct lis3lv02d *lis3)
 	lis3->write(lis3, CTRL_REG2, reg);
 
 	/* LIS3 power on delay is quite long */
-	msleep(lis3->pwron_delay / lis3lv02d_get_odr());
+	msleep(lis3->pwron_delay / lis3lv02d_get_odr(lis3));
 
 	if (lis3->reg_ctrl)
 		lis3_context_restore(lis3);
@@ -393,24 +393,27 @@ EXPORT_SYMBOL_GPL(lis3lv02d_poweron);
 
 static void lis3lv02d_joystick_poll(struct input_polled_dev *pidev)
 {
+	struct lis3lv02d *lis3 = pidev->private;
 	int x, y, z;
 
-	mutex_lock(&lis3_dev.mutex);
-	lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
+	mutex_lock(&lis3->mutex);
+	lis3lv02d_get_xyz(lis3, &x, &y, &z);
 	input_report_abs(pidev->input, ABS_X, x);
 	input_report_abs(pidev->input, ABS_Y, y);
 	input_report_abs(pidev->input, ABS_Z, z);
 	input_sync(pidev->input);
-	mutex_unlock(&lis3_dev.mutex);
+	mutex_unlock(&lis3->mutex);
 }
 
 static void lis3lv02d_joystick_open(struct input_polled_dev *pidev)
 {
-	if (lis3_dev.pm_dev)
-		pm_runtime_get_sync(lis3_dev.pm_dev);
+	struct lis3lv02d *lis3 = pidev->private;
 
-	if (lis3_dev.pdata && lis3_dev.whoami == WAI_8B && lis3_dev.idev)
-		atomic_set(&lis3_dev.wake_thread, 1);
+	if (lis3->pm_dev)
+		pm_runtime_get_sync(lis3->pm_dev);
+
+	if (lis3->pdata && lis3->whoami == WAI_8B && lis3->idev)
+		atomic_set(&lis3->wake_thread, 1);
 	/*
 	 * Update coordinates for the case where poll interval is 0 and
 	 * the chip in running purely under interrupt control
@@ -420,14 +423,18 @@ static void lis3lv02d_joystick_open(struct input_polled_dev *pidev)
 
 static void lis3lv02d_joystick_close(struct input_polled_dev *pidev)
 {
-	atomic_set(&lis3_dev.wake_thread, 0);
-	if (lis3_dev.pm_dev)
-		pm_runtime_put(lis3_dev.pm_dev);
+	struct lis3lv02d *lis3 = pidev->private;
+
+	atomic_set(&lis3->wake_thread, 0);
+	if (lis3->pm_dev)
+		pm_runtime_put(lis3->pm_dev);
 }
 
-static irqreturn_t lis302dl_interrupt(int irq, void *dummy)
+static irqreturn_t lis302dl_interrupt(int irq, void *data)
 {
-	if (!test_bit(0, &lis3_dev.misc_opened))
+	struct lis3lv02d *lis3 = data;
+
+	if (!test_bit(0, &lis3->misc_opened))
 		goto out;
 
 	/*
@@ -435,12 +442,12 @@ 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(&lis3_dev.count);
+	atomic_inc(&lis3->count);
 
-	wake_up_interruptible(&lis3_dev.misc_wait);
-	kill_fasync(&lis3_dev.async_queue, SIGIO, POLL_IN);
+	wake_up_interruptible(&lis3->misc_wait);
+	kill_fasync(&lis3->async_queue, SIGIO, POLL_IN);
 out:
-	if (atomic_read(&lis3_dev.wake_thread))
+	if (atomic_read(&lis3->wake_thread))
 		return IRQ_WAKE_THREAD;
 	return IRQ_HANDLED;
 }
@@ -512,28 +519,37 @@ static irqreturn_t lis302dl_interrupt_thread2_8b(int irq, void *data)
 
 static int lis3lv02d_misc_open(struct inode *inode, struct file *file)
 {
-	if (test_and_set_bit(0, &lis3_dev.misc_opened))
+	struct lis3lv02d *lis3 = container_of(file->private_data,
+					      struct lis3lv02d, miscdev);
+
+	if (test_and_set_bit(0, &lis3->misc_opened))
 		return -EBUSY; /* already open */
 
-	if (lis3_dev.pm_dev)
-		pm_runtime_get_sync(lis3_dev.pm_dev);
+	if (lis3->pm_dev)
+		pm_runtime_get_sync(lis3->pm_dev);
 
-	atomic_set(&lis3_dev.count, 0);
+	atomic_set(&lis3->count, 0);
 	return 0;
 }
 
 static int lis3lv02d_misc_release(struct inode *inode, struct file *file)
 {
-	fasync_helper(-1, file, 0, &lis3_dev.async_queue);
-	clear_bit(0, &lis3_dev.misc_opened); /* release the device */
-	if (lis3_dev.pm_dev)
-		pm_runtime_put(lis3_dev.pm_dev);
+	struct lis3lv02d *lis3 = container_of(file->private_data,
+					      struct lis3lv02d, miscdev);
+
+	fasync_helper(-1, file, 0, &lis3->async_queue);
+	clear_bit(0, &lis3->misc_opened); /* release the device */
+	if (lis3->pm_dev)
+		pm_runtime_put(lis3->pm_dev);
 	return 0;
 }
 
 static ssize_t lis3lv02d_misc_read(struct file *file, char __user *buf,
 				size_t count, loff_t *pos)
 {
+	struct lis3lv02d *lis3 = container_of(file->private_data,
+					      struct lis3lv02d, miscdev);
+
 	DECLARE_WAITQUEUE(wait, current);
 	u32 data;
 	unsigned char byte_data;
@@ -542,10 +558,10 @@ static ssize_t lis3lv02d_misc_read(struct file *file, char __user *buf,
 	if (count < 1)
 		return -EINVAL;
 
-	add_wait_queue(&lis3_dev.misc_wait, &wait);
+	add_wait_queue(&lis3->misc_wait, &wait);
 	while (true) {
 		set_current_state(TASK_INTERRUPTIBLE);
-		data = atomic_xchg(&lis3_dev.count, 0);
+		data = atomic_xchg(&lis3->count, 0);
 		if (data)
 			break;
 
@@ -575,22 +591,28 @@ static ssize_t lis3lv02d_misc_read(struct file *file, char __user *buf,
 
 out:
 	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(&lis3_dev.misc_wait, &wait);
+	remove_wait_queue(&lis3->misc_wait, &wait);
 
 	return retval;
 }
 
 static unsigned int lis3lv02d_misc_poll(struct file *file, poll_table *wait)
 {
-	poll_wait(file, &lis3_dev.misc_wait, wait);
-	if (atomic_read(&lis3_dev.count))
+	struct lis3lv02d *lis3 = container_of(file->private_data,
+					      struct lis3lv02d, miscdev);
+
+	poll_wait(file, &lis3->misc_wait, wait);
+	if (atomic_read(&lis3->count))
 		return POLLIN | POLLRDNORM;
 	return 0;
 }
 
 static int lis3lv02d_misc_fasync(int fd, struct file *file, int on)
 {
-	return fasync_helper(fd, file, on, &lis3_dev.async_queue);
+	struct lis3lv02d *lis3 = container_of(file->private_data,
+					      struct lis3lv02d, miscdev);
+
+	return fasync_helper(fd, file, on, &lis3->async_queue);
 }
 
 static const struct file_operations lis3lv02d_misc_fops = {
@@ -603,12 +625,6 @@ static const struct file_operations lis3lv02d_misc_fops = {
 	.fasync  = lis3lv02d_misc_fasync,
 };
 
-static struct miscdevice lis3lv02d_misc_device = {
-	.minor   = MISC_DYNAMIC_MINOR,
-	.name    = "freefall",
-	.fops    = &lis3lv02d_misc_fops,
-};
-
 int lis3lv02d_joystick_enable(struct lis3lv02d *lis3)
 {
 	struct input_dev *input_dev;
@@ -616,51 +632,52 @@ int lis3lv02d_joystick_enable(struct lis3lv02d *lis3)
 	int max_val, fuzz, flat;
 	int btns[] = {BTN_X, BTN_Y, BTN_Z};
 
-	if (lis3_dev.idev)
+	if (lis3->idev)
 		return -EINVAL;
 
-	lis3_dev.idev = input_allocate_polled_device();
-	if (!lis3_dev.idev)
+	lis3->idev = input_allocate_polled_device();
+	if (!lis3->idev)
 		return -ENOMEM;
 
-	lis3_dev.idev->poll = lis3lv02d_joystick_poll;
-	lis3_dev.idev->open = lis3lv02d_joystick_open;
-	lis3_dev.idev->close = lis3lv02d_joystick_close;
-	lis3_dev.idev->poll_interval = MDPS_POLL_INTERVAL;
-	lis3_dev.idev->poll_interval_min = MDPS_POLL_MIN;
-	lis3_dev.idev->poll_interval_max = MDPS_POLL_MAX;
-	input_dev = lis3_dev.idev->input;
+	lis3->idev->poll = lis3lv02d_joystick_poll;
+	lis3->idev->open = lis3lv02d_joystick_open;
+	lis3->idev->close = lis3lv02d_joystick_close;
+	lis3->idev->poll_interval = MDPS_POLL_INTERVAL;
+	lis3->idev->poll_interval_min = MDPS_POLL_MIN;
+	lis3->idev->poll_interval_max = MDPS_POLL_MAX;
+	lis3->idev->private = lis3;
+	input_dev = lis3->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;
+	input_dev->dev.parent = &lis3->pdev->dev;
 
 	set_bit(EV_ABS, input_dev->evbit);
-	max_val = (lis3_dev.mdps_max_val * lis3_dev.scale) / LIS3_ACCURACY;
-	if (lis3_dev.whoami == WAI_12B) {
+	max_val = (lis3->mdps_max_val * lis3->scale) / LIS3_ACCURACY;
+	if (lis3->whoami == WAI_12B) {
 		fuzz = LIS3_DEFAULT_FUZZ_12B;
 		flat = LIS3_DEFAULT_FLAT_12B;
 	} else {
 		fuzz = LIS3_DEFAULT_FUZZ_8B;
 		flat = LIS3_DEFAULT_FLAT_8B;
 	}
-	fuzz = (fuzz * lis3_dev.scale) / LIS3_ACCURACY;
-	flat = (flat * lis3_dev.scale) / LIS3_ACCURACY;
+	fuzz = (fuzz * lis3->scale) / LIS3_ACCURACY;
+	flat = (flat * lis3->scale) / LIS3_ACCURACY;
 
 	input_set_abs_params(input_dev, ABS_X, -max_val, max_val, fuzz, flat);
 	input_set_abs_params(input_dev, ABS_Y, -max_val, max_val, fuzz, flat);
 	input_set_abs_params(input_dev, ABS_Z, -max_val, max_val, fuzz, flat);
 
-	lis3_dev.mapped_btns[0] = lis3lv02d_get_axis(abs(lis3_dev.ac.x), btns);
-	lis3_dev.mapped_btns[1] = lis3lv02d_get_axis(abs(lis3_dev.ac.y), btns);
-	lis3_dev.mapped_btns[2] = lis3lv02d_get_axis(abs(lis3_dev.ac.z), btns);
+	lis3->mapped_btns[0] = lis3lv02d_get_axis(abs(lis3->ac.x), btns);
+	lis3->mapped_btns[1] = lis3lv02d_get_axis(abs(lis3->ac.y), btns);
+	lis3->mapped_btns[2] = lis3lv02d_get_axis(abs(lis3->ac.z), btns);
 
-	err = input_register_polled_device(lis3_dev.idev);
+	err = input_register_polled_device(lis3->idev);
 	if (err) {
-		input_free_polled_device(lis3_dev.idev);
-		lis3_dev.idev = NULL;
+		input_free_polled_device(lis3->idev);
+		lis3->idev = NULL;
 	}
 
 	return err;
@@ -669,19 +686,19 @@ EXPORT_SYMBOL_GPL(lis3lv02d_joystick_enable);
 
 void lis3lv02d_joystick_disable(struct lis3lv02d *lis3)
 {
-	if (lis3_dev.irq)
-		free_irq(lis3_dev.irq, &lis3_dev);
-	if (lis3_dev.pdata && lis3_dev.pdata->irq2)
-		free_irq(lis3_dev.pdata->irq2, &lis3_dev);
+	if (lis3->irq)
+		free_irq(lis3->irq, lis3);
+	if (lis3->pdata && lis3->pdata->irq2)
+		free_irq(lis3->pdata->irq2, lis3);
 
-	if (!lis3_dev.idev)
+	if (!lis3->idev)
 		return;
 
-	if (lis3_dev.irq)
-		misc_deregister(&lis3lv02d_misc_device);
-	input_unregister_polled_device(lis3_dev.idev);
-	input_free_polled_device(lis3_dev.idev);
-	lis3_dev.idev = NULL;
+	if (lis3->irq)
+		misc_deregister(&lis3->miscdev);
+	input_unregister_polled_device(lis3->idev);
+	input_free_polled_device(lis3->idev);
+	lis3->idev = NULL;
 }
 EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable);
 
@@ -706,6 +723,7 @@ static void lis3lv02d_sysfs_poweron(struct lis3lv02d *lis3)
 static ssize_t lis3lv02d_selftest_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
+	struct lis3lv02d *lis3 = dev_get_drvdata(dev);
 	s16 values[3];
 
 	static const char ok[] = "OK";
@@ -713,8 +731,8 @@ static ssize_t lis3lv02d_selftest_show(struct device *dev,
 	static const char irq[] = "FAIL_IRQ";
 	const char *res;
 
-	lis3lv02d_sysfs_poweron(&lis3_dev);
-	switch (lis3lv02d_selftest(&lis3_dev, values)) {
+	lis3lv02d_sysfs_poweron(lis3);
+	switch (lis3lv02d_selftest(lis3, values)) {
 	case SELFTEST_FAIL:
 		res = fail;
 		break;
@@ -733,33 +751,37 @@ static ssize_t lis3lv02d_selftest_show(struct device *dev,
 static ssize_t lis3lv02d_position_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
+	struct lis3lv02d *lis3 = dev_get_drvdata(dev);
 	int x, y, z;
 
-	lis3lv02d_sysfs_poweron(&lis3_dev);
-	mutex_lock(&lis3_dev.mutex);
-	lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
-	mutex_unlock(&lis3_dev.mutex);
+	lis3lv02d_sysfs_poweron(lis3);
+	mutex_lock(&lis3->mutex);
+	lis3lv02d_get_xyz(lis3, &x, &y, &z);
+	mutex_unlock(&lis3->mutex);
 	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)
 {
-	lis3lv02d_sysfs_poweron(&lis3_dev);
-	return sprintf(buf, "%d\n", lis3lv02d_get_odr());
+	struct lis3lv02d *lis3 = dev_get_drvdata(dev);
+
+	lis3lv02d_sysfs_poweron(lis3);
+	return sprintf(buf, "%d\n", lis3lv02d_get_odr(lis3));
 }
 
 static ssize_t lis3lv02d_rate_set(struct device *dev,
 				struct device_attribute *attr, const char *buf,
 				size_t count)
 {
+	struct lis3lv02d *lis3 = dev_get_drvdata(dev);
 	unsigned long rate;
 
 	if (strict_strtoul(buf, 0, &rate))
 		return -EINVAL;
 
-	lis3lv02d_sysfs_poweron(&lis3_dev);
-	if (lis3lv02d_set_odr(rate))
+	lis3lv02d_sysfs_poweron(lis3);
+	if (lis3lv02d_set_odr(lis3, rate))
 		return -EINVAL;
 
 	return count;
@@ -788,6 +810,7 @@ static int lis3lv02d_add_fs(struct lis3lv02d *lis3)
 	if (IS_ERR(lis3->pdev))
 		return PTR_ERR(lis3->pdev);
 
+	platform_set_drvdata(lis3->pdev, lis3);
 	return sysfs_create_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group);
 }
 
@@ -801,7 +824,7 @@ int lis3lv02d_remove_fs(struct lis3lv02d *lis3)
 
 		/* SYSFS may have left chip running. Turn off if necessary */
 		if (!pm_runtime_suspended(lis3->pm_dev))
-			lis3lv02d_poweroff(&lis3_dev);
+			lis3lv02d_poweroff(lis3);
 
 		pm_runtime_disable(lis3->pm_dev);
 		pm_runtime_set_suspended(lis3->pm_dev);
@@ -828,7 +851,7 @@ static void lis3lv02d_8b_configure(struct lis3lv02d *lis3,
 			(p->click_thresh_y << 4));
 
 		if (lis3->idev) {
-			struct input_dev *input_dev = lis3_dev.idev->input;
+			struct input_dev *input_dev = lis3->idev->input;
 			input_set_capability(input_dev, EV_KEY, BTN_X);
 			input_set_capability(input_dev, EV_KEY, BTN_Y);
 			input_set_capability(input_dev, EV_KEY, BTN_Z);
@@ -859,7 +882,7 @@ static void lis3lv02d_8b_configure(struct lis3lv02d *lis3,
 					lis302dl_interrupt_thread2_8b,
 					IRQF_TRIGGER_RISING | IRQF_ONESHOT |
 					(p->irq_flags2 & IRQF_TRIGGER_MASK),
-					DRIVER_NAME, &lis3_dev);
+					DRIVER_NAME, lis3);
 		if (err < 0)
 			pr_err("No second IRQ. Limited functionality\n");
 	}
@@ -951,7 +974,7 @@ int lis3lv02d_init_device(struct lis3lv02d *lis3)
 			lis3->write(lis3, CTRL_REG3, p->irq_cfg);
 
 		if (p->default_rate)
-			lis3lv02d_set_odr(p->default_rate);
+			lis3lv02d_set_odr(lis3, p->default_rate);
 	}
 
 	/* bail if we did not get an IRQ from the bus layer */
@@ -980,14 +1003,18 @@ int lis3lv02d_init_device(struct lis3lv02d *lis3)
 				thread_fn,
 				IRQF_TRIGGER_RISING | IRQF_ONESHOT |
 				irq_flags,
-				DRIVER_NAME, &lis3_dev);
+				DRIVER_NAME, lis3);
 
 	if (err < 0) {
 		pr_err("Cannot get IRQ\n");
 		goto out;
 	}
 
-	if (misc_register(&lis3lv02d_misc_device))
+	lis3->miscdev.minor	= MISC_DYNAMIC_MINOR;
+	lis3->miscdev.name	= "freefall";
+	lis3->miscdev.fops	= &lis3lv02d_misc_fops;
+
+	if (misc_register(&lis3->miscdev))
 		pr_err("misc_register failed\n");
 out:
 	return 0;
diff --git a/drivers/misc/lis3lv02d/lis3lv02d.h b/drivers/misc/lis3lv02d/lis3lv02d.h
index 49cb1f1..7d0f554 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d.h
+++ b/drivers/misc/lis3lv02d/lis3lv02d.h
@@ -21,6 +21,7 @@
 #include <linux/platform_device.h>
 #include <linux/input-polldev.h>
 #include <linux/regulator/consumer.h>
+#include <linux/miscdevice.h>
 
 /*
  * This driver tries to support the "digital" accelerometer chips from
@@ -273,6 +274,8 @@ struct lis3lv02d {
 	struct fasync_struct	*async_queue; /* queue for the misc device */
 	wait_queue_head_t	misc_wait; /* Wait queue for the misc device */
 	unsigned long		misc_opened; /* bit0: whether the device is open */
+	struct miscdevice	miscdev;
+
 	int                     data_ready_count[2];
 	atomic_t		wake_thread;
 	unsigned char           irq_cfg;
-- 
1.7.0.4


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [RFC PATCHv2 5/5] hwmon: lis3: Register hwif and remove references to global variable
  2011-04-05 14:45 [RFC PATCHv2 0/5] lis3lv02d: Regulator fix & support for multiple devices Ilkka Koskinen
                   ` (3 preceding siblings ...)
  2011-04-05 14:45 ` [RFC PATCHv2 4/5] hwmon: lis3: Remove the referencies to the global variable in core driver Ilkka Koskinen
@ 2011-04-05 14:45 ` Ilkka Koskinen
  4 siblings, 0 replies; 10+ messages in thread
From: Ilkka Koskinen @ 2011-04-05 14:45 UTC (permalink / raw)
  To: eric.piel, mjg
  Cc: linux-kernel, platform-driver-x86, samu.p.onkalo, ilkka.koskinen

This patch introduces an interface, which clients may allocate
new hw interface for lis3 device. In addition, the global lis3
device is removed and the devices are allocated dynamically.
That is, several lis3 devices can be supported and multiple
hw interfaces can be enabled without introducing problems.

Signed-off-by: Ilkka Koskinen <ilkka.koskinen@nokia.com>
---
 drivers/misc/lis3lv02d/lis3lv02d.c     |   30 +++++++++++++---
 drivers/misc/lis3lv02d/lis3lv02d.h     |    4 +-
 drivers/misc/lis3lv02d/lis3lv02d_i2c.c |   60 ++++++++++++++++++--------------
 drivers/misc/lis3lv02d/lis3lv02d_spi.c |   33 ++++++++++++------
 drivers/platform/x86/hp_accel.c        |   52 ++++++++++++++++-----------
 5 files changed, 113 insertions(+), 66 deletions(-)

diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c
index 11cbe57..bec9ca3 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d.c
+++ b/drivers/misc/lis3lv02d/lis3lv02d.c
@@ -85,11 +85,6 @@
 #define LIS3_DEFAULT_FUZZ_8B		1
 #define LIS3_DEFAULT_FLAT_8B		1
 
-struct lis3lv02d lis3_dev = {
-	.misc_wait   = __WAIT_QUEUE_HEAD_INITIALIZER(lis3_dev.misc_wait),
-};
-EXPORT_SYMBOL_GPL(lis3_dev);
-
 /* just like param_set_int() but does sanity-check so that it won't point
  * over the axis array size
  */
@@ -111,7 +106,8 @@ static struct kernel_param_ops param_ops_axis = {
 	.get = param_get_int,
 };
 
-module_param_array_named(axes, lis3_dev.ac.as_array, axis, NULL, 0644);
+static union axis_conversion ac;
+module_param_array_named(axes, ac.as_array, axis, NULL, 0644);
 MODULE_PARM_DESC(axes, "Axis-mapping for x,y,z directions");
 
 static s16 lis3lv02d_read_8(struct lis3lv02d *lis3, int reg)
@@ -888,6 +884,28 @@ static void lis3lv02d_8b_configure(struct lis3lv02d *lis3,
 	}
 }
 
+struct lis3lv02d *lis3_allocate_device(void)
+{
+	struct lis3lv02d *lis3;
+
+	lis3 = kzalloc(sizeof(*lis3), GFP_KERNEL);
+	if (!lis3)
+		return NULL;
+
+	init_waitqueue_head(&lis3->misc_wait);
+	memcpy(&lis3->ac.as_array, &ac.as_array,
+	       sizeof(lis3->ac.as_array));
+
+	return lis3;
+}
+EXPORT_SYMBOL(lis3_allocate_device);
+
+void lis3_free_device(struct lis3lv02d *lis3)
+{
+	kfree(lis3);
+}
+EXPORT_SYMBOL(lis3_free_device);
+
 /*
  * Initialise the accelerometer and the various subsystems.
  * Should be rather independent of the bus system.
diff --git a/drivers/misc/lis3lv02d/lis3lv02d.h b/drivers/misc/lis3lv02d/lis3lv02d.h
index 7d0f554..ef077d5 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d.h
+++ b/drivers/misc/lis3lv02d/lis3lv02d.h
@@ -290,5 +290,5 @@ void lis3lv02d_joystick_disable(struct lis3lv02d *lis3);
 void lis3lv02d_poweroff(struct lis3lv02d *lis3);
 void lis3lv02d_poweron(struct lis3lv02d *lis3);
 int lis3lv02d_remove_fs(struct lis3lv02d *lis3);
-
-extern struct lis3lv02d lis3_dev;
+struct lis3lv02d *lis3_allocate_device(void);
+void lis3_free_device(struct lis3lv02d *lis3);
diff --git a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
index 6cdc38f..108d05d 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
+++ b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
@@ -104,16 +104,21 @@ static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client,
 {
 	int ret = 0;
 	struct lis3lv02d_platform_data *pdata = client->dev.platform_data;
+	struct lis3lv02d *lis3;
+
+	lis3 = lis3_allocate_device();
+	if (!lis3)
+		return -ENOMEM;
 
 	if (pdata) {
 		/* Regulator control is optional */
 		if (pdata->driver_features & LIS3_USE_REGULATOR_CTRL)
-			lis3_dev.reg_ctrl = lis3_reg_ctrl;
+			lis3->reg_ctrl = lis3_reg_ctrl;
 
 		if ((pdata->driver_features & LIS3_USE_BLOCK_READ) &&
 			(i2c_check_functionality(client->adapter,
 						I2C_FUNC_SMBUS_I2C_BLOCK)))
-			lis3_dev.blkread  = lis3_i2c_blockread;
+			lis3->blkread  = lis3_i2c_blockread;
 
 		if (pdata->axis_x)
 			lis3lv02d_axis_map.x = pdata->axis_x;
@@ -131,44 +136,45 @@ static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client,
 			goto fail;
 	}
 
-	if (lis3_dev.reg_ctrl) {
-		lis3_dev.regulators[0].supply = reg_vdd;
-		lis3_dev.regulators[1].supply = reg_vdd_io;
+	if (lis3->reg_ctrl) {
+		lis3->regulators[0].supply = reg_vdd;
+		lis3->regulators[1].supply = reg_vdd_io;
 		ret = regulator_bulk_get(&client->dev,
-					ARRAY_SIZE(lis3_dev.regulators),
-					lis3_dev.regulators);
+					ARRAY_SIZE(lis3->regulators),
+					lis3->regulators);
 		if (ret < 0)
 			goto fail;
 	}
 
-	lis3_dev.pdata	  = pdata;
-	lis3_dev.bus_priv = client;
-	lis3_dev.init	  = lis3_i2c_init;
-	lis3_dev.read	  = lis3_i2c_read;
-	lis3_dev.write	  = lis3_i2c_write;
-	lis3_dev.irq	  = client->irq;
-	lis3_dev.ac	  = lis3lv02d_axis_map;
-	lis3_dev.pm_dev	  = &client->dev;
+	lis3->pdata	  = pdata;
+	lis3->bus_priv	  = client;
+	lis3->init	  = lis3_i2c_init;
+	lis3->read	  = lis3_i2c_read;
+	lis3->write	  = lis3_i2c_write;
+	lis3->irq	  = client->irq;
+	lis3->ac	  = lis3lv02d_axis_map;
+	lis3->pm_dev	  = &client->dev;
 
-	i2c_set_clientdata(client, &lis3_dev);
+	i2c_set_clientdata(client, lis3);
 
 	/* Provide power over the init call */
-	if (lis3_dev.reg_ctrl)
-		lis3_reg_ctrl(&lis3_dev, LIS3_REG_ON);
+	if (lis3->reg_ctrl)
+		lis3_reg_ctrl(lis3, LIS3_REG_ON);
 
-	ret = lis3lv02d_init_device(&lis3_dev);
+	ret = lis3lv02d_init_device(lis3);
 
-	if (lis3_dev.reg_ctrl)
-		lis3_reg_ctrl(&lis3_dev, LIS3_REG_OFF);
+	if (lis3->reg_ctrl)
+		lis3_reg_ctrl(lis3, LIS3_REG_OFF);
 
 	if (ret)
 		goto fail2;
 	return 0;
 
 fail2:
-	regulator_bulk_free(ARRAY_SIZE(lis3_dev.regulators),
-				lis3_dev.regulators);
+	regulator_bulk_free(ARRAY_SIZE(lis3->regulators),
+				lis3->regulators);
 fail:
+	lis3_free_device(lis3);
 	if (pdata && pdata->release_resources)
 		pdata->release_resources();
 	return ret;
@@ -183,11 +189,13 @@ static int __devexit lis3lv02d_i2c_remove(struct i2c_client *client)
 		pdata->release_resources();
 
 	lis3lv02d_joystick_disable(lis3);
-	lis3lv02d_remove_fs(&lis3_dev);
+	lis3lv02d_remove_fs(lis3);
 
-	if (lis3_dev.reg_ctrl)
+	if (lis3->reg_ctrl)
 		regulator_bulk_free(ARRAY_SIZE(lis3->regulators),
-				lis3_dev.regulators);
+				lis3->regulators);
+
+	lis3_free_device(lis3);
 	return 0;
 }
 
diff --git a/drivers/misc/lis3lv02d/lis3lv02d_spi.c b/drivers/misc/lis3lv02d/lis3lv02d_spi.c
index b2c1be1..c078f38 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d_spi.c
+++ b/drivers/misc/lis3lv02d/lis3lv02d_spi.c
@@ -61,6 +61,7 @@ static union axis_conversion lis3lv02d_axis_normal =
 static int __devinit lis302dl_spi_probe(struct spi_device *spi)
 {
 	int ret;
+	struct lis3lv02d *lis3;
 
 	spi->bits_per_word = 8;
 	spi->mode = SPI_MODE_0;
@@ -68,16 +69,24 @@ static int __devinit lis302dl_spi_probe(struct spi_device *spi)
 	if (ret < 0)
 		return ret;
 
-	lis3_dev.bus_priv	= spi;
-	lis3_dev.init		= lis3_spi_init;
-	lis3_dev.read		= lis3_spi_read;
-	lis3_dev.write		= lis3_spi_write;
-	lis3_dev.irq		= spi->irq;
-	lis3_dev.ac		= lis3lv02d_axis_normal;
-	lis3_dev.pdata		= spi->dev.platform_data;
-	spi_set_drvdata(spi, &lis3_dev);
+	lis3 = lis3_allocate_device();
+	if (!lis3)
+		return -ENOMEM;
 
-	return lis3lv02d_init_device(&lis3_dev);
+	lis3->bus_priv		= spi;
+	lis3->init		= lis3_spi_init;
+	lis3->read		= lis3_spi_read;
+	lis3->write		= lis3_spi_write;
+	lis3->irq		= spi->irq;
+	lis3->ac		= lis3lv02d_axis_normal;
+	lis3->pdata		= spi->dev.platform_data;
+	spi_set_drvdata(spi, lis3);
+
+	ret = lis3lv02d_init_device(lis3);
+	if (ret < 0)
+		lis3_free_device(lis3);
+
+	return ret;
 }
 
 static int __devexit lis302dl_spi_remove(struct spi_device *spi)
@@ -86,7 +95,9 @@ static int __devexit lis302dl_spi_remove(struct spi_device *spi)
 	lis3lv02d_joystick_disable(lis3);
 	lis3lv02d_poweroff(lis3);
 
-	return lis3lv02d_remove_fs(&lis3_dev);
+	lis3lv02d_remove_fs(lis3);
+	lis3_free_device(lis3);
+	return 0;
 }
 
 #ifdef CONFIG_PM_SLEEP
@@ -96,7 +107,7 @@ static int lis3lv02d_spi_suspend(struct device *dev)
 	struct lis3lv02d *lis3 = spi_get_drvdata(spi);
 
 	if (!lis3->pdata || !lis3->pdata->wakeup_flags)
-		lis3lv02d_poweroff(&lis3_dev);
+		lis3lv02d_poweroff(lis3);
 
 	return 0;
 }
diff --git a/drivers/platform/x86/hp_accel.c b/drivers/platform/x86/hp_accel.c
index 2148d77..fb31669 100644
--- a/drivers/platform/x86/hp_accel.c
+++ b/drivers/platform/x86/hp_accel.c
@@ -54,6 +54,8 @@ struct delayed_led_classdev {
 	void (*set_brightness)(struct delayed_led_classdev *data, enum led_brightness value);
 };
 
+struct lis3lv02d *lis3_dev;
+
 static inline void delayed_set_status_worker(struct work_struct *work)
 {
 	struct delayed_led_classdev *data =
@@ -148,7 +150,7 @@ int lis3lv02d_acpi_write(struct lis3lv02d *lis3, int reg, u8 val)
 
 static int lis3lv02d_dmi_matched(const struct dmi_system_id *dmi)
 {
-	lis3_dev.ac = *((union axis_conversion *)dmi->driver_data);
+	lis3_dev->ac = *((union axis_conversion *)dmi->driver_data);
 	pr_info("hardware type %s found\n", dmi->ident);
 
 	return 1;
@@ -240,7 +242,7 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = {
 
 static void hpled_set(struct delayed_led_classdev *led_cdev, enum led_brightness value)
 {
-	struct acpi_device *dev = lis3_dev.bus_priv;
+	struct acpi_device *dev = lis3_dev->bus_priv;
 	unsigned long long ret; /* Not used when writing */
 	union acpi_object in_obj[1];
 	struct acpi_object_list args = { 1, in_obj };
@@ -280,7 +282,7 @@ static void lis3lv02d_enum_resources(struct acpi_device *device)
 	acpi_status status;
 
 	status = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
-					lis3lv02d_get_resource, &lis3_dev.irq);
+					lis3lv02d_get_resource, &lis3_dev->irq);
 	if (ACPI_FAILURE(status))
 		printk(KERN_DEBUG DRIVER_NAME ": Error getting resources\n");
 }
@@ -292,41 +294,49 @@ static int lis3lv02d_add(struct acpi_device *device)
 	if (!device)
 		return -EINVAL;
 
-	lis3_dev.bus_priv = device;
-	lis3_dev.init = lis3lv02d_acpi_init;
-	lis3_dev.read = lis3lv02d_acpi_read;
-	lis3_dev.write = lis3lv02d_acpi_write;
+	lis3_dev = lis3_allocate_device();
+	if (!lis3_dev)
+		return -ENOMEM;
+
+	lis3_dev->bus_priv = device;
+	lis3_dev->init = lis3lv02d_acpi_init;
+	lis3_dev->read = lis3lv02d_acpi_read;
+	lis3_dev->write = lis3lv02d_acpi_write;
 	strcpy(acpi_device_name(device), DRIVER_NAME);
 	strcpy(acpi_device_class(device), ACPI_MDPS_CLASS);
-	device->driver_data = &lis3_dev;
+	device->driver_data = lis3_dev;
 
 	/* obtain IRQ number of our device from ACPI */
 	lis3lv02d_enum_resources(device);
 
 	/* If possible use a "standard" axes order */
-	if (lis3_dev.ac.x && lis3_dev.ac.y && lis3_dev.ac.z) {
+	if (lis3_dev->ac.x && lis3_dev->ac.y && lis3_dev->ac.z) {
 		pr_info("Using custom axes %d,%d,%d\n",
-			lis3_dev.ac.x, lis3_dev.ac.y, lis3_dev.ac.z);
+			lis3_dev->ac.x, lis3_dev->ac.y, lis3_dev->ac.z);
 	} else if (dmi_check_system(lis3lv02d_dmi_ids) == 0) {
 		pr_info("laptop model unknown, using default axes configuration\n");
-		lis3_dev.ac = lis3lv02d_axis_normal;
+		lis3_dev->ac = lis3lv02d_axis_normal;
 	}
 
 	/* call the core layer do its init */
-	ret = lis3lv02d_init_device(&lis3_dev);
+	ret = lis3lv02d_init_device(lis3_dev);
 	if (ret)
-		return ret;
+		goto fail;
 
 	INIT_WORK(&hpled_led.work, delayed_set_status_worker);
 	ret = led_classdev_register(NULL, &hpled_led.led_classdev);
 	if (ret) {
-		lis3lv02d_joystick_disable(&lis3_dev);
-		lis3lv02d_poweroff(&lis3_dev);
+		lis3lv02d_joystick_disable(lis3_dev);
+		lis3lv02d_poweroff(lis3_dev);
 		flush_work(&hpled_led.work);
-		return ret;
+		goto fail;
 	}
 
 	return ret;
+
+fail:
+	lis3_free_device(lis3_dev);
+	return ret;
 }
 
 static int lis3lv02d_remove(struct acpi_device *device, int type)
@@ -334,13 +344,13 @@ static int lis3lv02d_remove(struct acpi_device *device, int type)
 	if (!device)
 		return -EINVAL;
 
-	lis3lv02d_joystick_disable(&lis3_dev);
-	lis3lv02d_poweroff(&lis3_dev);
+	lis3lv02d_joystick_disable(lis3_dev);
+	lis3lv02d_poweroff(lis3_dev);
 
 	led_classdev_unregister(&hpled_led.led_classdev);
 	flush_work(&hpled_led.work);
 
-	return lis3lv02d_remove_fs(&lis3_dev);
+	return lis3lv02d_remove_fs(lis3_dev);
 }
 
 
@@ -348,13 +358,13 @@ static int lis3lv02d_remove(struct acpi_device *device, int type)
 static int lis3lv02d_suspend(struct acpi_device *device, pm_message_t state)
 {
 	/* make sure the device is off when we suspend */
-	lis3lv02d_poweroff(&lis3_dev);
+	lis3lv02d_poweroff(lis3_dev);
 	return 0;
 }
 
 static int lis3lv02d_resume(struct acpi_device *device)
 {
-	lis3lv02d_poweron(&lis3_dev);
+	lis3lv02d_poweron(lis3_dev);
 	return 0;
 }
 #else
-- 
1.7.0.4


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCHv2 4/5] hwmon: lis3: Remove the referencies to the global variable in core driver
  2011-04-05 14:45 ` [RFC PATCHv2 4/5] hwmon: lis3: Remove the referencies to the global variable in core driver Ilkka Koskinen
@ 2011-04-05 15:50   ` Thadeu Lima de Souza Cascardo
  2011-04-07 11:59     ` Ilkka Koskinen
  0 siblings, 1 reply; 10+ messages in thread
From: Thadeu Lima de Souza Cascardo @ 2011-04-05 15:50 UTC (permalink / raw)
  To: Ilkka Koskinen
  Cc: eric.piel, mjg, linux-kernel, platform-driver-x86, samu.p.onkalo

[-- Attachment #1: Type: text/plain, Size: 21278 bytes --]

On Tue, Apr 05, 2011 at 05:45:13PM +0300, Ilkka Koskinen wrote:
> Signed-off-by: Ilkka Koskinen <ilkka.koskinen@nokia.com>
> ---
>  drivers/misc/lis3lv02d/lis3lv02d.c |  237 ++++++++++++++++++++----------------
>  drivers/misc/lis3lv02d/lis3lv02d.h |    3 +
>  2 files changed, 135 insertions(+), 105 deletions(-)
> 
> diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c
> index b548afc..11cbe57 100644
> --- a/drivers/misc/lis3lv02d/lis3lv02d.c
> +++ b/drivers/misc/lis3lv02d/lis3lv02d.c
> @@ -163,7 +163,7 @@ static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z)
>  	int i;
>  
>  	if (lis3->blkread) {
> -		if (lis3_dev.whoami == WAI_12B) {
> +		if (lis3->whoami == WAI_12B) {
>  			u16 data[3];
>  			lis3->blkread(lis3, OUTX_L, 6, (u8 *)data);
>  			for (i = 0; i < 3; i++)
> @@ -195,18 +195,18 @@ static int lis3_8_rates[2] = {100, 400};
>  static int lis3_3dc_rates[16] = {0, 1, 10, 25, 50, 100, 200, 400, 1600, 5000};
>  
>  /* ODR is Output Data Rate */
> -static int lis3lv02d_get_odr(void)
> +static int lis3lv02d_get_odr(struct lis3lv02d *lis3)
>  {
>  	u8 ctrl;
>  	int shift;
>  
> -	lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl);
> -	ctrl &= lis3_dev.odr_mask;
> -	shift = ffs(lis3_dev.odr_mask) - 1;
> -	return lis3_dev.odrs[(ctrl >> shift)];
> +	lis3->read(lis3, CTRL_REG1, &ctrl);
> +	ctrl &= lis3->odr_mask;
> +	shift = ffs(lis3->odr_mask) - 1;
> +	return lis3->odrs[(ctrl >> shift)];
>  }
>  
> -static int lis3lv02d_set_odr(int rate)
> +static int lis3lv02d_set_odr(struct lis3lv02d *lis3, int rate)
>  {
>  	u8 ctrl;
>  	int i, len, shift;
> @@ -214,14 +214,14 @@ static int lis3lv02d_set_odr(int rate)
>  	if (!rate)
>  		return -EINVAL;
>  
> -	lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl);
> -	ctrl &= ~lis3_dev.odr_mask;
> -	len = 1 << hweight_long(lis3_dev.odr_mask); /* # of possible values */
> -	shift = ffs(lis3_dev.odr_mask) - 1;
> +	lis3->read(lis3, CTRL_REG1, &ctrl);
> +	ctrl &= ~lis3->odr_mask;
> +	len = 1 << hweight_long(lis3->odr_mask); /* # of possible values */
> +	shift = ffs(lis3->odr_mask) - 1;
>  
>  	for (i = 0; i < len; i++)
> -		if (lis3_dev.odrs[i] == rate) {
> -			lis3_dev.write(&lis3_dev, CTRL_REG1,
> +		if (lis3->odrs[i] == rate) {
> +			lis3->write(lis3, CTRL_REG1,
>  					ctrl | (i << shift));
>  			return 0;
>  		}
> @@ -240,12 +240,12 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
>  	mutex_lock(&lis3->mutex);
>  
>  	irq_cfg = lis3->irq_cfg;
> -	if (lis3_dev.whoami == WAI_8B) {
> +	if (lis3->whoami == WAI_8B) {
>  		lis3->data_ready_count[IRQ_LINE0] = 0;
>  		lis3->data_ready_count[IRQ_LINE1] = 0;
>  
>  		/* Change interrupt cfg to data ready for selftest */
> -		atomic_inc(&lis3_dev.wake_thread);
> +		atomic_inc(&lis3->wake_thread);
>  		lis3->irq_cfg = LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY;
>  		lis3->read(lis3, CTRL_REG3, &ctrl_reg_data);
>  		lis3->write(lis3, CTRL_REG3, (ctrl_reg_data &
> @@ -253,12 +253,12 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
>  				(LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY));
>  	}
>  
> -	if (lis3_dev.whoami == WAI_3DC) {
> +	if (lis3->whoami == WAI_3DC) {
>  		ctlreg = CTRL_REG4;
>  		selftest = CTRL4_ST0;
>  	} else {
>  		ctlreg = CTRL_REG1;
> -		if (lis3_dev.whoami == WAI_12B)
> +		if (lis3->whoami == WAI_12B)
>  			selftest = CTRL1_ST;
>  		else
>  			selftest = CTRL1_STP;
> @@ -266,7 +266,7 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
>  
>  	lis3->read(lis3, ctlreg, &reg);
>  	lis3->write(lis3, ctlreg, (reg | selftest));
> -	msleep(lis3->pwron_delay / lis3lv02d_get_odr());
> +	msleep(lis3->pwron_delay / lis3lv02d_get_odr(lis3));
>  
>  	/* Read directly to avoid axis remap */
>  	x = lis3->read_data(lis3, OUTX);
> @@ -275,7 +275,7 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
>  
>  	/* back to normal settings */
>  	lis3->write(lis3, ctlreg, reg);
> -	msleep(lis3->pwron_delay / lis3lv02d_get_odr());
> +	msleep(lis3->pwron_delay / lis3lv02d_get_odr(lis3));
>  
>  	results[0] = x - lis3->read_data(lis3, OUTX);
>  	results[1] = y - lis3->read_data(lis3, OUTY);
> @@ -283,9 +283,9 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
>  
>  	ret = 0;
>  
> -	if (lis3_dev.whoami == WAI_8B) {
> +	if (lis3->whoami == WAI_8B) {
>  		/* Restore original interrupt configuration */
> -		atomic_dec(&lis3_dev.wake_thread);
> +		atomic_dec(&lis3->wake_thread);
>  		lis3->write(lis3, CTRL_REG3, ctrl_reg_data);
>  		lis3->irq_cfg = irq_cfg;
>  
> @@ -383,7 +383,7 @@ void lis3lv02d_poweron(struct lis3lv02d *lis3)
>  	lis3->write(lis3, CTRL_REG2, reg);
>  
>  	/* LIS3 power on delay is quite long */
> -	msleep(lis3->pwron_delay / lis3lv02d_get_odr());
> +	msleep(lis3->pwron_delay / lis3lv02d_get_odr(lis3));
>  
>  	if (lis3->reg_ctrl)
>  		lis3_context_restore(lis3);
> @@ -393,24 +393,27 @@ EXPORT_SYMBOL_GPL(lis3lv02d_poweron);
>  
>  static void lis3lv02d_joystick_poll(struct input_polled_dev *pidev)
>  {
> +	struct lis3lv02d *lis3 = pidev->private;
>  	int x, y, z;
>  
> -	mutex_lock(&lis3_dev.mutex);
> -	lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
> +	mutex_lock(&lis3->mutex);
> +	lis3lv02d_get_xyz(lis3, &x, &y, &z);
>  	input_report_abs(pidev->input, ABS_X, x);
>  	input_report_abs(pidev->input, ABS_Y, y);
>  	input_report_abs(pidev->input, ABS_Z, z);
>  	input_sync(pidev->input);
> -	mutex_unlock(&lis3_dev.mutex);
> +	mutex_unlock(&lis3->mutex);
>  }
>  
>  static void lis3lv02d_joystick_open(struct input_polled_dev *pidev)
>  {
> -	if (lis3_dev.pm_dev)
> -		pm_runtime_get_sync(lis3_dev.pm_dev);
> +	struct lis3lv02d *lis3 = pidev->private;
>  
> -	if (lis3_dev.pdata && lis3_dev.whoami == WAI_8B && lis3_dev.idev)
> -		atomic_set(&lis3_dev.wake_thread, 1);
> +	if (lis3->pm_dev)
> +		pm_runtime_get_sync(lis3->pm_dev);
> +
> +	if (lis3->pdata && lis3->whoami == WAI_8B && lis3->idev)
> +		atomic_set(&lis3->wake_thread, 1);
>  	/*
>  	 * Update coordinates for the case where poll interval is 0 and
>  	 * the chip in running purely under interrupt control
> @@ -420,14 +423,18 @@ static void lis3lv02d_joystick_open(struct input_polled_dev *pidev)
>  
>  static void lis3lv02d_joystick_close(struct input_polled_dev *pidev)
>  {
> -	atomic_set(&lis3_dev.wake_thread, 0);
> -	if (lis3_dev.pm_dev)
> -		pm_runtime_put(lis3_dev.pm_dev);
> +	struct lis3lv02d *lis3 = pidev->private;
> +
> +	atomic_set(&lis3->wake_thread, 0);
> +	if (lis3->pm_dev)
> +		pm_runtime_put(lis3->pm_dev);
>  }
>  
> -static irqreturn_t lis302dl_interrupt(int irq, void *dummy)
> +static irqreturn_t lis302dl_interrupt(int irq, void *data)
>  {
> -	if (!test_bit(0, &lis3_dev.misc_opened))
> +	struct lis3lv02d *lis3 = data;
> +
> +	if (!test_bit(0, &lis3->misc_opened))
>  		goto out;
>  
>  	/*
> @@ -435,12 +442,12 @@ 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(&lis3_dev.count);
> +	atomic_inc(&lis3->count);
>  
> -	wake_up_interruptible(&lis3_dev.misc_wait);
> -	kill_fasync(&lis3_dev.async_queue, SIGIO, POLL_IN);
> +	wake_up_interruptible(&lis3->misc_wait);
> +	kill_fasync(&lis3->async_queue, SIGIO, POLL_IN);
>  out:
> -	if (atomic_read(&lis3_dev.wake_thread))
> +	if (atomic_read(&lis3->wake_thread))
>  		return IRQ_WAKE_THREAD;
>  	return IRQ_HANDLED;
>  }
> @@ -512,28 +519,37 @@ static irqreturn_t lis302dl_interrupt_thread2_8b(int irq, void *data)
>  
>  static int lis3lv02d_misc_open(struct inode *inode, struct file *file)
>  {
> -	if (test_and_set_bit(0, &lis3_dev.misc_opened))
> +	struct lis3lv02d *lis3 = container_of(file->private_data,
> +					      struct lis3lv02d, miscdev);
> +
> +	if (test_and_set_bit(0, &lis3->misc_opened))
>  		return -EBUSY; /* already open */
>  
> -	if (lis3_dev.pm_dev)
> -		pm_runtime_get_sync(lis3_dev.pm_dev);
> +	if (lis3->pm_dev)
> +		pm_runtime_get_sync(lis3->pm_dev);
>  
> -	atomic_set(&lis3_dev.count, 0);
> +	atomic_set(&lis3->count, 0);
>  	return 0;
>  }
>  
>  static int lis3lv02d_misc_release(struct inode *inode, struct file *file)
>  {
> -	fasync_helper(-1, file, 0, &lis3_dev.async_queue);
> -	clear_bit(0, &lis3_dev.misc_opened); /* release the device */
> -	if (lis3_dev.pm_dev)
> -		pm_runtime_put(lis3_dev.pm_dev);
> +	struct lis3lv02d *lis3 = container_of(file->private_data,
> +					      struct lis3lv02d, miscdev);
> +
> +	fasync_helper(-1, file, 0, &lis3->async_queue);
> +	clear_bit(0, &lis3->misc_opened); /* release the device */
> +	if (lis3->pm_dev)
> +		pm_runtime_put(lis3->pm_dev);
>  	return 0;
>  }
>  
>  static ssize_t lis3lv02d_misc_read(struct file *file, char __user *buf,
>  				size_t count, loff_t *pos)
>  {
> +	struct lis3lv02d *lis3 = container_of(file->private_data,
> +					      struct lis3lv02d, miscdev);
> +
>  	DECLARE_WAITQUEUE(wait, current);
>  	u32 data;
>  	unsigned char byte_data;
> @@ -542,10 +558,10 @@ static ssize_t lis3lv02d_misc_read(struct file *file, char __user *buf,
>  	if (count < 1)
>  		return -EINVAL;
>  
> -	add_wait_queue(&lis3_dev.misc_wait, &wait);
> +	add_wait_queue(&lis3->misc_wait, &wait);
>  	while (true) {
>  		set_current_state(TASK_INTERRUPTIBLE);
> -		data = atomic_xchg(&lis3_dev.count, 0);
> +		data = atomic_xchg(&lis3->count, 0);
>  		if (data)
>  			break;
>  
> @@ -575,22 +591,28 @@ static ssize_t lis3lv02d_misc_read(struct file *file, char __user *buf,
>  
>  out:
>  	__set_current_state(TASK_RUNNING);
> -	remove_wait_queue(&lis3_dev.misc_wait, &wait);
> +	remove_wait_queue(&lis3->misc_wait, &wait);
>  
>  	return retval;
>  }
>  
>  static unsigned int lis3lv02d_misc_poll(struct file *file, poll_table *wait)
>  {
> -	poll_wait(file, &lis3_dev.misc_wait, wait);
> -	if (atomic_read(&lis3_dev.count))
> +	struct lis3lv02d *lis3 = container_of(file->private_data,
> +					      struct lis3lv02d, miscdev);
> +
> +	poll_wait(file, &lis3->misc_wait, wait);
> +	if (atomic_read(&lis3->count))
>  		return POLLIN | POLLRDNORM;
>  	return 0;
>  }
>  
>  static int lis3lv02d_misc_fasync(int fd, struct file *file, int on)
>  {
> -	return fasync_helper(fd, file, on, &lis3_dev.async_queue);
> +	struct lis3lv02d *lis3 = container_of(file->private_data,
> +					      struct lis3lv02d, miscdev);
> +
> +	return fasync_helper(fd, file, on, &lis3->async_queue);
>  }
>  
>  static const struct file_operations lis3lv02d_misc_fops = {
> @@ -603,12 +625,6 @@ static const struct file_operations lis3lv02d_misc_fops = {
>  	.fasync  = lis3lv02d_misc_fasync,
>  };
>  
> -static struct miscdevice lis3lv02d_misc_device = {
> -	.minor   = MISC_DYNAMIC_MINOR,
> -	.name    = "freefall",
> -	.fops    = &lis3lv02d_misc_fops,
> -};
> -
>  int lis3lv02d_joystick_enable(struct lis3lv02d *lis3)
>  {
>  	struct input_dev *input_dev;
> @@ -616,51 +632,52 @@ int lis3lv02d_joystick_enable(struct lis3lv02d *lis3)
>  	int max_val, fuzz, flat;
>  	int btns[] = {BTN_X, BTN_Y, BTN_Z};
>  
> -	if (lis3_dev.idev)
> +	if (lis3->idev)
>  		return -EINVAL;
>  
> -	lis3_dev.idev = input_allocate_polled_device();
> -	if (!lis3_dev.idev)
> +	lis3->idev = input_allocate_polled_device();
> +	if (!lis3->idev)
>  		return -ENOMEM;
>  
> -	lis3_dev.idev->poll = lis3lv02d_joystick_poll;
> -	lis3_dev.idev->open = lis3lv02d_joystick_open;
> -	lis3_dev.idev->close = lis3lv02d_joystick_close;
> -	lis3_dev.idev->poll_interval = MDPS_POLL_INTERVAL;
> -	lis3_dev.idev->poll_interval_min = MDPS_POLL_MIN;
> -	lis3_dev.idev->poll_interval_max = MDPS_POLL_MAX;
> -	input_dev = lis3_dev.idev->input;
> +	lis3->idev->poll = lis3lv02d_joystick_poll;
> +	lis3->idev->open = lis3lv02d_joystick_open;
> +	lis3->idev->close = lis3lv02d_joystick_close;
> +	lis3->idev->poll_interval = MDPS_POLL_INTERVAL;
> +	lis3->idev->poll_interval_min = MDPS_POLL_MIN;
> +	lis3->idev->poll_interval_max = MDPS_POLL_MAX;
> +	lis3->idev->private = lis3;
> +	input_dev = lis3->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;
> +	input_dev->dev.parent = &lis3->pdev->dev;
>  
>  	set_bit(EV_ABS, input_dev->evbit);
> -	max_val = (lis3_dev.mdps_max_val * lis3_dev.scale) / LIS3_ACCURACY;
> -	if (lis3_dev.whoami == WAI_12B) {
> +	max_val = (lis3->mdps_max_val * lis3->scale) / LIS3_ACCURACY;
> +	if (lis3->whoami == WAI_12B) {
>  		fuzz = LIS3_DEFAULT_FUZZ_12B;
>  		flat = LIS3_DEFAULT_FLAT_12B;
>  	} else {
>  		fuzz = LIS3_DEFAULT_FUZZ_8B;
>  		flat = LIS3_DEFAULT_FLAT_8B;
>  	}
> -	fuzz = (fuzz * lis3_dev.scale) / LIS3_ACCURACY;
> -	flat = (flat * lis3_dev.scale) / LIS3_ACCURACY;
> +	fuzz = (fuzz * lis3->scale) / LIS3_ACCURACY;
> +	flat = (flat * lis3->scale) / LIS3_ACCURACY;
>  
>  	input_set_abs_params(input_dev, ABS_X, -max_val, max_val, fuzz, flat);
>  	input_set_abs_params(input_dev, ABS_Y, -max_val, max_val, fuzz, flat);
>  	input_set_abs_params(input_dev, ABS_Z, -max_val, max_val, fuzz, flat);
>  
> -	lis3_dev.mapped_btns[0] = lis3lv02d_get_axis(abs(lis3_dev.ac.x), btns);
> -	lis3_dev.mapped_btns[1] = lis3lv02d_get_axis(abs(lis3_dev.ac.y), btns);
> -	lis3_dev.mapped_btns[2] = lis3lv02d_get_axis(abs(lis3_dev.ac.z), btns);
> +	lis3->mapped_btns[0] = lis3lv02d_get_axis(abs(lis3->ac.x), btns);
> +	lis3->mapped_btns[1] = lis3lv02d_get_axis(abs(lis3->ac.y), btns);
> +	lis3->mapped_btns[2] = lis3lv02d_get_axis(abs(lis3->ac.z), btns);
>  
> -	err = input_register_polled_device(lis3_dev.idev);
> +	err = input_register_polled_device(lis3->idev);
>  	if (err) {
> -		input_free_polled_device(lis3_dev.idev);
> -		lis3_dev.idev = NULL;
> +		input_free_polled_device(lis3->idev);
> +		lis3->idev = NULL;
>  	}
>  
>  	return err;
> @@ -669,19 +686,19 @@ EXPORT_SYMBOL_GPL(lis3lv02d_joystick_enable);
>  
>  void lis3lv02d_joystick_disable(struct lis3lv02d *lis3)
>  {
> -	if (lis3_dev.irq)
> -		free_irq(lis3_dev.irq, &lis3_dev);
> -	if (lis3_dev.pdata && lis3_dev.pdata->irq2)
> -		free_irq(lis3_dev.pdata->irq2, &lis3_dev);
> +	if (lis3->irq)
> +		free_irq(lis3->irq, lis3);
> +	if (lis3->pdata && lis3->pdata->irq2)
> +		free_irq(lis3->pdata->irq2, lis3);
>  
> -	if (!lis3_dev.idev)
> +	if (!lis3->idev)
>  		return;
>  
> -	if (lis3_dev.irq)
> -		misc_deregister(&lis3lv02d_misc_device);
> -	input_unregister_polled_device(lis3_dev.idev);
> -	input_free_polled_device(lis3_dev.idev);
> -	lis3_dev.idev = NULL;
> +	if (lis3->irq)
> +		misc_deregister(&lis3->miscdev);
> +	input_unregister_polled_device(lis3->idev);
> +	input_free_polled_device(lis3->idev);
> +	lis3->idev = NULL;
>  }
>  EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable);
>  
> @@ -706,6 +723,7 @@ static void lis3lv02d_sysfs_poweron(struct lis3lv02d *lis3)
>  static ssize_t lis3lv02d_selftest_show(struct device *dev,
>  				struct device_attribute *attr, char *buf)
>  {
> +	struct lis3lv02d *lis3 = dev_get_drvdata(dev);
>  	s16 values[3];
>  
>  	static const char ok[] = "OK";
> @@ -713,8 +731,8 @@ static ssize_t lis3lv02d_selftest_show(struct device *dev,
>  	static const char irq[] = "FAIL_IRQ";
>  	const char *res;
>  
> -	lis3lv02d_sysfs_poweron(&lis3_dev);
> -	switch (lis3lv02d_selftest(&lis3_dev, values)) {
> +	lis3lv02d_sysfs_poweron(lis3);
> +	switch (lis3lv02d_selftest(lis3, values)) {
>  	case SELFTEST_FAIL:
>  		res = fail;
>  		break;
> @@ -733,33 +751,37 @@ static ssize_t lis3lv02d_selftest_show(struct device *dev,
>  static ssize_t lis3lv02d_position_show(struct device *dev,
>  				struct device_attribute *attr, char *buf)
>  {
> +	struct lis3lv02d *lis3 = dev_get_drvdata(dev);
>  	int x, y, z;
>  
> -	lis3lv02d_sysfs_poweron(&lis3_dev);
> -	mutex_lock(&lis3_dev.mutex);
> -	lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
> -	mutex_unlock(&lis3_dev.mutex);
> +	lis3lv02d_sysfs_poweron(lis3);
> +	mutex_lock(&lis3->mutex);
> +	lis3lv02d_get_xyz(lis3, &x, &y, &z);
> +	mutex_unlock(&lis3->mutex);
>  	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)
>  {
> -	lis3lv02d_sysfs_poweron(&lis3_dev);
> -	return sprintf(buf, "%d\n", lis3lv02d_get_odr());
> +	struct lis3lv02d *lis3 = dev_get_drvdata(dev);
> +
> +	lis3lv02d_sysfs_poweron(lis3);
> +	return sprintf(buf, "%d\n", lis3lv02d_get_odr(lis3));
>  }
>  
>  static ssize_t lis3lv02d_rate_set(struct device *dev,
>  				struct device_attribute *attr, const char *buf,
>  				size_t count)
>  {
> +	struct lis3lv02d *lis3 = dev_get_drvdata(dev);
>  	unsigned long rate;
>  
>  	if (strict_strtoul(buf, 0, &rate))
>  		return -EINVAL;
>  
> -	lis3lv02d_sysfs_poweron(&lis3_dev);
> -	if (lis3lv02d_set_odr(rate))
> +	lis3lv02d_sysfs_poweron(lis3);
> +	if (lis3lv02d_set_odr(lis3, rate))
>  		return -EINVAL;
>  
>  	return count;
> @@ -788,6 +810,7 @@ static int lis3lv02d_add_fs(struct lis3lv02d *lis3)
>  	if (IS_ERR(lis3->pdev))
>  		return PTR_ERR(lis3->pdev);
>  
> +	platform_set_drvdata(lis3->pdev, lis3);
>  	return sysfs_create_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group);
>  }
>  
> @@ -801,7 +824,7 @@ int lis3lv02d_remove_fs(struct lis3lv02d *lis3)
>  
>  		/* SYSFS may have left chip running. Turn off if necessary */
>  		if (!pm_runtime_suspended(lis3->pm_dev))
> -			lis3lv02d_poweroff(&lis3_dev);
> +			lis3lv02d_poweroff(lis3);
>  
>  		pm_runtime_disable(lis3->pm_dev);
>  		pm_runtime_set_suspended(lis3->pm_dev);
> @@ -828,7 +851,7 @@ static void lis3lv02d_8b_configure(struct lis3lv02d *lis3,
>  			(p->click_thresh_y << 4));
>  
>  		if (lis3->idev) {
> -			struct input_dev *input_dev = lis3_dev.idev->input;
> +			struct input_dev *input_dev = lis3->idev->input;
>  			input_set_capability(input_dev, EV_KEY, BTN_X);
>  			input_set_capability(input_dev, EV_KEY, BTN_Y);
>  			input_set_capability(input_dev, EV_KEY, BTN_Z);
> @@ -859,7 +882,7 @@ static void lis3lv02d_8b_configure(struct lis3lv02d *lis3,
>  					lis302dl_interrupt_thread2_8b,
>  					IRQF_TRIGGER_RISING | IRQF_ONESHOT |
>  					(p->irq_flags2 & IRQF_TRIGGER_MASK),
> -					DRIVER_NAME, &lis3_dev);
> +					DRIVER_NAME, lis3);
>  		if (err < 0)
>  			pr_err("No second IRQ. Limited functionality\n");
>  	}
> @@ -951,7 +974,7 @@ int lis3lv02d_init_device(struct lis3lv02d *lis3)
>  			lis3->write(lis3, CTRL_REG3, p->irq_cfg);
>  
>  		if (p->default_rate)
> -			lis3lv02d_set_odr(p->default_rate);
> +			lis3lv02d_set_odr(lis3, p->default_rate);
>  	}
>  
>  	/* bail if we did not get an IRQ from the bus layer */
> @@ -980,14 +1003,18 @@ int lis3lv02d_init_device(struct lis3lv02d *lis3)
>  				thread_fn,
>  				IRQF_TRIGGER_RISING | IRQF_ONESHOT |
>  				irq_flags,
> -				DRIVER_NAME, &lis3_dev);
> +				DRIVER_NAME, lis3);
>  
>  	if (err < 0) {
>  		pr_err("Cannot get IRQ\n");
>  		goto out;
>  	}
>  
> -	if (misc_register(&lis3lv02d_misc_device))
> +	lis3->miscdev.minor	= MISC_DYNAMIC_MINOR;
> +	lis3->miscdev.name	= "freefall";
> +	lis3->miscdev.fops	= &lis3lv02d_misc_fops;
> +
> +	if (misc_register(&lis3->miscdev))
>  		pr_err("misc_register failed\n");

You should not use miscdevice in case there will be multiple devices.
First, it will fail. There cannot be more than one device with the same
name. Second, current dynamic minor devices is restricted to 64 devices.
Since this is reserved to one-shot devices, freefall was OK as a misc
device until you fixed it to allow multiple freefall devices.  :-)

So, I'd recommend switching to a new device class, and have freefall0,
freefall1, etc.

Anyway, good job on this.

Regards,
Cascardo.

>  out:
>  	return 0;
> diff --git a/drivers/misc/lis3lv02d/lis3lv02d.h b/drivers/misc/lis3lv02d/lis3lv02d.h
> index 49cb1f1..7d0f554 100644
> --- a/drivers/misc/lis3lv02d/lis3lv02d.h
> +++ b/drivers/misc/lis3lv02d/lis3lv02d.h
> @@ -21,6 +21,7 @@
>  #include <linux/platform_device.h>
>  #include <linux/input-polldev.h>
>  #include <linux/regulator/consumer.h>
> +#include <linux/miscdevice.h>
>  
>  /*
>   * This driver tries to support the "digital" accelerometer chips from
> @@ -273,6 +274,8 @@ struct lis3lv02d {
>  	struct fasync_struct	*async_queue; /* queue for the misc device */
>  	wait_queue_head_t	misc_wait; /* Wait queue for the misc device */
>  	unsigned long		misc_opened; /* bit0: whether the device is open */
> +	struct miscdevice	miscdev;
> +
>  	int                     data_ready_count[2];
>  	atomic_t		wake_thread;
>  	unsigned char           irq_cfg;
> -- 
> 1.7.0.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe platform-driver-x86" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCHv2 4/5] hwmon: lis3: Remove the referencies to the global variable in core driver
  2011-04-05 15:50   ` Thadeu Lima de Souza Cascardo
@ 2011-04-07 11:59     ` Ilkka Koskinen
  2011-04-07 21:58       ` Thadeu Lima de Souza Cascardo
  0 siblings, 1 reply; 10+ messages in thread
From: Ilkka Koskinen @ 2011-04-07 11:59 UTC (permalink / raw)
  To: ext Thadeu Lima de Souza Cascardo
  Cc: Ilkka Koskinen, eric.piel, mjg, linux-kernel,
	platform-driver-x86, samu.p.onkalo


Hi,

Thanks for the comments!

On Tue, 5 Apr 2011, ext Thadeu Lima de Souza Cascardo wrote:
> On Tue, Apr 05, 2011 at 05:45:13PM +0300, Ilkka Koskinen wrote:
>> Signed-off-by: Ilkka Koskinen <ilkka.koskinen@nokia.com>
>> ---
>>  drivers/misc/lis3lv02d/lis3lv02d.c |  237 ++++++++++++++++++++----------------
>>  drivers/misc/lis3lv02d/lis3lv02d.h |    3 +
>>  2 files changed, 135 insertions(+), 105 deletions(-)

>> @@ -980,14 +1003,18 @@ int lis3lv02d_init_device(struct lis3lv02d *lis3)
>>  				thread_fn,
>>  				IRQF_TRIGGER_RISING | IRQF_ONESHOT |
>>  				irq_flags,
>> -				DRIVER_NAME, &lis3_dev);
>> +				DRIVER_NAME, lis3);
>>
>>  	if (err < 0) {
>>  		pr_err("Cannot get IRQ\n");
>>  		goto out;
>>  	}
>>
>> -	if (misc_register(&lis3lv02d_misc_device))
>> +	lis3->miscdev.minor	= MISC_DYNAMIC_MINOR;
>> +	lis3->miscdev.name	= "freefall";
>> +	lis3->miscdev.fops	= &lis3lv02d_misc_fops;
>> +
>> +	if (misc_register(&lis3->miscdev))
>>  		pr_err("misc_register failed\n");
>
> You should not use miscdevice in case there will be multiple devices.
> First, it will fail. There cannot be more than one device with the same
> name. Second, current dynamic minor devices is restricted to 64 devices.
> Since this is reserved to one-shot devices, freefall was OK as a misc
> device until you fixed it to allow multiple freefall devices.  :-)

Ah, true :)

> So, I'd recommend switching to a new device class, and have freefall0,
> freefall1, etc.

I wonder if introducing a new class makes sense. I mean, I can figure out 
use cases for several accelerometers but for several free fall sensors? :/

Would it be better to add a mechanism to tell to the core module if the 
particular device is used for free fall detection or not?

Cheers, Ilkka

> Anyway, good job on this.
>
> Regards,
> Cascardo.


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCHv2 4/5] hwmon: lis3: Remove the referencies to the global variable in core driver
  2011-04-07 11:59     ` Ilkka Koskinen
@ 2011-04-07 21:58       ` Thadeu Lima de Souza Cascardo
  2011-04-08 17:51         ` Jonathan Cameron
  0 siblings, 1 reply; 10+ messages in thread
From: Thadeu Lima de Souza Cascardo @ 2011-04-07 21:58 UTC (permalink / raw)
  To: Ilkka Koskinen
  Cc: Ilkka Koskinen, eric.piel, mjg, linux-kernel,
	platform-driver-x86, samu.p.onkalo, linux-input

[-- Attachment #1: Type: text/plain, Size: 3675 bytes --]

On Thu, Apr 07, 2011 at 02:59:48PM +0300, Ilkka Koskinen wrote:
> 
> Hi,
> 
> Thanks for the comments!
> 
> On Tue, 5 Apr 2011, ext Thadeu Lima de Souza Cascardo wrote:
> >On Tue, Apr 05, 2011 at 05:45:13PM +0300, Ilkka Koskinen wrote:
> >>Signed-off-by: Ilkka Koskinen <ilkka.koskinen@nokia.com>
> >>---
> >> drivers/misc/lis3lv02d/lis3lv02d.c |  237 ++++++++++++++++++++----------------
> >> drivers/misc/lis3lv02d/lis3lv02d.h |    3 +
> >> 2 files changed, 135 insertions(+), 105 deletions(-)
> 
> >>@@ -980,14 +1003,18 @@ int lis3lv02d_init_device(struct lis3lv02d *lis3)
> >> 				thread_fn,
> >> 				IRQF_TRIGGER_RISING | IRQF_ONESHOT |
> >> 				irq_flags,
> >>-				DRIVER_NAME, &lis3_dev);
> >>+				DRIVER_NAME, lis3);
> >>
> >> 	if (err < 0) {
> >> 		pr_err("Cannot get IRQ\n");
> >> 		goto out;
> >> 	}
> >>
> >>-	if (misc_register(&lis3lv02d_misc_device))
> >>+	lis3->miscdev.minor	= MISC_DYNAMIC_MINOR;
> >>+	lis3->miscdev.name	= "freefall";
> >>+	lis3->miscdev.fops	= &lis3lv02d_misc_fops;
> >>+
> >>+	if (misc_register(&lis3->miscdev))
> >> 		pr_err("misc_register failed\n");
> >
> >You should not use miscdevice in case there will be multiple devices.
> >First, it will fail. There cannot be more than one device with the same
> >name. Second, current dynamic minor devices is restricted to 64 devices.
> >Since this is reserved to one-shot devices, freefall was OK as a misc
> >device until you fixed it to allow multiple freefall devices.  :-)
> 
> Ah, true :)
> 
> >So, I'd recommend switching to a new device class, and have freefall0,
> >freefall1, etc.
> 
> I wonder if introducing a new class makes sense. I mean, I can
> figure out use cases for several accelerometers but for several free
> fall sensors? :/
> 
> Would it be better to add a mechanism to tell to the core module if
> the particular device is used for free fall detection or not?
> 
> Cheers, Ilkka
> 

I would suggest an input handler or just letting userspace handle that
using input events. Then, I checked out the code and realized that this
is done by the hardware, using an interrupt. Should we handle said
interrupt as a particular kind of event (perhaps a new misc event)?

I've written classmate-laptop driver, which has an accelerometer too
(using ACPI). Should we start documenting how accelerometer drivers
should be written? Input event devices are the best class, but I've seen
cases where drivers use sysfs files. In fact, I've just checked and seen
that lis3lv02d does that too, in the file position. But I've seen
drivers out there that use one file per axis. I guess that's the way
hwmon drivers usually do things, creating sysfs files.

Should we start standardizing these drivers? I think input devices are
good enough to report the data, including for 2-axis devices (I have one
SPI "inclinometer" here - how those should be distinguished?). sysfs
files would be nice for setting parameters. classmate-laptop, for
example, has a sensitivity parameter. Besides freefall, lis3 seems to
have a selftest function and a rate setting.

One last email in linux-input and pdx lists has requested a new MISC
event to report a change in direction for some devices. Although I think
freefall and change in direction could be computed using the
accelerometer values in userspace, these devices do it directly. How
should we handle them in a standard way?

I would like to gather some opinions before writing a draft of
recommendations for writing such drivers. Is linux-input the best forum
for this?

Regards,
Cascardo.


> >Anyway, good job on this.
> >
> >Regards,
> >Cascardo.
> 

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCHv2 4/5] hwmon: lis3: Remove the referencies to the global variable in core driver
  2011-04-07 21:58       ` Thadeu Lima de Souza Cascardo
@ 2011-04-08 17:51         ` Jonathan Cameron
  0 siblings, 0 replies; 10+ messages in thread
From: Jonathan Cameron @ 2011-04-08 17:51 UTC (permalink / raw)
  To: Thadeu Lima de Souza Cascardo
  Cc: Ilkka Koskinen, Ilkka Koskinen, eric.piel, mjg, linux-kernel,
	platform-driver-x86, samu.p.onkalo, linux-input, linux-iio,
	Hemanth V

On 04/07/11 22:58, Thadeu Lima de Souza Cascardo wrote:
> On Thu, Apr 07, 2011 at 02:59:48PM +0300, Ilkka Koskinen wrote:
>>
>> Hi,
>>
>> Thanks for the comments!
>>
>> On Tue, 5 Apr 2011, ext Thadeu Lima de Souza Cascardo wrote:
>>> On Tue, Apr 05, 2011 at 05:45:13PM +0300, Ilkka Koskinen wrote:
>>>> Signed-off-by: Ilkka Koskinen <ilkka.koskinen@nokia.com>
>>>> ---
>>>> drivers/misc/lis3lv02d/lis3lv02d.c |  237 ++++++++++++++++++++----------------
>>>> drivers/misc/lis3lv02d/lis3lv02d.h |    3 +
>>>> 2 files changed, 135 insertions(+), 105 deletions(-)
>>
>>>> @@ -980,14 +1003,18 @@ int lis3lv02d_init_device(struct lis3lv02d *lis3)
>>>> 				thread_fn,
>>>> 				IRQF_TRIGGER_RISING | IRQF_ONESHOT |
>>>> 				irq_flags,
>>>> -				DRIVER_NAME, &lis3_dev);
>>>> +				DRIVER_NAME, lis3);
>>>>
>>>> 	if (err < 0) {
>>>> 		pr_err("Cannot get IRQ\n");
>>>> 		goto out;
>>>> 	}
>>>>
>>>> -	if (misc_register(&lis3lv02d_misc_device))
>>>> +	lis3->miscdev.minor	= MISC_DYNAMIC_MINOR;
>>>> +	lis3->miscdev.name	= "freefall";
>>>> +	lis3->miscdev.fops	= &lis3lv02d_misc_fops;
>>>> +
>>>> +	if (misc_register(&lis3->miscdev))
>>>> 		pr_err("misc_register failed\n");
>>>
>>> You should not use miscdevice in case there will be multiple devices.
>>> First, it will fail. There cannot be more than one device with the same
>>> name. Second, current dynamic minor devices is restricted to 64 devices.
>>> Since this is reserved to one-shot devices, freefall was OK as a misc
>>> device until you fixed it to allow multiple freefall devices.  :-)
>>
>> Ah, true :)
>>
>>> So, I'd recommend switching to a new device class, and have freefall0,
>>> freefall1, etc.
>>
>> I wonder if introducing a new class makes sense. I mean, I can
>> figure out use cases for several accelerometers but for several free
>> fall sensors? :/
>>
>> Would it be better to add a mechanism to tell to the core module if
>> the particular device is used for free fall detection or not?
>>
>> Cheers, Ilkka
>>
> 
> I would suggest an input handler or just letting userspace handle that
> using input events. Then, I checked out the code and realized that this
> is done by the hardware, using an interrupt. Should we handle said
> interrupt as a particular kind of event (perhaps a new misc event)?
> 
> I've written classmate-laptop driver, which has an accelerometer too
> (using ACPI). Should we start documenting how accelerometer drivers
> should be written? Input event devices are the best class, but I've seen
> cases where drivers use sysfs files. In fact, I've just checked and seen
> that lis3lv02d does that too, in the file position. But I've seen
> drivers out there that use one file per axis. I guess that's the way
> hwmon drivers usually do things, creating sysfs files.
sysfs is the quick and easy to handle option.  The single file per axis
is because you need a surprisingly complex description to explain the
contents of a 'scan' across all axis.  There are plenty of devices out
there that don't conform to the simple x y z coordinates.  If you do
it with one file per reading this is clearly handled in the naming.

Obviously if you want high frequency data with the samples grouped
across various axes, the single attribute per axis isn't all that
helpful.  However if you want this you are likely to want to use input
(if appropriate) or perhaps IIO see below but basically we are interested
in a wide range of sensors including some that are quicker than ever
makes sense for input devices and hence have a much simpler path to
userspace.  (different aims = different solution!) 
> 
> Should we start standardizing these drivers? I think input devices are
> good enough to report the data, including for 2-axis devices (I have one
> SPI "inclinometer" here - how those should be distinguished?). sysfs
> files would be nice for setting parameters. classmate-laptop, for
> example, has a sensitivity parameter. Besides freefall, lis3 seems to
> have a selftest function and a rate setting.
Quite a few discussions have taken place on standardizing this in the past.
I've cc'd Hemanth and IIO to cover the main contributors (IIRC).

The general view is that if it really is used primarily for 'input' e.g.
a human deliberately doing stuff with it to manipulate software, then it
should be via input.  Other forms of accelerometer and uses such as freefall
are more dubious.  Freefall definitely isn't deliberate user input (most
of the time ;).  There are plenty of accelerometers that do nothing else
such as those in hard disks.  Even if we have multiple sensors why on
earth would a userspace app want to treat them independently? Hence
a single chrdev seems more than adequate to me

We have a lot of the more interesting devices in iio (staging/iio/accel).
Fun things such as vibration sensors (extremely high frequency short period
sampling) an impact sensors alongside some conventional accelerometers.
Free fall is an area we don't have well covered though.  Actually
it's handled as a generic all axis low value threshold (which is what they
typically actually are up to some filtering - handling description of
filtering is still on the todo list!).  Note we are covering a much
wider range of sensors that just accelerometers so needed something
that generalized. On that front we have a lot of relatively tightly
defined interfaces that cover most things I've seen on these sensors.

As we are still in staging, we are mostly happy to discuss any new
proposals, but note that if we change anything for accelerometers we will
also have to change it for every other sensor type so that is the angle
I for one will be approaching new discussions from.
Consistency is a pain sometimes!

Anyhow, some references to previous related discussions:
https://lkml.org/lkml/2010/9/21/167 (iio sysfs event control attribute naming -
docs in tree are more up to date drivers/staging/iio/Documentation/sysfs-bus-iio)

https://lkml.org/lkml/2010/5/21/30 (Hemanth's CMA3000 accelerometer driver).


> 
> One last email in linux-input and pdx lists has requested a new MISC
> event to report a change in direction for some devices. Although I think
> freefall and change in direction could be computed using the
> accelerometer values in userspace, these devices do it directly. How
> should we handle them in a standard way?
Change of direction is much more likely to be deliberate human interaction
than freefall. I'm not convinced the same solutions will apply.
> 
> I would like to gather some opinions before writing a draft of
> recommendations for writing such drivers. Is linux-input the best forum
> for this?
Probably, though please cc linux-iio as it's clearly relevant there as well
and a heads up to lkml that the discussion is starting might also bring
in a few others.

Good to see someone else is trying to start a discussion around this.
I hope you get more input than some of the previous ones have had!

Jonathan

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2011-04-08 17:49 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-04-05 14:45 [RFC PATCHv2 0/5] lis3lv02d: Regulator fix & support for multiple devices Ilkka Koskinen
2011-04-05 14:45 ` [RFC PATCHv2 1/5] hwmon: lis3: Free regulators if probe() fails Ilkka Koskinen
2011-04-05 14:45 ` [RFC PATCHv2 2/5] hwmon: lis3: Change naming to consistent Ilkka Koskinen
2011-04-05 14:45 ` [RFC PATCHv2 3/5] hwmon: lis3: Change exported function to use given device Ilkka Koskinen
2011-04-05 14:45 ` [RFC PATCHv2 4/5] hwmon: lis3: Remove the referencies to the global variable in core driver Ilkka Koskinen
2011-04-05 15:50   ` Thadeu Lima de Souza Cascardo
2011-04-07 11:59     ` Ilkka Koskinen
2011-04-07 21:58       ` Thadeu Lima de Souza Cascardo
2011-04-08 17:51         ` Jonathan Cameron
2011-04-05 14:45 ` [RFC PATCHv2 5/5] hwmon: lis3: Register hwif and remove references to global variable Ilkka Koskinen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).