Hi Dmitry,

On Sun, May 07, 2017 at 02:38:00PM -0700, Dmitry Torokhov wrote:
> > + *  This program is free software; you can redistribute it and/or modify it
> > + *  under  the terms of the GNU General  Public License as published by the
> > + *  Free Software Foundation;  either version 2 of the License, or (at your
> > + *  option) any later version.
> > + */
> > +
> > +#define DEBUG
> 
> I do not think this is needed.

Leftover from writing the driver :) Will remove in v4.

> > +
> > +#include <linux/input.h>
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/of_device.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/pwm.h>
> > +#include <linux/regulator/consumer.h>
> > +#include <linux/slab.h>
> > +
> > +/**
> 
> This is not kernel doc, so no "/**".

Ack.

> > + * Motorola Droid 4 (also known as mapphone), has a vibrator, which pulses
> > + * 1x on rising edge. Increasing the pwm period results in more pulses per
> > + * second, but reduces intensity. There is also a second channel to control
> > + * the vibrator's rotation direction to increase effect. The following
> > + * numbers were determined manually. Going below 12.5 Hz means, clearly
> > + * noticeable pauses and at 30 Hz the vibration is just barely noticable
> > + * anymore.
> > + */
> > +#define MAPPHONE_MIN_FREQ 125 /* 12.5 Hz */
> > +#define MAPPHONE_MAX_FREQ 300 /* 30.0 Hz */
> > +
> > [...]
> > +
> > +   vibrator->pwm_dir = devm_pwm_get(&pdev->dev, "direction");
> > +   err = PTR_ERR_OR_ZERO(vibrator->pwm_dir);
> > +   if (err == -ENODATA) {
> > +           vibrator->pwm_dir = NULL;
> > +   } else if (err == -EPROBE_DEFER) {
> > +           return err;
> > +   } else if (err) {
> > +           dev_err(&pdev->dev, "Failed to request direction pwm: %d", err);
> > +           return err;
> > +   } else {
> > +           /* Sync up PWM state and ensure it is off. */
> > +           pwm_init_state(vibrator->pwm_dir, &state);
> > +           state.enabled = false;
> > +           err = pwm_apply_state(vibrator->pwm_dir, &state);
> > +           if (err) {
> > +                   dev_err(&pdev->dev, "failed to apply initial PWM state: 
> > %d",
> > +                           err);
> > +                   return err;
> > +           }
> > +   }
> 
> I wonder if the above is not better with "switch":
> 
>       switch (err) {
>       case 0:
>               /* Sync up PWM state and ensure it is off. */
>               pwm_init_state(vibrator->pwm_dir, &state);
>               state.enabled = false;
>               err = pwm_apply_state(vibrator->pwm_dir, &state);
>               if (err) {
>                       dev_err(&pdev->dev,
>                               "failed to apply initial PWM state: %d", err);
>                       return err;
>               }
>               break;
> 
>       case -ENODATA:
>               /* Direction PWM is optional */
>               vibrator->pwm_dir = NULL;
>               break;
> 
>       default:
>               dev_err(&pdev->dev, "Failed to request direction pwm: %d", err);
>               /* Fall through */
> 
>       case -EPROBE_DEFER:
>               return err;
>       }

Ack.

> > +
> > +   vibrator->hw = of_device_get_match_data(&pdev->dev);
> > +   if (!vibrator->hw)
> > +           vibrator->hw = &pwm_vib_hw_generic;
> > +
> > +   input->name = "pwm-vibrator";
> > +   input->id.bustype = BUS_HOST;
> > +   input->dev.parent = &pdev->dev;
> > +   input->close = pwm_vibrator_close;
> > +
> > +   input_set_drvdata(input, vibrator);
> > +   input_set_capability(input, EV_FF, FF_RUMBLE);
> > +
> > +   err = input_ff_create_memless(input, NULL, pwm_vibrator_play_effect);
> > +   if (err) {
> > +           dev_err(&pdev->dev, "Couldn't create FF dev: %d", err);
> > +           return err;
> > +   }
> > +
> > +   err = input_register_device(input);
> > +   if (err) {
> > +           dev_err(&pdev->dev, "Couldn't register input dev: %d", err);
> > +           return err;
> > +   }
> > +
> > +   platform_set_drvdata(pdev, vibrator);
> > +
> > +   return 0;
> > +}
> > +
> > +static int __maybe_unused pwm_vibrator_suspend(struct device *dev)
> > +{
> > +   struct platform_device *pdev = to_platform_device(dev);
> > +   struct pwm_vibrator *vibrator = platform_get_drvdata(pdev);
> > +   struct input_dev *input = vibrator->input;
> > +   unsigned long flags;
> > +
> > +   spin_lock_irqsave(&input->event_lock, flags);
> 
> Hmm, no, this is not goting to work. The original patch had a chance if
> PWM was not sleeping, but with introduction of regulator and work this
> definitely sleeps.

Actually PWM is sleeping, that's why I added work (regulator was
added later) :)

> I think we should solve issue of events [not] being delivered during
> suspend transition in input core, and simply drop spin_lock_irqsave()
> here and in resume().

Sounds good. will you take care of the input-core change?

> > +   cancel_work_sync(&vibrator->play_work);
> > +   if (vibrator->level)
> > +           pwm_vibrator_stop(vibrator);
> > +   spin_unlock_irqrestore(&input->event_lock, flags);
> > +
> > +   return 0;
> > +}
> > +
> > +static int __maybe_unused pwm_vibrator_resume(struct device *dev)
> > +{
> > +   struct platform_device *pdev = to_platform_device(dev);
> > +   struct pwm_vibrator *vibrator = platform_get_drvdata(pdev);
> > +   struct input_dev *input = vibrator->input;
> > +   unsigned long flags;
> > +
> > +   spin_lock_irqsave(&input->event_lock, flags);
> > +   if (vibrator->level)
> > +           pwm_vibrator_start(vibrator);
> > +   spin_unlock_irqrestore(&input->event_lock, flags);
> > +
> > +   return 0;
> > +}
> > +
> > +static SIMPLE_DEV_PM_OPS(pwm_vibrator_pm_ops,
> > +                    pwm_vibrator_suspend, pwm_vibrator_resume);
> > +
> > +#ifdef CONFIG_OF
> > +
> > +#define PWM_VIB_COMPAT(of_compatible, cfg) {                       \
> > +                   .compatible = of_compatible,            \
> > +                   .data = &cfg,   \
> > +}
> > +
> > +static const struct of_device_id pwm_vibra_dt_match_table[] = {
> > +   PWM_VIB_COMPAT("pwm-vibrator", pwm_vib_hw_generic),
> > +   PWM_VIB_COMPAT("motorola,mapphone-pwm-vibrator", pwm_vib_hw_mapphone),
> > +   {},
> > +};
> > +MODULE_DEVICE_TABLE(of, pwm_vibra_dt_match_table);
> > +#endif
> > +
> > +static struct platform_driver pwm_vibrator_driver = {
> > +   .probe  = pwm_vibrator_probe,
> > +   .driver = {
> > +           .name   = "pwm-vibrator",
> > +           .pm     = &pwm_vibrator_pm_ops,
> > +           .of_match_table = of_match_ptr(pwm_vibra_dt_match_table),
> > +   },
> > +};
> > +module_platform_driver(pwm_vibrator_driver);
> > +
> > +MODULE_AUTHOR("Sebastian Reichel <s...@kernel.org>");
> > +MODULE_DESCRIPTION("PWM vibrator driver");
> > +MODULE_LICENSE("GPL");
> > +MODULE_ALIAS("platform:pwm-vibrator");
> > -- 
> > 2.11.0
> > 
> 
> Thanks.

Thanks for the review.

-- Sebastian

Attachment: signature.asc
Description: PGP signature

Reply via email to