[PATCH 1/2] PWM: ECAP: PWM driver support for ECAP APWM.
Philip, Avinash
avinashphilip at ti.com
Mon Jul 23 05:10:09 EDT 2012
On Mon, Jul 23, 2012 at 12:22:35, Thierry Reding wrote:
> On Fri, Jul 13, 2012 at 03:05:01PM +0530, Philip, Avinash wrote:
[snip]
> > obj-$(CONFIG_PWM_VT8500) += pwm-vt8500.o
> > +obj-$(CONFIG_PWM_ECAP) += pwm-ecap.o
>
> Both the Kconfig and Makefile should have the entries ordered
> alphabetically.
Ok. I will correct it.
>
[snip]
> > +/* ECAP registers and bits definitions */
> > +#define TSCTR 0x00
> > +#define CTRPHS 0x04
> > +#define CAP1 0x08
> > +#define CAP2 0x0C
> > +#define CAP3 0x10
> > +#define CAP4 0x14
> > +#define ECCTL1 0x28
>
> These registers are not used. I guess there is some use to list all
> registers here but on the other hand the majority are unused so they
> just clutter the driver.
>
> > +#define ECCTL2_APWM_POL_LOW BIT(10)
>
> This bit is never used.
>
> > +#define ECEINT 0x2C
> > +#define ECFLG 0x2E
> > +#define ECCLR 0x30
> > +#define REVID 0x5c
>
> These are unused as well.
Ok. I will remove it. These are been placed in future enhancement.
>
> > +
> > +#define DRIVER_NAME "ecap"
>
> You only use this once when defining the struct platform_driver, so
> maybe you can just drop it.
In the v2 patch, I am planning to use same in
platform_get_resource_byname(). Here I will use this define to search
resources.
>
> > +
> > +struct ecap_pwm_chip {
> > + struct pwm_chip chip;
> > + unsigned int clk_rate;
> > + void __iomem *mmio_base;
> > + int pwm_period_ns;
> > + int pwm_duty_ns;
> > +};
>
> The pwm_period_ns and pwm_duty_ns don't seem to be used at all. Can they
> be dropped?
Ok. I will remove it.
>
> > + /*
> > + * Enable 'Free run Time stamp counter mode' to start counter
> > + * and 'APWM mode' to enable APWM output
> > + */
> > + reg_val = readw(pc->mmio_base + ECCTL2);
> > + reg_val |= ECCTL2_TSCTR_FREERUN | ECCTL2_APWM_MODE;
>
> You already set the APWM_MODE bit in .config(), why is it needed here
> again? Seeing that .disable() clears the bit as well, perhaps leaving it
> clear in .config() is the better option.
Clearing APWM mode in .disable() ensures PWM low output (i.e., PWM pin = low
in idle state).
The Period & Compare registers are updated from Shadow registers (CAP1 & CAP2)
During PWM configuration. To enable loading from Shadow registers, APWM mode
should be set.
The same is done in .config().
>
> > +}
> > +
> > +static void ecap_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
> > +{
> > + if (test_bit(PWMF_ENABLED, &pwm->flags)) {
> > + dev_warn(chip->dev, "Removing PWM device without disabling\n");
> > + pm_runtime_put_sync(chip->dev);
> > + }
> > +}
>
> I wonder whether we want to have something like this in the PWM core at
> some point. Maybe we should call .disable() automatically when they are
> freed, or alternatively return -EBUSY if a PWM is freed but still
> enabled. I think I prefer the latter. For now we can leave this in,
> because I don't want to make any such core changes for 3.6 now that the
> merge window is open.
OK Thanks.
>
> > +
> > +static struct pwm_ops ecap_pwm_ops = {
> > + .free = ecap_pwm_free,
> > + .config = ecap_pwm_config,
> > + .enable = ecap_pwm_enable,
> > + .disable = ecap_pwm_disable,
> > + .owner = THIS_MODULE,
> > +};
>
> This should be "static const pwm_ops ...".
Ok I will correct it.
>
> > +
> > +static int __devinit ecap_pwm_probe(struct platform_device *pdev)
> > +{
> > + int ret;
> > + struct resource *r;
> > + struct clk *clk;
> > + struct ecap_pwm_chip *pc;
> > +
> > + pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
> > + if (!pc) {
> > + dev_err(&pdev->dev, "failed to allocate memory\n");
> > + return -ENOMEM;
> > + }
> > +
> > + clk = devm_clk_get(&pdev->dev, "fck");
> > + if (IS_ERR(clk)) {
> > + dev_err(&pdev->dev, "failed to get clock\n");
> > + return PTR_ERR(clk);
> > + }
> > +
> > + pc->clk_rate = clk_get_rate(clk);
> > + if (!pc->clk_rate) {
> > + dev_err(&pdev->dev, "failed to get clock rate\n");
> > + return -EINVAL;
> > + }
> > +
> > + pc->chip.dev = &pdev->dev;
> > + pc->chip.ops = &ecap_pwm_ops;
> > + pc->chip.base = -1;
> > + pc->chip.npwm = 1;
>
> The cover letter mentions that the AM335x has 3 instances of the ECAP.
> Is there any chance that they can be unified in one driver instance
> (i.e. .npwm = 3?).
No. All instances have separate resources (clocks, memory ..).
>
> > +
> > + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ecap_reg");
> > + if (r == NULL) {
>
> You use "if (!ptr)" everywhere else, maybe you should make this
> consistent?
Ok
> Also the platform_get_resource_byname() is really only
> useful for devices that have several register regions associated with
> them. I don't know your hardware in detail, but I doubt that a PWM
> device has more than one register region.
In fact PWM Module has 4 different register space (eCAP, eHRPWM, eQEP &
Common Config space). So I need to use platform_get_resource_byname()
>
> > + dev_err(&pdev->dev, "no memory resource defined\n");
> > + return -ENODEV;
> > + }
> > +
> > + pc->mmio_base = devm_request_and_ioremap(&pdev->dev, r);
> > + if (!pc->mmio_base) {
> > + dev_err(&pdev->dev, "failed to ioremap() registers\n");
> > + return -EADDRNOTAVAIL;
> > + }
> > +
> > + ret = pwmchip_add(&pc->chip);
> > + if (ret < 0) {
> > + dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
> > + return ret;
> > + }
> > +
> > + pm_runtime_enable(&pdev->dev);
> > + platform_set_drvdata(pdev, pc);
> > + dev_info(&pdev->dev, "PWM device initialized\n");
>
> I think this can go away. If none of the above errors is shown you can
> just assume that the PWM was initialized.
Ok. I will remove.
>
> > + return 0;
> > +}
> > +
> > +static int __devexit ecap_pwm_remove(struct platform_device *pdev)
> > +{
> > + struct ecap_pwm_chip *pc = platform_get_drvdata(pdev);
> > + struct pwm_device *pwm;
> > +
> > + if (WARN_ON(!pc))
> > + return -ENODEV;
>
> Do you really want to be this verbose? This kind of check is very rare
> anyway, but explicitly warning about it doesn't seems overkill. I think
> the check can even be left out, since every possible error that would
> lead to the driver data not being checked would already cause .probe()
> to return < 0 and therefore .remove() won't ever be called anyway.
Point taken, I will remove.
>
> > +
> > + pwm = &pc->chip.pwms[0];
>
> You don't use this variable.
Ok
Thanks
Avinash
>
> Thierry
>
More information about the linux-arm-kernel
mailing list