[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