[PATCHv7 1/4] pwm: Add Freescale FTM PWM driver support
Li.Xiubo at freescale.com
Li.Xiubo at freescale.com
Tue Dec 17 22:34:45 EST 2013
> > --- a/drivers/pwm/Makefile
> > +++ b/drivers/pwm/Makefile
> > @@ -5,6 +5,7 @@ obj-$(CONFIG_PWM_ATMEL_TCB) += pwm-atmel-tcb.o
> > obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o
> > obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o
> > obj-$(CONFIG_PWM_IMX) += pwm-imx.o
> > +obj-$(CONFIG_PWM_FSL_FTM) += pwm-fsl-ftm.o
>
> This needs to move up one line to preserve the alphabetical ordering.
>
Yes, it had been. It caused by the rebase operation and after that I
haven't aware about this. I will revise this.
> > diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c
> [...]
> > +struct fsl_pwm_chip {
> [...]
> > + int big_endian;
>
> This should be of type bool.
I'll revise it.
>
> > +};
> > +
> > +static inline u32 fsl_pwm_readl(struct fsl_pwm_chip *fpc,
> > + const void __iomem *addr)
> > +{
> > + u32 val;
> > +
> > + val = __raw_readl(addr);
> > +
> > + if (likely(fpc->big_endian))
>
> The likely() probably isn't very useful in this case. But if you want to
> keep it, it should at least be reversed, since little-endian is actually
> the default (you have to specify the big-endian property to activate the
> big endian mode).
>
So why added the likely() for bit endian mode is that this driver maybe used
for ARM and like PowerPC architectures, and in PowerPC platforms and LS-1 series
the big endian mode will be used almostly. Now only VF610-twr is the little
endian mode devices, and this is also why I added the big endian mode support.
> > + val = be32_to_cpu(val);
> > + else
> > + val = le32_to_cpu(val);
> > + rmb();
>
> I'd prefer the rmb() to follow the __raw_readl() immediately to make the
> relationship more explicit.
>
The fsl_pwm_readl() and fsl_pwm_writel() are almost copied the readl() and
writel().
For instance:
+ static inline u32 fsl_pwm_readl(struct fsl_pwm_chip *fpc,
+ const void __iomem *addr)
+ {
+ u32 val;
+
+ val = __raw_readl(addr);
+
+ if (likely(fpc->big_endian))
+ val = be32_to_cpu(val);
+ else
+ val = le32_to_cpu(val);
+ rmb();
+
+ return val;
+ }
As we can see, this is one inline function, if locating the rmb() just follow
__raw_readl() immediately, I'm not very sure the compiler will do the following
reorders ?
In some function calls the fsl_pwm_readl(Address1) and little-endain mode is used:
The original code is:
tmp = fsl_pwm_readl(Address1)
<Do calculating about the tmp value returned from fsl_pwm_readl here>
Maybe reordered to :
tmp = raw_readl(addr);
rmb();
<Do calculating about the tmp value returned from fsl_pwm_readl here>
tmp = le32_to_cpu(tmp);
...
As we have known that in the fsl_pwm_readl(), the 'val' used by le32_to_cpu() has
a dependency on __raw_readl(), so the compiler will grantee the right orders, and
also the Arch will grantee the right orders too.
This is why I located the rmb() just before 'return val'.
> > +static inline int fsl_pwm_calculate_default_ps(struct fsl_pwm_chip *fpc,
> > + int index)
>
> Please align arguments on subsequent lines with the first argument on the
> first line. There are a few more of those in this file, please check all
> other functions as well.
>
> Also I think it's better to turn the FSL_PWM_CLK_* enum into a named enum
> and reuse the type here. That way you get proper type-checking.
>
> > + switch (index) {
> [...]
> > + default:
> > + return -EINVAL;
>
> And with proper type checking you don't need this default case anymore.
>
I'll revise this.
> > +static unsigned long fsl_pwm_calculate_period_cycles(struct fsl_pwm_chip
> *fpc,
> > + unsigned long period_ns, int index) {
> > + int ret;
> > + unsigned long cycles;
> > +
> > + fpc->counter_clk_select = FTM_SC_CLK(index);
> > +
> > + ret = fsl_pwm_calculate_default_ps(fpc, index);
> > + if (ret) {
> > + dev_err(fpc->chip.dev, "failed to calculate default ps.\n");
>
> No need for the terminating fullstop (.) here, but perhaps you could write
> out what "ps" actually stands for. Also including the error code in the
> error message would be good since you're not propagating the error to the
> caller.
>
Yes, I will.
> > + cycles = fsl_pwm_calculate_cycles(fpc, period_ns);
> > +
> > + return cycles;
>
> This can simply be "return fsl_pwm_calculate_cycles(fpc, period_ns);", in
> which case you can get rid of the cycles variable.
>
That's better.
> > +static unsigned long fsl_pwm_calculate_period(struct fsl_pwm_chip *fpc,
> > + unsigned long period_ns)
> > +{
> [...]
> > + if (fix_rate > ext_rate) {
> > + m0 = FSL_PWM_CLK_FIX;
> > + m1 = FSL_PWM_CLK_EXT;
> > + } else {
> > + m0 = FSL_PWM_CLK_EXT;
> > + m1 = FSL_PWM_CLK_FIX;
> > +
> > + }
>
> There's a gratuitous blank line above this one.
>
I'll remove it.
> > + dev_err(fpc->chip.dev, "fail to config pwm%d, the period "
> > + "time should be the same with the current "
> > + "running pwm(s).\n", pwm->hwpwm);
>
> I think I'd make this error message more terse and put more information
> into a comment. Perhaps something like this:
>
> /*
> * The FSL FTM controller supports only a single period for all PWM
> * channels, therefore incompatible changes need to be refused.
> */
> if (fpc->period_ns && fpc->period_ns != period_ns) {
> dev_err(fpc->chip.dev,
> "conflicting period requested for PWM %u\n",
> pwm->hwpwm);
> ...
> }
>
> > + mutex_unlock(&fpc->lock);
> > + return -EINVAL;
>
> I think something like -EBUSY would be more appropriate here.
>
Agree, I will use this.
> > + if (!fpc->period_ns && duty_ns) {
> > + period = fsl_pwm_calculate_period(fpc, period_ns);
> > + if (!period) {
> > + dev_err(fpc->chip.dev, "fail to calculate the "
>
> "failed"
>
> > + "period cycles.\n");
>
> And no fullstop either. Also I don't think you need "cycles" here. In fact
> something equally accurate like this:
>
> dev_err(fpc->chip.dev, "failed to calculate period\n");
>
> Still fits within 80 characters.
>
Yes, I will.
> > + fpc->period_ns = period_ns;
> > + }
> > + mutex_unlock(&fpc->lock);
>
> This could use a blank line as well.
>
I'll add it.
> > +static int fsl_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device
> *pwm,
> > + enum pwm_polarity polarity)
> > +{
> > + u32 val;
> > + struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
> > +
> > + val = fsl_pwm_readl(fpc, fpc->base + FTM_POL);
> > + if (polarity == PWM_POLARITY_INVERSED)
>
> Blank line between the above.
>
I will.
> > +static int fsl_pwm_probe(struct platform_device *pdev) {
> > + int ret;
> > + struct fsl_pwm_chip *fpc;
> > + struct resource *res;
> > + struct device_node *np = pdev->dev.of_node;
> > +
> > + fpc = devm_kzalloc(&pdev->dev, sizeof(*fpc), GFP_KERNEL);
> > + if (!fpc)
> > + return -ENOMEM;
> > +
> > + mutex_init(&fpc->lock);
> > +
> > + fpc->chip.dev = &pdev->dev;
> > +
> > + fpc->big_endian = of_property_read_bool(np, "big-endian");
> > +
> > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > + fpc->base = devm_ioremap_resource(&pdev->dev, res);
> > + if (IS_ERR(fpc->base))
> > + return PTR_ERR(fpc->base);
> > +
> > + fpc->sys_clk = devm_clk_get(fpc->chip.dev, "ftm_sys");
>
> For consistency I'd use &pdev->dev here...
>
> > + if (IS_ERR(fpc->sys_clk)) {
> > + dev_err(fpc->chip.dev,
>
> ... and here.
>
I will.
> > + ret = pwmchip_add(&fpc->chip);
> > + if (ret < 0) {
> > + dev_err(&pdev->dev, "failed to add PWM chip %d\n", ret);
>
> Perhaps "failed to add PWM chip: %d\n", so that %d isn't confused to mean
> the PWM chip number?
>
Yes, that's better.
> > +static int fsl_pwm_remove(struct platform_device *pdev) {
> > + struct fsl_pwm_chip *fpc = platform_get_drvdata(pdev);
> > +
> > + mutex_destroy(&fpc->lock);
>
> I think you can drop this. Once fsl_pwm_remove() exists, the memory pointed
> to by fpc will be freed, so you won't be able to access the mutex anyway.
>
Yes, actually it is.
Well I think this can make the code more robust and uniform.
Thanks,
--
Xiubo
More information about the linux-arm-kernel
mailing list