Re: [PATCH] input: keyboard: introduce lm8323 driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi felipe,

On Thu, Feb 19, 2009 at 02:31:17PM +0200, Felipe Balbi wrote:
> From: Felipe Balbi <felipe.balbi@xxxxxxxxx>
> 
> lm8323 is the keypad driver used in n810 device. This
> driver has been sitting in linux-omap for quite a long
> time, it's about time to get comments from upstream and
> get it merged.
> 

Thank you ofr the patch. I did not quite like the hard-coding of 3 PWMs,
I think an array works better and also you enable IRQ before allocating
input device, which is not safe. Also probe() leaks input device
structure in certain scenarios. I have a fixup patch and would
appreciate if you coould try it.

Thanks!

-- 
Dmitry


Input: lm8323 fixups

Signed-off-by: Dmitry Torokhov <dtor@xxxxxxx>
---

 drivers/input/keyboard/lm8323.c |  236 ++++++++++++++++-----------------------
 include/linux/i2c/lm8323.h      |   10 +-
 2 files changed, 100 insertions(+), 146 deletions(-)


diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c
index a796680..9f4ef51 100644
--- a/drivers/input/keyboard/lm8323.c
+++ b/drivers/input/keyboard/lm8323.c
@@ -137,6 +137,7 @@ struct lm8323_pwm {
 	struct mutex		lock;
 	struct work_struct	work;
 	struct led_classdev	cdev;
+	struct lm8323_chip	*chip;
 };
 
 struct lm8323_chip {
@@ -154,9 +155,7 @@ struct lm8323_chip {
 	int			size_y;
 	int			debounce_time;
 	int			active_time;
-	struct lm8323_pwm	pwm1;
-	struct lm8323_pwm	pwm2;
-	struct lm8323_pwm	pwm3;
+	struct lm8323_pwm	pwm[LM8323_NUM_PWMS];
 };
 
 #define client_to_lm8323(c)	container_of(c, struct lm8323_chip, client)
@@ -165,20 +164,6 @@ struct lm8323_chip {
 #define cdev_to_pwm(c)		container_of(c, struct lm8323_pwm, cdev)
 #define work_to_pwm(w)		container_of(w, struct lm8323_pwm, work)
 
-static struct lm8323_chip *pwm_to_lm8323(struct lm8323_pwm *pwm)
-{
-	switch (pwm->id) {
-	case 1:
-		return container_of(pwm, struct lm8323_chip, pwm1);
-	case 2:
-		return container_of(pwm, struct lm8323_chip, pwm2);
-	case 3:
-		return container_of(pwm, struct lm8323_chip, pwm3);
-	default:
-		return NULL;
-	}
-}
-
 #define LM8323_MAX_DATA 8
 
 /*
@@ -395,6 +380,7 @@ static void lm8323_work(struct work_struct *work)
 {
 	struct lm8323_chip *lm = work_to_lm8323(work);
 	u8 ints;
+	int i;
 
 	mutex_lock(&lm->lock);
 
@@ -414,17 +400,12 @@ static void lm8323_work(struct work_struct *work)
 						  "reinitialising\n");
 			lm8323_configure(lm);
 		}
-		if (ints & INT_PWM1) {
-			dev_vdbg(&lm->client->dev, "pwm1 engine completed\n");
-			pwm_done(&lm->pwm1);
-		}
-		if (ints & INT_PWM2) {
-			dev_vdbg(&lm->client->dev, "pwm2 engine completed\n");
-			pwm_done(&lm->pwm2);
-		}
-		if (ints & INT_PWM3) {
-			dev_vdbg(&lm->client->dev, "pwm3 engine completed\n");
-			pwm_done(&lm->pwm3);
+		for (i = 0; i < LM8323_NUM_PWMS; i++) {
+			if (ints & (1 << (INT_PWM1 + i))) {
+				dev_vdbg(&lm->client->dev,
+					 "pwm%d engine completed\n", i);
+				pwm_done(&lm->pwm[i]);
+			}
 		}
 	}
 
@@ -459,9 +440,7 @@ static int lm8323_read_id(struct lm8323_chip *lm, u8 *buf)
 
 static void lm8323_write_pwm_one(struct lm8323_pwm *pwm, int pos, u16 cmd)
 {
-	struct lm8323_chip *lm = pwm_to_lm8323(pwm);
-
-	lm8323_write(lm, 4, LM8323_CMD_PWM_WRITE, (pos << 2) | pwm->id,
+	lm8323_write(pwm->chip, 4, LM8323_CMD_PWM_WRITE, (pos << 2) | pwm->id,
 		     (cmd & 0xff00) >> 8, cmd & 0x00ff);
 }
 
@@ -474,14 +453,13 @@ static void lm8323_write_pwm_one(struct lm8323_pwm *pwm, int pos, u16 cmd)
 static void lm8323_write_pwm(struct lm8323_pwm *pwm, int kill,
 			     int len, const u16 *cmds)
 {
-	struct lm8323_chip *lm = pwm_to_lm8323(pwm);
 	int i;
 
 	for (i = 0; i < len; i++)
 		lm8323_write_pwm_one(pwm, i, cmds[i]);
 
 	lm8323_write_pwm_one(pwm, i++, PWM_END(kill));
-	lm8323_write(lm, 2, LM8323_CMD_START_PWM, pwm->id);
+	lm8323_write(pwm->chip, 2, LM8323_CMD_START_PWM, pwm->id);
 	pwm->running = 1;
 }
 
@@ -546,7 +524,7 @@ static void lm8323_pwm_set_brightness(struct led_classdev *led_cdev,
 				      enum led_brightness brightness)
 {
 	struct lm8323_pwm *pwm = cdev_to_pwm(led_cdev);
-	struct lm8323_chip *lm = pwm_to_lm8323(pwm);
+	struct lm8323_chip *lm = pwm->chip;
 
 	mutex_lock(&pwm->lock);
 	pwm->desired_brightness = brightness;
@@ -582,7 +560,7 @@ static ssize_t lm8323_pwm_store_time(struct device *dev,
 	struct led_classdev *led_cdev = dev_get_drvdata(dev);
 	struct lm8323_pwm *pwm = cdev_to_pwm(led_cdev);
 	int ret;
-	int time;
+	unsigned long time;
 
 	ret = strict_strtoul(buf, 10, &time);
 	/* Numbers only, please. */
@@ -598,28 +576,22 @@ static DEVICE_ATTR(time, 0644, lm8323_pwm_show_time, lm8323_pwm_store_time);
 static int init_pwm(struct lm8323_chip *lm, int id, struct device *dev,
 		    const char *name)
 {
-	struct lm8323_pwm *pwm = NULL;
+	struct lm8323_pwm *pwm;
 
 	BUG_ON(id > 3);
 
-	switch (id) {
-	case 1:
-		pwm = &lm->pwm1;
-		break;
-	case 2:
-		pwm = &lm->pwm2;
-		break;
-	case 3:
-		pwm = &lm->pwm3;
-		break;
-	}
+	pwm = &lm->pwm[id - 1];
 
 	pwm->id = id;
 	pwm->fade_time = 0;
 	pwm->brightness = 0;
 	pwm->desired_brightness = 0;
 	pwm->running = 0;
+	pwm->enabled = 0;
+	INIT_WORK(&pwm->work, lm8323_pwm_work);
 	mutex_init(&pwm->lock);
+	pwm->chip = lm;
+
 	if (name) {
 		pwm->cdev.name = name;
 		pwm->cdev.brightness_set = lm8323_pwm_set_brightness;
@@ -628,15 +600,12 @@ static int init_pwm(struct lm8323_chip *lm, int id, struct device *dev,
 			return -1;
 		}
 		if (device_create_file(pwm->cdev.dev,
-					     &dev_attr_time) < 0) {
+					&dev_attr_time) < 0) {
 			dev_err(dev, "couldn't register time attribute\n");
 			led_classdev_unregister(&pwm->cdev);
 			return -1;
 		}
-		INIT_WORK(&pwm->work, lm8323_pwm_work);
 		pwm->enabled = 1;
-	} else {
-		pwm->enabled = 0;
 	}
 
 	return 0;
@@ -658,7 +627,7 @@ static ssize_t lm8323_set_disable(struct device *dev,
 {
 	struct lm8323_chip *lm = dev_get_drvdata(dev);
 	int ret;
-	int i;
+	unsigned long i;
 
 	ret = strict_strtoul(buf, 10, &i);
 
@@ -671,46 +640,50 @@ static ssize_t lm8323_set_disable(struct device *dev,
 static DEVICE_ATTR(disable_kp, 0644, lm8323_show_disable, lm8323_set_disable);
 
 static int lm8323_probe(struct i2c_client *client,
-		const struct i2c_device_id *id)
+			const struct i2c_device_id *id)
 {
-	struct lm8323_platform_data *pdata;
+	struct lm8323_platform_data *pdata = client->dev.platform_data;
 	struct input_dev *idev;
 	struct lm8323_chip *lm;
-	int i, err = 0;
+	int i, err;
 	unsigned long tmo;
 	u8 data[2];
 
-	lm = kzalloc(sizeof *lm, GFP_KERNEL);
-	if (!lm)
-		return -ENOMEM;
-
-	i2c_set_clientdata(client, lm);
-	lm->client = client;
-	pdata = client->dev.platform_data;
 	if (!pdata || !pdata->size_x || !pdata->size_y) {
 		dev_err(&client->dev, "missing platform_data\n");
-		err = -EINVAL;
-		goto fail2;
+		return -EINVAL;
 	}
 
-	lm->size_x = pdata->size_x;
-	if (lm->size_x > 8) {
+	if (pdata->size_x > 8) {
 		dev_err(&client->dev, "invalid x size %d specified\n",
-				lm->size_x);
-		err = -EINVAL;
-		goto fail2;
+			pdata->size_x);
+		return -EINVAL;
 	}
 
-	lm->size_y = pdata->size_y;
-	if (lm->size_y > 12) {
+	if (pdata->size_y > 12) {
 		dev_err(&client->dev, "invalid y size %d specified\n",
-				lm->size_y);
-		err = -EINVAL;
-		goto fail2;
+			pdata->size_y);
+		return -EINVAL;
 	}
 
+	lm = kzalloc(sizeof *lm, GFP_KERNEL);
+	idev = input_allocate_device();
+	if (!lm || !idev) {
+		err = -ENOMEM;
+		goto fail1;
+	}
+
+	i2c_set_clientdata(client, lm);
+
+	lm->client = client;
+	lm->idev = idev;
+	mutex_init(&lm->lock);
+	INIT_WORK(&lm->work, lm8323_work);
+
+	lm->size_x = pdata->size_x;
+	lm->size_y = pdata->size_y;
 	dev_vdbg(&client->dev, "Keypad size: %d x %d\n",
-			lm->size_x, lm->size_y);
+		 lm->size_x, lm->size_y);
 
 	lm->debounce_time = pdata->debounce_time;
 	lm->active_time = pdata->active_time;
@@ -726,61 +699,38 @@ static int lm8323_probe(struct i2c_client *client,
 
 		if (time_after(jiffies, tmo)) {
 			dev_err(&client->dev,
-					"timeout waiting for initialisation\n");
+				"timeout waiting for initialisation\n");
 			break;
 		}
 
 		msleep(1);
 	}
+
 	lm8323_configure(lm);
 
 	/* If a true probe check the device */
 	if (lm8323_read_id(lm, data) != 0) {
 		dev_err(&client->dev, "device not found\n");
 		err = -ENODEV;
-		goto fail2;
+		goto fail1;
 	}
 
-	if (init_pwm(lm, 1, &client->dev, pdata->pwm1_name) < 0)
-		goto fail3;
-	if (init_pwm(lm, 2, &client->dev, pdata->pwm2_name) < 0)
-		goto fail4;
-	if (init_pwm(lm, 3, &client->dev, pdata->pwm3_name) < 0)
-		goto fail5;
-
-	mutex_init(&lm->lock);
-	INIT_WORK(&lm->work, lm8323_work);
-
-	err = request_irq(client->irq, lm8323_irq,
-			  IRQF_TRIGGER_FALLING | IRQF_DISABLED,
-			  "lm8323", lm);
-	if (err) {
-		dev_err(&client->dev, "could not get IRQ %d\n", client->irq);
-		goto fail6;
+	for (i = 0; i < LM8323_NUM_PWMS; i++) {
+		err = init_pwm(lm, i + 1, &client->dev, pdata->pwm_names[i]);
+		if (err < 0)
+			goto fail2;
 	}
 
-	device_init_wakeup(&client->dev, 1);
-	enable_irq_wake(client->irq);
-
 	lm->kp_enabled = 1;
 	err = device_create_file(&client->dev, &dev_attr_disable_kp);
 	if (err < 0)
-		goto fail7;
-
-	idev = input_allocate_device();
-	if (!idev) {
-		err = -ENOMEM;
-		goto fail8;
-	}
+		goto fail2;
 
-	if (pdata->name)
-		idev->name = pdata->name;
-	else
-		idev->name = "LM8323 keypad";
-	snprintf(lm->phys, sizeof(lm->phys), "%s/input-kp", client->dev.bus_id);
+	idev->name = pdata->name ? : "LM8323 keypad";
+	snprintf(lm->phys, sizeof(lm->phys),
+		 "%s/input-kp", dev_name(&client->dev));
 	idev->phys = lm->phys;
 
-	lm->keys_down = 0;
 	idev->evbit[0] = BIT(EV_KEY);
 	for (i = 0; i < LM8323_KEYMAP_SIZE; i++) {
 		if (pdata->keymap[i] > 0)
@@ -792,30 +742,36 @@ static int lm8323_probe(struct i2c_client *client,
 	if (pdata->repeat)
 		__set_bit(EV_REP, idev->evbit);
 
-	lm->idev = idev;
 	err = input_register_device(idev);
 	if (err) {
 		dev_dbg(&client->dev, "error registering input device\n");
-		goto fail8;
+		goto fail3;
 	}
 
+	err = request_irq(client->irq, lm8323_irq,
+			  IRQF_TRIGGER_FALLING | IRQF_DISABLED,
+			  "lm8323", lm);
+	if (err) {
+		dev_err(&client->dev, "could not get IRQ %d\n", client->irq);
+		goto fail4;
+	}
+
+	device_init_wakeup(&client->dev, 1);
+	enable_irq_wake(client->irq);
+
 	return 0;
 
-fail8:
-	device_remove_file(&client->dev, &dev_attr_disable_kp);
-fail7:
-	free_irq(client->irq, lm);
-fail6:
-	if (lm->pwm3.enabled)
-		led_classdev_unregister(&lm->pwm3.cdev);
-fail5:
-	if (lm->pwm2.enabled)
-		led_classdev_unregister(&lm->pwm2.cdev);
 fail4:
-	if (lm->pwm1.enabled)
-		led_classdev_unregister(&lm->pwm1.cdev);
+	input_unregister_device(idev);
+	idev = NULL;
 fail3:
+	device_remove_file(&client->dev, &dev_attr_disable_kp);
 fail2:
+	while (--i >= 0)
+		if (lm->pwm[i].enabled)
+			led_classdev_unregister(&lm->pwm[i].cdev);
+fail1:
+	input_free_device(idev);
 	kfree(lm);
 	return err;
 }
@@ -823,18 +779,20 @@ fail2:
 static int lm8323_remove(struct i2c_client *client)
 {
 	struct lm8323_chip *lm = i2c_get_clientdata(client);
+	int i;
 
 	disable_irq_wake(client->irq);
 	free_irq(client->irq, lm);
 	cancel_work_sync(&lm->work);
+
 	input_unregister_device(lm->idev);
+
 	device_remove_file(&lm->client->dev, &dev_attr_disable_kp);
-	if (lm->pwm3.enabled)
-		led_classdev_unregister(&lm->pwm3.cdev);
-	if (lm->pwm2.enabled)
-		led_classdev_unregister(&lm->pwm2.cdev);
-	if (lm->pwm1.enabled)
-		led_classdev_unregister(&lm->pwm1.cdev);
+
+	for (i = 0; i < 3; i++)
+		if (lm->pwm[i].enabled)
+			led_classdev_unregister(&lm->pwm[i].cdev);
+
 	kfree(lm);
 
 	return 0;
@@ -848,6 +806,7 @@ static int lm8323_remove(struct i2c_client *client)
 static int lm8323_suspend(struct i2c_client *client, pm_message_t mesg)
 {
 	struct lm8323_chip *lm = i2c_get_clientdata(client);
+	int i;
 
 	set_irq_wake(client->irq, 0);
 	disable_irq(client->irq);
@@ -856,12 +815,9 @@ static int lm8323_suspend(struct i2c_client *client, pm_message_t mesg)
 	lm->pm_suspend = 1;
 	mutex_unlock(&lm->lock);
 
-	if (lm->pwm1.enabled)
-		led_classdev_suspend(&lm->pwm1.cdev);
-	if (lm->pwm2.enabled)
-		led_classdev_suspend(&lm->pwm2.cdev);
-	if (lm->pwm3.enabled)
-		led_classdev_suspend(&lm->pwm3.cdev);
+	for (i = 0; i < 3; i++)
+		if (lm->pwm[i].enabled)
+			led_classdev_suspend(&lm->pwm[i].cdev);
 
 	return 0;
 }
@@ -869,17 +825,15 @@ static int lm8323_suspend(struct i2c_client *client, pm_message_t mesg)
 static int lm8323_resume(struct i2c_client *client)
 {
 	struct lm8323_chip *lm = i2c_get_clientdata(client);
+	int i;
 
 	mutex_lock(&lm->lock);
 	lm->pm_suspend = 0;
 	mutex_unlock(&lm->lock);
 
-	if (lm->pwm1.enabled)
-		led_classdev_resume(&lm->pwm1.cdev);
-	if (lm->pwm2.enabled)
-		led_classdev_resume(&lm->pwm2.cdev);
-	if (lm->pwm3.enabled)
-		led_classdev_resume(&lm->pwm3.cdev);
+	for (i = 0; i < 3; i++)
+		if (lm->pwm[i].enabled)
+			led_classdev_resume(&lm->pwm[i].cdev);
 
 	enable_irq(client->irq);
 	set_irq_wake(client->irq, 1);
diff --git a/include/linux/i2c/lm8323.h b/include/linux/i2c/lm8323.h
index 67e82bc..50fad47 100644
--- a/include/linux/i2c/lm8323.h
+++ b/include/linux/i2c/lm8323.h
@@ -25,7 +25,9 @@
  * so keys can be mapped directly at the index of the
  * LM8323 keycode instead of subtracting one.
  */
-#define LM8323_KEYMAP_SIZE (0x7f + 1)
+#define LM8323_KEYMAP_SIZE	(0x7f + 1)
+
+#define LM8323_NUM_PWMS		3
 
 struct lm8323_platform_data {
 	int debounce_time; /* Time to watch for key bouncing, in ms. */
@@ -36,11 +38,9 @@ struct lm8323_platform_data {
 	int repeat:1;
 	const s16 *keymap;
 
-	char *pwm1_name; /* Device name for PWM1. */
-	char *pwm2_name; /* Device name for PWM2. */
-	char *pwm3_name; /* Device name for PWM3. */
+	const char *pwm_names[LM8323_NUM_PWMS];
 
-	char *name; /* Device name. */
+	const char *name; /* Device name. */
 };
 
 #endif /* __LINUX_LM8323_H */
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux