linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
From: tomasz.figa@gmail.com (Tomasz Figa)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 08/15] pwm: Add new pwm-samsung driver
Date: Tue, 18 Jun 2013 19:59:55 +0200	[thread overview]
Message-ID: <1430661.RSssKEDPJD@flatron> (raw)
In-Reply-To: <20130617202910.GB5265@mithrandir>

Hi Thierry,

On Monday 17 of June 2013 22:29:11 Thierry Reding wrote:
> On Wed, Jun 05, 2013 at 11:18:13PM +0200, Tomasz Figa wrote:
> > This patch introduces new Samsung PWM driver, which uses Samsung
> > PWM/timer master driver to control shared parts of the hardware.
> > 
> > Signed-off-by: Tomasz Figa <tomasz.figa@gmail.com>
> 
> Sorry for jumping in so late, I've been busy with other things lately.
> 
> > ---
> > 
> >  drivers/pwm/Makefile      |   1 +
> >  drivers/pwm/pwm-samsung.c | 528
> >  ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 529
> >  insertions(+)
> >  create mode 100644 drivers/pwm/pwm-samsung.c
> > 
> > diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
> > index 229a599..833c3ac 100644
> > --- a/drivers/pwm/Makefile
> > +++ b/drivers/pwm/Makefile
> > @@ -9,6 +9,7 @@ obj-$(CONFIG_PWM_MXS)		+= pwm-mxs.o
> > 
> >  obj-$(CONFIG_PWM_PUV3)		+= pwm-puv3.o
> >  obj-$(CONFIG_PWM_PXA)		+= pwm-pxa.o
> >  obj-$(CONFIG_PWM_SAMSUNG)	+= pwm-samsung-legacy.o
> > 
> > +obj-$(CONFIG_PWM_SAMSUNG)	+= pwm-samsung.o
> > 
> >  obj-$(CONFIG_PWM_SPEAR)		+= pwm-spear.o
> >  obj-$(CONFIG_PWM_TEGRA)		+= pwm-tegra.o
> >  obj-$(CONFIG_PWM_TIECAP)	+= pwm-tiecap.o
> > 
> > diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c
> > new file mode 100644
> > index 0000000..61bed3d
> > --- /dev/null
> > +++ b/drivers/pwm/pwm-samsung.c
> > @@ -0,0 +1,528 @@
> > +/* drivers/pwm/pwm-samsung.c
> 
> Nit: this line can be dropped. It serves no purpose.
> 
> > + *
> > + * Copyright (c) 2007 Ben Dooks
> > + * Copyright (c) 2008 Simtec Electronics
> > + *     Ben Dooks <ben@simtec.co.uk>, <ben-linux@fluff.org>
> > + * Copyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.com>
> > + *
> > + * PWM driver for Samsung SoCs
> > + *
> > + * 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. +*/
> 
> Nit: the */ should align with the * above.
> 
> > +struct samsung_pwm_channel {
> > +	unsigned long period_ns;
> > +	unsigned long duty_ns;
> > +	unsigned long tin_ns;
> > +};
> > +
> > +struct samsung_pwm_chip {
> > +	struct pwm_chip chip;
> > +	struct samsung_pwm_variant variant;
> > +	struct samsung_pwm_channel channels[SAMSUNG_PWM_NUM];
> 
> The new driver for Renesas did something similar, but I want to
> discourage storing per-channel data within the chip structure.
> 
> The PWM framework provides a way to store this information along with
> the PWM device (see pwm_{set,get}_chip_data()).
> 
> > +
> > +	void __iomem *base;
> > +	struct clk *base_clk;
> > +	struct clk *tclk0;
> > +	struct clk *tclk1;
> > +};
> > +#define to_samsung_pwm_chip(chip)	\
> > +			container_of(chip, struct samsung_pwm_chip, chip)
> 
> Can you turn this into a static inline function please?
> 
> > +#ifndef CONFIG_CLKSRC_SAMSUNG_PWM
> > +static DEFINE_SPINLOCK(samsung_pwm_lock);
> > +#endif
> 
> Why is this lock global? Shouldn't it more correctly be part of
> samsung_pwm_chip?
> 
> > +static void pwm_samsung_set_divisor(struct samsung_pwm_chip *pwm,
> > +					unsigned int channel, u8 divisor)
> 
> Nit: please align arguments on subsequent lines with the first argument
> of the first line. There's many more of these but I haven't mentioned
> them all explicitly.

Hmm, I'm addressing all your comments that aren't addressed yet in v2 at 
the moment and I'm wondering if this is really the correct way of breaking 
function headers...

According to Documentation/CodingStyle:

/* Quotation starts */
Statements longer than 80 columns will be broken into sensible chunks, 
unless exceeding 80 columns significantly increases readability and does 
not hide information. Descendants are always substantially shorter than 
the parent and are placed substantially to the right. The same applies to 
function headers with a long argument list. However, never break user-
visible strings such as printk messages, because that breaks the ability 
to grep for them.
/* Quotation ends */

Do I understand this incorrectly or does the above fragment state that 
broken lines must be aligned to the right?

Best regards,
Tomasz

> > +static inline int pwm_samsung_is_tdiv(struct samsung_pwm_chip *chip,
> 
> Any particular reason for making this inline?
> 
> > +static int pwm_samsung_config(struct pwm_chip *chip, struct
> > pwm_device *pwm, +		int duty_ns, int period_ns)
> > +{
> > +	struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
> > +	struct samsung_pwm_channel *chan = &our_chip->channels[pwm-
>hwpwm];
> > +	unsigned long tin_ns = chan->tin_ns;
> > +	unsigned int tcon_chan = pwm->hwpwm;
> > +	unsigned long tin_rate;
> > +	unsigned long period;
> > +	unsigned long flags;
> > +	unsigned long tcnt;
> 
> Many of these unsigned long variable could be declared on a single line
> to make the function shorter.
> 
> > +	long tcmp;
> > +	u32 tcon;
> > +
> > +	/* We currently avoid using 64bit arithmetic by using the
> > +	 * fact that anything faster than 1Hz is easily representable
> > +	 * by 32bits. */
> 
> Can you turn these into proper block-style comments? Like so:
> 
> 	/*
> 	 * We currently...
> 	 * ...
> 	 * by 32 bits.
> 	 */
> 
> > +	if (period_ns > NSEC_PER_SEC || duty_ns > NSEC_PER_SEC)
> > +		return -ERANGE;
> 
> Note that technically you only need to check period_ns because the core
> already ensures that duty_ns <= period_ns.
> 
> > +static int pwm_samsung_set_polarity(struct pwm_chip *chip,
> > +			struct pwm_device *pwm, enum pwm_polarity 
polarity)
> > +{
> > +	struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
> > +	unsigned int channel = pwm->hwpwm;
> > +	unsigned long flags;
> > +	u32 tcon;
> > +
> > +	if (channel > 0)
> > +		++channel;
> 
> You have to repeat that in quite a few places, so I wonder if it'd make
> sense to wrap it into a function and add a comment about why the
> increment is necessary.
> 
> > +static struct pwm_ops pwm_samsung_ops = {
> 
> "static const" please.
> 
> > +#ifdef CONFIG_OF
> > +static const struct samsung_pwm_variant s3c24xx_variant = {
> > +	.bits		= 16,
> > +	.div_base	= 1,
> > +	.has_tint_cstat	= false,
> > +	.tclk_mask	= (1 << 4),
> > +};
> > +
> > +static const struct samsung_pwm_variant s3c64xx_variant = {
> > +	.bits		= 32,
> > +	.div_base	= 0,
> > +	.has_tint_cstat	= true,
> > +	.tclk_mask	= (1 << 7) | (1 << 6) | (1 << 5),
> > +};
> > +
> > +static const struct samsung_pwm_variant s5p64x0_variant = {
> > +	.bits		= 32,
> > +	.div_base	= 0,
> > +	.has_tint_cstat	= true,
> > +	.tclk_mask	= 0,
> > +};
> > +
> > +static const struct samsung_pwm_variant s5p_variant = {
> > +	.bits		= 32,
> > +	.div_base	= 0,
> > +	.has_tint_cstat	= true,
> > +	.tclk_mask	= (1 << 5),
> > +};
> > +
> > +static const struct of_device_id samsung_pwm_matches[] = {
> > +	{ .compatible = "samsung,s3c2410-pwm", .data = &s3c24xx_variant },
> > +	{ .compatible = "samsung,s3c6400-pwm", .data = &s3c64xx_variant },
> > +	{ .compatible = "samsung,s5p6440-pwm", .data = &s5p64x0_variant },
> > +	{ .compatible = "samsung,s5pc100-pwm", .data = &s5p_variant },
> > +	{ .compatible = "samsung,exynos4210-pwm", .data = &s5p64x0_variant
> > },
> > +	{},
> > +};
> > +#endif
> > +
> > +static int pwm_samsung_parse_dt(struct samsung_pwm_chip *chip)
> > +{
> > +	struct device_node *np = chip->chip.dev->of_node;
> > +	const struct of_device_id *match;
> > +	struct property *prop;
> > +	const __be32 *cur;
> > +	u32 val;
> > +
> > +	match = of_match_node(samsung_pwm_matches, np);
> > +	if (!match)
> > +		return -ENODEV;
> > +
> > +	memcpy(&chip->variant, match->data, sizeof(chip->variant));
> > +
> > +	of_property_for_each_u32(np, "samsung,pwm-outputs", prop, cur, 
val)
> > {
> > +		if (val >= SAMSUNG_PWM_NUM) {
> > +			pr_warning("%s: invalid channel index in 
samsung,pwm-outputs
> > property\n", +								
__func__);
> > +			continue;
> > +		}
> > +		chip->variant.output_mask |= 1 << val;
> 
> Could the output_mask be moved to the struct samsung_pwm_chip instead?
> The reason I ask is because it would allow you to make the variant
> constant throughout the driver.
> 
> > +static int pwm_samsung_probe(struct platform_device *pdev)
> > +{
> > +	struct device *dev = &pdev->dev;
> > +	struct samsung_pwm_chip *chip;
> > +	struct resource *res;
> > +	int ret;
> > +
> > +	chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
> > +	if (chip == NULL) {
> > +		dev_err(dev, "failed to allocate driver data\n");
> > +		return -ENOMEM;
> > +	}
> > +
> > +	chip->chip.dev = &pdev->dev;
> > +	chip->chip.ops = &pwm_samsung_ops;
> > +	chip->chip.base = -1;
> > +	chip->chip.npwm = SAMSUNG_PWM_NUM;
> > +
> > +	if (pdev->dev.of_node) {
> 
> Maybe add an IS_ENABLED(CONFIG_OF) check here? That'd allow all OF-
> related code to be thrown away if OF isn't selected.
> 
> > +		ret = pwm_samsung_parse_dt(chip);
> > +		if (ret)
> > +			return ret;
> > +
> > +		chip->chip.of_xlate = of_pwm_xlate_with_flags;
> > +		chip->chip.of_pwm_n_cells = 3;
> > +	} else {
> > +		if (!pdev->dev.platform_data) {
> > +			dev_err(&pdev->dev, "no platform data 
specified\n");
> > +			return -EINVAL;
> > +		}
> > +
> > +		memcpy(&chip->variant, pdev->dev.platform_data,
> > +							sizeof(chip-
>variant));
> > +	}
> 
> Obviously this needs some modification in order for the variant to
> become constant. But I think you can easily do so by making the driver
> match using the platform_driver's id_table field, similar to how the
> matching is done for OF.
> 
> > +	chip->base = devm_request_and_ioremap(&pdev->dev, res);
> > +	if (!chip->base) {
> > +		dev_err(&pdev->dev, "failed to request and map 
registers\n");
> > +		return -ENOMEM;
> > +	}
> 
> devm_request_and_ioremap() is now deprecated and in the process of being
> removed. You should use devm_ioremap_resource() instead.
> 
> > +
> > +	chip->base_clk = devm_clk_get(&pdev->dev, "timers");
> > +	if (IS_ERR(chip->base_clk)) {
> > +		dev_err(dev, "failed to get timer base clk\n");
> > +		return PTR_ERR(chip->base_clk);
> > +	}
> > +	clk_prepare_enable(chip->base_clk);
> 
> You need to check the return value of clk_prepare_enable(). And if I was
> very pedantic, there should be a blank line before this one.
> 
> > +	ret = pwmchip_add(&chip->chip);
> > +	if (ret < 0) {
> > +		dev_err(dev, "failed to register pwm\n");
> 
> "failed to register PWM chip" please.
> 
> > +		goto err_clk_disable;
> > +	}
> > +
> > +	dev_info(dev, "base_clk at %lu, tclk0 at %lu, tclk1 at %lu\n",
> > +		clk_get_rate(chip->base_clk),
> > +		!IS_ERR(chip->tclk0) ? clk_get_rate(chip->tclk0) : 0,
> > +		!IS_ERR(chip->tclk1) ? clk_get_rate(chip->tclk1) : 0);
> > +
> > +	platform_set_drvdata(pdev, chip);
> > +
> > +	return 0;
> > +
> > +err_clk_disable:
> > +	clk_disable_unprepare(chip->base_clk);
> > +
> > +	return ret;
> 
> There's only a single case where this can actually happen, so I don't
> think you need the label here. Just put the clk_disable_unprepare() call
> and the return statement where you jump to the label.
> 
> > +#ifdef CONFIG_PM
> 
> I think this should really be CONFIG_PM_SLEEP.
> 
> > +static struct dev_pm_ops pwm_samsung_pm_ops = {
> 
> "static const" please.
> 
> Thierry

  parent reply	other threads:[~2013-06-18 17:59 UTC|newest]

Thread overview: 51+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-06-05 21:18 [PATCH 00/15] Final Samsung PWM support cleanup Tomasz Figa
2013-06-05 21:18 ` [PATCH 01/15] ARM: SAMSUNG: Unify base address definitions of timer block Tomasz Figa
2013-06-05 21:18 ` [PATCH 02/15] ARM: SAMSUNG: Add new PWM platform device Tomasz Figa
2013-06-05 21:18 ` [PATCH 03/15] ARM: SAMSUNG: Set PWM platform data Tomasz Figa
2013-06-05 21:18 ` [PATCH 04/15] ARM: SAMSUNG: Move all platforms to new clocksource driver Tomasz Figa
2013-06-05 21:18 ` [PATCH 05/15] ARM: SAMSUNG: Remove old samsung-time driver Tomasz Figa
2013-06-05 21:18 ` [PATCH 06/15] ARM: SAMSUNG: Remove unused PWM timer IRQ chip code Tomasz Figa
2013-06-05 21:18 ` [PATCH 07/15] pwm: samsung: Rename to pwm-samsung-legacy Tomasz Figa
2013-06-05 21:18 ` [PATCH 08/15] pwm: Add new pwm-samsung driver Tomasz Figa
2013-06-13 20:14   ` Heiko Stübner
2013-06-13 20:18     ` Tomasz Figa
2013-06-16 17:19   ` Tomasz Figa
2013-06-16 20:45     ` Kukjin Kim
2013-06-17 20:29   ` Thierry Reding
2013-06-17 20:50     ` Tomasz Figa
2013-06-18 22:17       ` Thierry Reding
2013-06-18 22:45         ` Tomasz Figa
2013-06-19  9:43           ` Thierry Reding
2013-06-19 10:23             ` Tomasz Figa
2013-06-24 17:52               ` Tomasz Figa
2013-06-24 19:50                 ` Thierry Reding
2013-06-24 20:03                   ` Tomasz Figa
2013-06-24 20:28                     ` Thierry Reding
2013-06-24 20:55                     ` Arnd Bergmann
2013-06-18 17:59     ` Tomasz Figa [this message]
2013-06-18 18:06       ` Kukjin Kim
2013-06-18 18:13         ` Tomasz Figa
2013-06-18 21:33           ` Thierry Reding
2013-06-18 21:35             ` Tomasz Figa
2013-06-18 19:41     ` Tomasz Figa
2013-06-18 21:40       ` Thierry Reding
2013-06-18 21:42         ` Tomasz Figa
2013-06-18 22:20           ` Thierry Reding
2013-06-05 21:18 ` [PATCH 09/15] ARM: SAMSUNG: Rework private data handling in dev-backlight Tomasz Figa
2013-06-05 21:18 ` [PATCH 10/15] ARM: SAMSUNG: Modify board files to use new PWM platform device Tomasz Figa
2013-06-05 21:18 ` [PATCH 11/15] pwm: Remove superseded pwm-samsung-legacy driver Tomasz Figa
2013-06-05 21:18 ` [PATCH 12/15] ARM: SAMSUNG: Remove old PWM timer platform devices Tomasz Figa
2013-06-05 21:18 ` [PATCH 13/15] ARM: SAMSUNG: Remove pwm-clock infrastructure Tomasz Figa
2013-06-05 21:18 ` [PATCH 14/15] ARM: SAMSUNG: Remove remaining uses of plat/regs-timer.h header Tomasz Figa
2013-06-13 20:24   ` Heiko Stübner
2013-06-13 20:38     ` Tomasz Figa
2013-06-05 21:18 ` [PATCH 15/15] ARM: SAMSUNG: Remove " Tomasz Figa
2013-06-12 21:48 ` [PATCH 00/15] Final Samsung PWM support cleanup Tomasz Figa
2013-06-12 23:00   ` Olof Johansson
2013-06-12 23:13     ` Tomasz Figa
2013-06-12 23:38       ` Heiko Stübner
2013-06-12 23:52         ` Sylwester Nawrocki
2013-06-13  9:07           ` Tomasz Figa
2013-06-13 20:17             ` Heiko Stübner
2013-06-13 22:27               ` Heiko Stübner
2013-06-13  0:25     ` Kukjin Kim

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1430661.RSssKEDPJD@flatron \
    --to=tomasz.figa@gmail.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).