Re: [RFC 2/4] pwm: sifive: Add a driver for SiFive SoC PWM

2018-10-16 Thread Atish Patra

On 10/10/18 6:11 AM, Christoph Hellwig wrote:

Thanks for getting these drivers submitted upstream!

I don't really know anything about PWM, so just some random nitpicking
below..


+   iowrite32(frac, pwm->regs + REG_PWMCMP0 + (dev->hwpwm * SIZE_PWMCMP));


* already has a higher precedence than +, so no need for the inner
braces.


+   duty = ioread32(pwm->regs + REG_PWMCMP0 + (dev->hwpwm * SIZE_PWMCMP));


Same here.


Will remove the braces in both places.



+   /* (1 << (16+scale)) * 10^9/rate = real_period */

unsigned long scalePow = (pwm->approx_period * (u64)rate) / 10;

no camcel case, please.


My bad. I will fix that.




+   int scale = ilog2(scalePow) - 16;
+
+   scale = clamp(scale, 0, 0xf);


Why not:

int scale = clamp(ilog2(scale_pow) - 16, 0, 0xf);



Sure.


+static int sifive_pwm_clock_notifier(struct notifier_block *nb,
+unsigned long event, void *data)
+{
+   struct clk_notifier_data *ndata = data;
+   struct sifive_pwm_device *pwm = container_of(nb,
+struct sifive_pwm_device,
+notifier);


I don't think there are any guidlines, but I always prefer to just move
the whole container_of onto a new line:

struct sifive_pwm_device *pwm =
container_of(nb, struct sifive_pwm_device, notifier);


Done.

Regards,
Atish



+static struct platform_driver sifive_pwm_driver = {
+   .probe = sifive_pwm_probe,
+   .remove = sifive_pwm_remove,
+   .driver = {
+   .name = "pwm-sifivem",
+   .of_match_table = of_match_ptr(sifive_pwm_of_match),
+   },
+};


What about using tabs to align this a little more nicely?

static struct platform_driver sifive_pwm_driver = {
.probe  = sifive_pwm_probe,
.remove = sifive_pwm_remove,
.driver = {
.name   = "pwm-sifivem",
.of_match_table = of_match_ptr(sifive_pwm_of_match),
},
};





Re: [RFC 2/4] pwm: sifive: Add a driver for SiFive SoC PWM

2018-10-16 Thread Atish Patra

On 10/10/18 6:11 AM, Christoph Hellwig wrote:

Thanks for getting these drivers submitted upstream!

I don't really know anything about PWM, so just some random nitpicking
below..


+   iowrite32(frac, pwm->regs + REG_PWMCMP0 + (dev->hwpwm * SIZE_PWMCMP));


* already has a higher precedence than +, so no need for the inner
braces.


+   duty = ioread32(pwm->regs + REG_PWMCMP0 + (dev->hwpwm * SIZE_PWMCMP));


Same here.


Will remove the braces in both places.



+   /* (1 << (16+scale)) * 10^9/rate = real_period */

unsigned long scalePow = (pwm->approx_period * (u64)rate) / 10;

no camcel case, please.


My bad. I will fix that.




+   int scale = ilog2(scalePow) - 16;
+
+   scale = clamp(scale, 0, 0xf);


Why not:

int scale = clamp(ilog2(scale_pow) - 16, 0, 0xf);



Sure.


+static int sifive_pwm_clock_notifier(struct notifier_block *nb,
+unsigned long event, void *data)
+{
+   struct clk_notifier_data *ndata = data;
+   struct sifive_pwm_device *pwm = container_of(nb,
+struct sifive_pwm_device,
+notifier);


I don't think there are any guidlines, but I always prefer to just move
the whole container_of onto a new line:

struct sifive_pwm_device *pwm =
container_of(nb, struct sifive_pwm_device, notifier);


Done.

Regards,
Atish



+static struct platform_driver sifive_pwm_driver = {
+   .probe = sifive_pwm_probe,
+   .remove = sifive_pwm_remove,
+   .driver = {
+   .name = "pwm-sifivem",
+   .of_match_table = of_match_ptr(sifive_pwm_of_match),
+   },
+};


What about using tabs to align this a little more nicely?

static struct platform_driver sifive_pwm_driver = {
.probe  = sifive_pwm_probe,
.remove = sifive_pwm_remove,
.driver = {
.name   = "pwm-sifivem",
.of_match_table = of_match_ptr(sifive_pwm_of_match),
},
};





Re: [RFC 2/4] pwm: sifive: Add a driver for SiFive SoC PWM

2018-10-16 Thread Atish Patra

On 10/10/18 7:13 AM, Thierry Reding wrote:

On Tue, Oct 09, 2018 at 11:51:23AM -0700, Atish Patra wrote:

From: "Wesley W. Terpstra" 

Adds a PWM driver for PWM chip present in SiFive's HiFive Unleashed SoC.

Signed-off-by: Wesley W. Terpstra 
[Atish: Various fixes and code cleanup]
Signed-off-by: Atish Patra 
---
  drivers/pwm/Kconfig  |  10 ++
  drivers/pwm/Makefile |   1 +
  drivers/pwm/pwm-sifive.c | 240 +++
  3 files changed, 251 insertions(+)
  create mode 100644 drivers/pwm/pwm-sifive.c

diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 504d2527..dd12144d 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -378,6 +378,16 @@ config PWM_SAMSUNG
  To compile this driver as a module, choose M here: the module
  will be called pwm-samsung.
  
+config PWM_SIFIVE

+   tristate "SiFive PWM support"
+   depends on OF
+   depends on COMMON_CLK
+   help
+ Generic PWM framework driver for SiFive SoCs.
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-sifive.
+
  config PWM_SPEAR
tristate "STMicroelectronics SPEAr PWM support"
depends on PLAT_SPEAR
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 9c676a0d..30089ca6 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_PWM_RCAR)+= pwm-rcar.o
  obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o
  obj-$(CONFIG_PWM_ROCKCHIP)+= pwm-rockchip.o
  obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
+obj-$(CONFIG_PWM_SIFIVE)   += pwm-sifive.o
  obj-$(CONFIG_PWM_SPEAR)   += pwm-spear.o
  obj-$(CONFIG_PWM_STI) += pwm-sti.o
  obj-$(CONFIG_PWM_STM32)   += pwm-stm32.o
diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c
new file mode 100644
index ..99580025
--- /dev/null
+++ b/drivers/pwm/pwm-sifive.c
@@ -0,0 +1,240 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 SiFive
+ */
+#include 


What do you need this for? Your driver should only be dealing with enum
pwm_polarity, not the defines from the above header. This works but only
because PWM_POLARITY_INVERTED and PWM_POLARITY_INVERSED happen to be the
same value.


+#include 
+#include 
+#include 
+#include 
+#include 
+#include 


Keep these in alphabetical order, please.


+
+#define MAX_PWM4
+
+/* Register offsets */
+#define REG_PWMCFG 0x0
+#define REG_PWMCOUNT   0x8
+#define REG_PWMS   0x10
+#defineREG_PWMCMP0 0x20
+
+/* PWMCFG fields */
+#define BIT_PWM_SCALE  0
+#define BIT_PWM_STICKY 8
+#define BIT_PWM_ZERO_ZMP   9
+#define BIT_PWM_DEGLITCH   10
+#define BIT_PWM_EN_ALWAYS  12
+#define BIT_PWM_EN_ONCE13
+#define BIT_PWM0_CENTER16
+#define BIT_PWM0_GANG  24
+#define BIT_PWM0_IP28
+
+#define SIZE_PWMCMP4
+#define MASK_PWM_SCALE 0xf
+
+struct sifive_pwm_device {
+   struct pwm_chip chip;
+   struct notifier_block   notifier;
+   struct clk  *clk;
+   void __iomem*regs;
+   unsigned intapprox_period;
+   unsigned intreal_period;
+};


No need to align these. A single space is enough to separate variable
type and name.


+
+static inline struct sifive_pwm_device *to_sifive_pwm_chip(struct pwm_chip *c)
+{
+   return container_of(c, struct sifive_pwm_device, chip);
+}
+
+static int sifive_pwm_apply(struct pwm_chip *chip, struct pwm_device *dev,
+   struct pwm_state *state)
+{
+   struct sifive_pwm_device *pwm = to_sifive_pwm_chip(chip);
+   unsigned int duty_cycle;
+   u32 frac;
+
+   duty_cycle = state->duty_cycle;
+   if (!state->enabled)
+   duty_cycle = 0;
+   if (state->polarity == PWM_POLARITY_NORMAL)
+   duty_cycle = state->period - duty_cycle;


That's not actually polarity inversion. This is "lightweight" inversion
which should be up to the consumer, not the PWM driver, to implement. If
you don't actually have a knob in hardware to switch the polarity, don't
support it.



I couldn't find anything about polarity support in the spec. Of course, 
I might be complete idiot as well :). I will wait for Wesly's confirmation.




+
+   frac = ((u64)duty_cycle << 16) / state->period;
+   frac = min(frac, 0xU);
+
+   iowrite32(frac, pwm->regs + REG_PWMCMP0 + (dev->hwpwm * SIZE_PWMCMP));


writel()?





+
+   if (state->enabled) {
+   state->period = pwm->real_period;
+   state->duty_cycle = ((u64)frac * pwm->real_period) >> 16;
+   if (state->polarity == PWM_POLARITY_NORMAL)
+   state->duty_cycle = state->period - state->duty_cycle;
+   }
+
+   return 0;
+}
+
+static void 

Re: [RFC 2/4] pwm: sifive: Add a driver for SiFive SoC PWM

2018-10-16 Thread Atish Patra

On 10/10/18 7:13 AM, Thierry Reding wrote:

On Tue, Oct 09, 2018 at 11:51:23AM -0700, Atish Patra wrote:

From: "Wesley W. Terpstra" 

Adds a PWM driver for PWM chip present in SiFive's HiFive Unleashed SoC.

Signed-off-by: Wesley W. Terpstra 
[Atish: Various fixes and code cleanup]
Signed-off-by: Atish Patra 
---
  drivers/pwm/Kconfig  |  10 ++
  drivers/pwm/Makefile |   1 +
  drivers/pwm/pwm-sifive.c | 240 +++
  3 files changed, 251 insertions(+)
  create mode 100644 drivers/pwm/pwm-sifive.c

diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 504d2527..dd12144d 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -378,6 +378,16 @@ config PWM_SAMSUNG
  To compile this driver as a module, choose M here: the module
  will be called pwm-samsung.
  
+config PWM_SIFIVE

+   tristate "SiFive PWM support"
+   depends on OF
+   depends on COMMON_CLK
+   help
+ Generic PWM framework driver for SiFive SoCs.
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-sifive.
+
  config PWM_SPEAR
tristate "STMicroelectronics SPEAr PWM support"
depends on PLAT_SPEAR
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 9c676a0d..30089ca6 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_PWM_RCAR)+= pwm-rcar.o
  obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o
  obj-$(CONFIG_PWM_ROCKCHIP)+= pwm-rockchip.o
  obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
+obj-$(CONFIG_PWM_SIFIVE)   += pwm-sifive.o
  obj-$(CONFIG_PWM_SPEAR)   += pwm-spear.o
  obj-$(CONFIG_PWM_STI) += pwm-sti.o
  obj-$(CONFIG_PWM_STM32)   += pwm-stm32.o
diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c
new file mode 100644
index ..99580025
--- /dev/null
+++ b/drivers/pwm/pwm-sifive.c
@@ -0,0 +1,240 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 SiFive
+ */
+#include 


What do you need this for? Your driver should only be dealing with enum
pwm_polarity, not the defines from the above header. This works but only
because PWM_POLARITY_INVERTED and PWM_POLARITY_INVERSED happen to be the
same value.


+#include 
+#include 
+#include 
+#include 
+#include 
+#include 


Keep these in alphabetical order, please.


+
+#define MAX_PWM4
+
+/* Register offsets */
+#define REG_PWMCFG 0x0
+#define REG_PWMCOUNT   0x8
+#define REG_PWMS   0x10
+#defineREG_PWMCMP0 0x20
+
+/* PWMCFG fields */
+#define BIT_PWM_SCALE  0
+#define BIT_PWM_STICKY 8
+#define BIT_PWM_ZERO_ZMP   9
+#define BIT_PWM_DEGLITCH   10
+#define BIT_PWM_EN_ALWAYS  12
+#define BIT_PWM_EN_ONCE13
+#define BIT_PWM0_CENTER16
+#define BIT_PWM0_GANG  24
+#define BIT_PWM0_IP28
+
+#define SIZE_PWMCMP4
+#define MASK_PWM_SCALE 0xf
+
+struct sifive_pwm_device {
+   struct pwm_chip chip;
+   struct notifier_block   notifier;
+   struct clk  *clk;
+   void __iomem*regs;
+   unsigned intapprox_period;
+   unsigned intreal_period;
+};


No need to align these. A single space is enough to separate variable
type and name.


+
+static inline struct sifive_pwm_device *to_sifive_pwm_chip(struct pwm_chip *c)
+{
+   return container_of(c, struct sifive_pwm_device, chip);
+}
+
+static int sifive_pwm_apply(struct pwm_chip *chip, struct pwm_device *dev,
+   struct pwm_state *state)
+{
+   struct sifive_pwm_device *pwm = to_sifive_pwm_chip(chip);
+   unsigned int duty_cycle;
+   u32 frac;
+
+   duty_cycle = state->duty_cycle;
+   if (!state->enabled)
+   duty_cycle = 0;
+   if (state->polarity == PWM_POLARITY_NORMAL)
+   duty_cycle = state->period - duty_cycle;


That's not actually polarity inversion. This is "lightweight" inversion
which should be up to the consumer, not the PWM driver, to implement. If
you don't actually have a knob in hardware to switch the polarity, don't
support it.



I couldn't find anything about polarity support in the spec. Of course, 
I might be complete idiot as well :). I will wait for Wesly's confirmation.




+
+   frac = ((u64)duty_cycle << 16) / state->period;
+   frac = min(frac, 0xU);
+
+   iowrite32(frac, pwm->regs + REG_PWMCMP0 + (dev->hwpwm * SIZE_PWMCMP));


writel()?





+
+   if (state->enabled) {
+   state->period = pwm->real_period;
+   state->duty_cycle = ((u64)frac * pwm->real_period) >> 16;
+   if (state->polarity == PWM_POLARITY_NORMAL)
+   state->duty_cycle = state->period - state->duty_cycle;
+   }
+
+   return 0;
+}
+
+static void 

Re: [RFC 2/4] pwm: sifive: Add a driver for SiFive SoC PWM

2018-10-10 Thread Thierry Reding
On Tue, Oct 09, 2018 at 11:51:23AM -0700, Atish Patra wrote:
> From: "Wesley W. Terpstra" 
> 
> Adds a PWM driver for PWM chip present in SiFive's HiFive Unleashed SoC.
> 
> Signed-off-by: Wesley W. Terpstra 
> [Atish: Various fixes and code cleanup]
> Signed-off-by: Atish Patra 
> ---
>  drivers/pwm/Kconfig  |  10 ++
>  drivers/pwm/Makefile |   1 +
>  drivers/pwm/pwm-sifive.c | 240 
> +++
>  3 files changed, 251 insertions(+)
>  create mode 100644 drivers/pwm/pwm-sifive.c
> 
> diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
> index 504d2527..dd12144d 100644
> --- a/drivers/pwm/Kconfig
> +++ b/drivers/pwm/Kconfig
> @@ -378,6 +378,16 @@ config PWM_SAMSUNG
> To compile this driver as a module, choose M here: the module
> will be called pwm-samsung.
>  
> +config PWM_SIFIVE
> + tristate "SiFive PWM support"
> + depends on OF
> + depends on COMMON_CLK
> + help
> +   Generic PWM framework driver for SiFive SoCs.
> +
> +   To compile this driver as a module, choose M here: the module
> +   will be called pwm-sifive.
> +
>  config PWM_SPEAR
>   tristate "STMicroelectronics SPEAr PWM support"
>   depends on PLAT_SPEAR
> diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
> index 9c676a0d..30089ca6 100644
> --- a/drivers/pwm/Makefile
> +++ b/drivers/pwm/Makefile
> @@ -37,6 +37,7 @@ obj-$(CONFIG_PWM_RCAR)  += pwm-rcar.o
>  obj-$(CONFIG_PWM_RENESAS_TPU)+= pwm-renesas-tpu.o
>  obj-$(CONFIG_PWM_ROCKCHIP)   += pwm-rockchip.o
>  obj-$(CONFIG_PWM_SAMSUNG)+= pwm-samsung.o
> +obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o
>  obj-$(CONFIG_PWM_SPEAR)  += pwm-spear.o
>  obj-$(CONFIG_PWM_STI)+= pwm-sti.o
>  obj-$(CONFIG_PWM_STM32)  += pwm-stm32.o
> diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c
> new file mode 100644
> index ..99580025
> --- /dev/null
> +++ b/drivers/pwm/pwm-sifive.c
> @@ -0,0 +1,240 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2017 SiFive
> + */
> +#include 

What do you need this for? Your driver should only be dealing with enum
pwm_polarity, not the defines from the above header. This works but only
because PWM_POLARITY_INVERTED and PWM_POLARITY_INVERSED happen to be the
same value.

> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 

Keep these in alphabetical order, please.

> +
> +#define MAX_PWM  4
> +
> +/* Register offsets */
> +#define REG_PWMCFG   0x0
> +#define REG_PWMCOUNT 0x8
> +#define REG_PWMS 0x10
> +#define  REG_PWMCMP0 0x20
> +
> +/* PWMCFG fields */
> +#define BIT_PWM_SCALE0
> +#define BIT_PWM_STICKY   8
> +#define BIT_PWM_ZERO_ZMP 9
> +#define BIT_PWM_DEGLITCH 10
> +#define BIT_PWM_EN_ALWAYS12
> +#define BIT_PWM_EN_ONCE  13
> +#define BIT_PWM0_CENTER  16
> +#define BIT_PWM0_GANG24
> +#define BIT_PWM0_IP  28
> +
> +#define SIZE_PWMCMP  4
> +#define MASK_PWM_SCALE   0xf
> +
> +struct sifive_pwm_device {
> + struct pwm_chip chip;
> + struct notifier_block   notifier;
> + struct clk  *clk;
> + void __iomem*regs;
> + unsigned intapprox_period;
> + unsigned intreal_period;
> +};

No need to align these. A single space is enough to separate variable
type and name.

> +
> +static inline struct sifive_pwm_device *to_sifive_pwm_chip(struct pwm_chip 
> *c)
> +{
> + return container_of(c, struct sifive_pwm_device, chip);
> +}
> +
> +static int sifive_pwm_apply(struct pwm_chip *chip, struct pwm_device *dev,
> + struct pwm_state *state)
> +{
> + struct sifive_pwm_device *pwm = to_sifive_pwm_chip(chip);
> + unsigned int duty_cycle;
> + u32 frac;
> +
> + duty_cycle = state->duty_cycle;
> + if (!state->enabled)
> + duty_cycle = 0;
> + if (state->polarity == PWM_POLARITY_NORMAL)
> + duty_cycle = state->period - duty_cycle;

That's not actually polarity inversion. This is "lightweight" inversion
which should be up to the consumer, not the PWM driver, to implement. If
you don't actually have a knob in hardware to switch the polarity, don't
support it.

> +
> + frac = ((u64)duty_cycle << 16) / state->period;
> + frac = min(frac, 0xU);
> +
> + iowrite32(frac, pwm->regs + REG_PWMCMP0 + (dev->hwpwm * SIZE_PWMCMP));

writel()?

> +
> + if (state->enabled) {
> + state->period = pwm->real_period;
> + state->duty_cycle = ((u64)frac * pwm->real_period) >> 16;
> + if (state->polarity == PWM_POLARITY_NORMAL)
> + state->duty_cycle = state->period - state->duty_cycle;
> + }
> +
> + return 0;
> +}
> +
> +static void sifive_pwm_get_state(struct pwm_chip *chip, struct 

Re: [RFC 2/4] pwm: sifive: Add a driver for SiFive SoC PWM

2018-10-10 Thread Thierry Reding
On Tue, Oct 09, 2018 at 11:51:23AM -0700, Atish Patra wrote:
> From: "Wesley W. Terpstra" 
> 
> Adds a PWM driver for PWM chip present in SiFive's HiFive Unleashed SoC.
> 
> Signed-off-by: Wesley W. Terpstra 
> [Atish: Various fixes and code cleanup]
> Signed-off-by: Atish Patra 
> ---
>  drivers/pwm/Kconfig  |  10 ++
>  drivers/pwm/Makefile |   1 +
>  drivers/pwm/pwm-sifive.c | 240 
> +++
>  3 files changed, 251 insertions(+)
>  create mode 100644 drivers/pwm/pwm-sifive.c
> 
> diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
> index 504d2527..dd12144d 100644
> --- a/drivers/pwm/Kconfig
> +++ b/drivers/pwm/Kconfig
> @@ -378,6 +378,16 @@ config PWM_SAMSUNG
> To compile this driver as a module, choose M here: the module
> will be called pwm-samsung.
>  
> +config PWM_SIFIVE
> + tristate "SiFive PWM support"
> + depends on OF
> + depends on COMMON_CLK
> + help
> +   Generic PWM framework driver for SiFive SoCs.
> +
> +   To compile this driver as a module, choose M here: the module
> +   will be called pwm-sifive.
> +
>  config PWM_SPEAR
>   tristate "STMicroelectronics SPEAr PWM support"
>   depends on PLAT_SPEAR
> diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
> index 9c676a0d..30089ca6 100644
> --- a/drivers/pwm/Makefile
> +++ b/drivers/pwm/Makefile
> @@ -37,6 +37,7 @@ obj-$(CONFIG_PWM_RCAR)  += pwm-rcar.o
>  obj-$(CONFIG_PWM_RENESAS_TPU)+= pwm-renesas-tpu.o
>  obj-$(CONFIG_PWM_ROCKCHIP)   += pwm-rockchip.o
>  obj-$(CONFIG_PWM_SAMSUNG)+= pwm-samsung.o
> +obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o
>  obj-$(CONFIG_PWM_SPEAR)  += pwm-spear.o
>  obj-$(CONFIG_PWM_STI)+= pwm-sti.o
>  obj-$(CONFIG_PWM_STM32)  += pwm-stm32.o
> diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c
> new file mode 100644
> index ..99580025
> --- /dev/null
> +++ b/drivers/pwm/pwm-sifive.c
> @@ -0,0 +1,240 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2017 SiFive
> + */
> +#include 

What do you need this for? Your driver should only be dealing with enum
pwm_polarity, not the defines from the above header. This works but only
because PWM_POLARITY_INVERTED and PWM_POLARITY_INVERSED happen to be the
same value.

> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 

Keep these in alphabetical order, please.

> +
> +#define MAX_PWM  4
> +
> +/* Register offsets */
> +#define REG_PWMCFG   0x0
> +#define REG_PWMCOUNT 0x8
> +#define REG_PWMS 0x10
> +#define  REG_PWMCMP0 0x20
> +
> +/* PWMCFG fields */
> +#define BIT_PWM_SCALE0
> +#define BIT_PWM_STICKY   8
> +#define BIT_PWM_ZERO_ZMP 9
> +#define BIT_PWM_DEGLITCH 10
> +#define BIT_PWM_EN_ALWAYS12
> +#define BIT_PWM_EN_ONCE  13
> +#define BIT_PWM0_CENTER  16
> +#define BIT_PWM0_GANG24
> +#define BIT_PWM0_IP  28
> +
> +#define SIZE_PWMCMP  4
> +#define MASK_PWM_SCALE   0xf
> +
> +struct sifive_pwm_device {
> + struct pwm_chip chip;
> + struct notifier_block   notifier;
> + struct clk  *clk;
> + void __iomem*regs;
> + unsigned intapprox_period;
> + unsigned intreal_period;
> +};

No need to align these. A single space is enough to separate variable
type and name.

> +
> +static inline struct sifive_pwm_device *to_sifive_pwm_chip(struct pwm_chip 
> *c)
> +{
> + return container_of(c, struct sifive_pwm_device, chip);
> +}
> +
> +static int sifive_pwm_apply(struct pwm_chip *chip, struct pwm_device *dev,
> + struct pwm_state *state)
> +{
> + struct sifive_pwm_device *pwm = to_sifive_pwm_chip(chip);
> + unsigned int duty_cycle;
> + u32 frac;
> +
> + duty_cycle = state->duty_cycle;
> + if (!state->enabled)
> + duty_cycle = 0;
> + if (state->polarity == PWM_POLARITY_NORMAL)
> + duty_cycle = state->period - duty_cycle;

That's not actually polarity inversion. This is "lightweight" inversion
which should be up to the consumer, not the PWM driver, to implement. If
you don't actually have a knob in hardware to switch the polarity, don't
support it.

> +
> + frac = ((u64)duty_cycle << 16) / state->period;
> + frac = min(frac, 0xU);
> +
> + iowrite32(frac, pwm->regs + REG_PWMCMP0 + (dev->hwpwm * SIZE_PWMCMP));

writel()?

> +
> + if (state->enabled) {
> + state->period = pwm->real_period;
> + state->duty_cycle = ((u64)frac * pwm->real_period) >> 16;
> + if (state->polarity == PWM_POLARITY_NORMAL)
> + state->duty_cycle = state->period - state->duty_cycle;
> + }
> +
> + return 0;
> +}
> +
> +static void sifive_pwm_get_state(struct pwm_chip *chip, struct 

Re: [RFC 2/4] pwm: sifive: Add a driver for SiFive SoC PWM

2018-10-10 Thread Thierry Reding
On Wed, Oct 10, 2018 at 06:11:29AM -0700, Christoph Hellwig wrote:
[...]
> > +static struct platform_driver sifive_pwm_driver = {
> > +   .probe = sifive_pwm_probe,
> > +   .remove = sifive_pwm_remove,
> > +   .driver = {
> > +   .name = "pwm-sifivem",
> > +   .of_match_table = of_match_ptr(sifive_pwm_of_match),
> > +   },
> > +};
> 
> What about using tabs to align this a little more nicely?
> 
> static struct platform_driver sifive_pwm_driver = {
>   .probe  = sifive_pwm_probe,
>   .remove = sifive_pwm_remove,
>   .driver = {
>   .name   = "pwm-sifivem",
>   .of_match_table = of_match_ptr(sifive_pwm_of_match),
>   },
> };

I discourage people from doing that because down the road somebody might
add a field here that's longer than the alignment tabs and then either
it becomes ugly or they either have to realign everything to keep it
pretty. Single spaces around '=' don't have that problem if used
consistently.

Thierry


signature.asc
Description: PGP signature


Re: [RFC 2/4] pwm: sifive: Add a driver for SiFive SoC PWM

2018-10-10 Thread Thierry Reding
On Wed, Oct 10, 2018 at 06:11:29AM -0700, Christoph Hellwig wrote:
[...]
> > +static struct platform_driver sifive_pwm_driver = {
> > +   .probe = sifive_pwm_probe,
> > +   .remove = sifive_pwm_remove,
> > +   .driver = {
> > +   .name = "pwm-sifivem",
> > +   .of_match_table = of_match_ptr(sifive_pwm_of_match),
> > +   },
> > +};
> 
> What about using tabs to align this a little more nicely?
> 
> static struct platform_driver sifive_pwm_driver = {
>   .probe  = sifive_pwm_probe,
>   .remove = sifive_pwm_remove,
>   .driver = {
>   .name   = "pwm-sifivem",
>   .of_match_table = of_match_ptr(sifive_pwm_of_match),
>   },
> };

I discourage people from doing that because down the road somebody might
add a field here that's longer than the alignment tabs and then either
it becomes ugly or they either have to realign everything to keep it
pretty. Single spaces around '=' don't have that problem if used
consistently.

Thierry


signature.asc
Description: PGP signature


Re: [RFC 2/4] pwm: sifive: Add a driver for SiFive SoC PWM

2018-10-10 Thread Christoph Hellwig
Thanks for getting these drivers submitted upstream!

I don't really know anything about PWM, so just some random nitpicking
below..

> + iowrite32(frac, pwm->regs + REG_PWMCMP0 + (dev->hwpwm * SIZE_PWMCMP));

* already has a higher precedence than +, so no need for the inner
braces.

> + duty = ioread32(pwm->regs + REG_PWMCMP0 + (dev->hwpwm * SIZE_PWMCMP));

Same here.

> + /* (1 << (16+scale)) * 10^9/rate = real_period */
unsigned long scalePow = (pwm->approx_period * (u64)rate) / 10;

no camcel case, please.

> + int scale = ilog2(scalePow) - 16;
> +
> + scale = clamp(scale, 0, 0xf);

Why not:

int scale = clamp(ilog2(scale_pow) - 16, 0, 0xf);

> +static int sifive_pwm_clock_notifier(struct notifier_block *nb,
> +  unsigned long event, void *data)
> +{
> + struct clk_notifier_data *ndata = data;
> + struct sifive_pwm_device *pwm = container_of(nb,
> +  struct sifive_pwm_device,
> +  notifier);

I don't think there are any guidlines, but I always prefer to just move
the whole container_of onto a new line:

struct sifive_pwm_device *pwm =
container_of(nb, struct sifive_pwm_device, notifier);

> +static struct platform_driver sifive_pwm_driver = {
> + .probe = sifive_pwm_probe,
> + .remove = sifive_pwm_remove,
> + .driver = {
> + .name = "pwm-sifivem",
> + .of_match_table = of_match_ptr(sifive_pwm_of_match),
> + },
> +};

What about using tabs to align this a little more nicely?

static struct platform_driver sifive_pwm_driver = {
.probe  = sifive_pwm_probe,
.remove = sifive_pwm_remove,
.driver = {
.name   = "pwm-sifivem",
.of_match_table = of_match_ptr(sifive_pwm_of_match),
},
};


Re: [RFC 2/4] pwm: sifive: Add a driver for SiFive SoC PWM

2018-10-10 Thread Christoph Hellwig
Thanks for getting these drivers submitted upstream!

I don't really know anything about PWM, so just some random nitpicking
below..

> + iowrite32(frac, pwm->regs + REG_PWMCMP0 + (dev->hwpwm * SIZE_PWMCMP));

* already has a higher precedence than +, so no need for the inner
braces.

> + duty = ioread32(pwm->regs + REG_PWMCMP0 + (dev->hwpwm * SIZE_PWMCMP));

Same here.

> + /* (1 << (16+scale)) * 10^9/rate = real_period */
unsigned long scalePow = (pwm->approx_period * (u64)rate) / 10;

no camcel case, please.

> + int scale = ilog2(scalePow) - 16;
> +
> + scale = clamp(scale, 0, 0xf);

Why not:

int scale = clamp(ilog2(scale_pow) - 16, 0, 0xf);

> +static int sifive_pwm_clock_notifier(struct notifier_block *nb,
> +  unsigned long event, void *data)
> +{
> + struct clk_notifier_data *ndata = data;
> + struct sifive_pwm_device *pwm = container_of(nb,
> +  struct sifive_pwm_device,
> +  notifier);

I don't think there are any guidlines, but I always prefer to just move
the whole container_of onto a new line:

struct sifive_pwm_device *pwm =
container_of(nb, struct sifive_pwm_device, notifier);

> +static struct platform_driver sifive_pwm_driver = {
> + .probe = sifive_pwm_probe,
> + .remove = sifive_pwm_remove,
> + .driver = {
> + .name = "pwm-sifivem",
> + .of_match_table = of_match_ptr(sifive_pwm_of_match),
> + },
> +};

What about using tabs to align this a little more nicely?

static struct platform_driver sifive_pwm_driver = {
.probe  = sifive_pwm_probe,
.remove = sifive_pwm_remove,
.driver = {
.name   = "pwm-sifivem",
.of_match_table = of_match_ptr(sifive_pwm_of_match),
},
};


[RFC 2/4] pwm: sifive: Add a driver for SiFive SoC PWM

2018-10-09 Thread Atish Patra
From: "Wesley W. Terpstra" 

Adds a PWM driver for PWM chip present in SiFive's HiFive Unleashed SoC.

Signed-off-by: Wesley W. Terpstra 
[Atish: Various fixes and code cleanup]
Signed-off-by: Atish Patra 
---
 drivers/pwm/Kconfig  |  10 ++
 drivers/pwm/Makefile |   1 +
 drivers/pwm/pwm-sifive.c | 240 +++
 3 files changed, 251 insertions(+)
 create mode 100644 drivers/pwm/pwm-sifive.c

diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 504d2527..dd12144d 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -378,6 +378,16 @@ config PWM_SAMSUNG
  To compile this driver as a module, choose M here: the module
  will be called pwm-samsung.
 
+config PWM_SIFIVE
+   tristate "SiFive PWM support"
+   depends on OF
+   depends on COMMON_CLK
+   help
+ Generic PWM framework driver for SiFive SoCs.
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-sifive.
+
 config PWM_SPEAR
tristate "STMicroelectronics SPEAr PWM support"
depends on PLAT_SPEAR
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 9c676a0d..30089ca6 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_PWM_RCAR)+= pwm-rcar.o
 obj-$(CONFIG_PWM_RENESAS_TPU)  += pwm-renesas-tpu.o
 obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o
 obj-$(CONFIG_PWM_SAMSUNG)  += pwm-samsung.o
+obj-$(CONFIG_PWM_SIFIVE)   += pwm-sifive.o
 obj-$(CONFIG_PWM_SPEAR)+= pwm-spear.o
 obj-$(CONFIG_PWM_STI)  += pwm-sti.o
 obj-$(CONFIG_PWM_STM32)+= pwm-stm32.o
diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c
new file mode 100644
index ..99580025
--- /dev/null
+++ b/drivers/pwm/pwm-sifive.c
@@ -0,0 +1,240 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 SiFive
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define MAX_PWM4
+
+/* Register offsets */
+#define REG_PWMCFG 0x0
+#define REG_PWMCOUNT   0x8
+#define REG_PWMS   0x10
+#defineREG_PWMCMP0 0x20
+
+/* PWMCFG fields */
+#define BIT_PWM_SCALE  0
+#define BIT_PWM_STICKY 8
+#define BIT_PWM_ZERO_ZMP   9
+#define BIT_PWM_DEGLITCH   10
+#define BIT_PWM_EN_ALWAYS  12
+#define BIT_PWM_EN_ONCE13
+#define BIT_PWM0_CENTER16
+#define BIT_PWM0_GANG  24
+#define BIT_PWM0_IP28
+
+#define SIZE_PWMCMP4
+#define MASK_PWM_SCALE 0xf
+
+struct sifive_pwm_device {
+   struct pwm_chip chip;
+   struct notifier_block   notifier;
+   struct clk  *clk;
+   void __iomem*regs;
+   unsigned intapprox_period;
+   unsigned intreal_period;
+};
+
+static inline struct sifive_pwm_device *to_sifive_pwm_chip(struct pwm_chip *c)
+{
+   return container_of(c, struct sifive_pwm_device, chip);
+}
+
+static int sifive_pwm_apply(struct pwm_chip *chip, struct pwm_device *dev,
+   struct pwm_state *state)
+{
+   struct sifive_pwm_device *pwm = to_sifive_pwm_chip(chip);
+   unsigned int duty_cycle;
+   u32 frac;
+
+   duty_cycle = state->duty_cycle;
+   if (!state->enabled)
+   duty_cycle = 0;
+   if (state->polarity == PWM_POLARITY_NORMAL)
+   duty_cycle = state->period - duty_cycle;
+
+   frac = ((u64)duty_cycle << 16) / state->period;
+   frac = min(frac, 0xU);
+
+   iowrite32(frac, pwm->regs + REG_PWMCMP0 + (dev->hwpwm * SIZE_PWMCMP));
+
+   if (state->enabled) {
+   state->period = pwm->real_period;
+   state->duty_cycle = ((u64)frac * pwm->real_period) >> 16;
+   if (state->polarity == PWM_POLARITY_NORMAL)
+   state->duty_cycle = state->period - state->duty_cycle;
+   }
+
+   return 0;
+}
+
+static void sifive_pwm_get_state(struct pwm_chip *chip, struct pwm_device *dev,
+struct pwm_state *state)
+{
+   struct sifive_pwm_device *pwm = to_sifive_pwm_chip(chip);
+   unsigned long duty;
+
+   duty = ioread32(pwm->regs + REG_PWMCMP0 + (dev->hwpwm * SIZE_PWMCMP));
+
+   state->period = pwm->real_period;
+   state->duty_cycle = ((u64)duty * pwm->real_period) >> 16;
+   state->polarity   = PWM_POLARITY_INVERSED;
+   state->enabled= duty > 0;
+}
+
+static const struct pwm_ops sifive_pwm_ops = {
+   .get_state  = sifive_pwm_get_state,
+   .apply  = sifive_pwm_apply,
+   .owner  = THIS_MODULE,
+};
+
+static struct pwm_device *sifive_pwm_xlate(struct pwm_chip *chip,
+  const struct of_phandle_args *args)
+{
+   struct sifive_pwm_device *pwm = to_sifive_pwm_chip(chip);
+  

[RFC 2/4] pwm: sifive: Add a driver for SiFive SoC PWM

2018-10-09 Thread Atish Patra
From: "Wesley W. Terpstra" 

Adds a PWM driver for PWM chip present in SiFive's HiFive Unleashed SoC.

Signed-off-by: Wesley W. Terpstra 
[Atish: Various fixes and code cleanup]
Signed-off-by: Atish Patra 
---
 drivers/pwm/Kconfig  |  10 ++
 drivers/pwm/Makefile |   1 +
 drivers/pwm/pwm-sifive.c | 240 +++
 3 files changed, 251 insertions(+)
 create mode 100644 drivers/pwm/pwm-sifive.c

diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 504d2527..dd12144d 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -378,6 +378,16 @@ config PWM_SAMSUNG
  To compile this driver as a module, choose M here: the module
  will be called pwm-samsung.
 
+config PWM_SIFIVE
+   tristate "SiFive PWM support"
+   depends on OF
+   depends on COMMON_CLK
+   help
+ Generic PWM framework driver for SiFive SoCs.
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-sifive.
+
 config PWM_SPEAR
tristate "STMicroelectronics SPEAr PWM support"
depends on PLAT_SPEAR
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 9c676a0d..30089ca6 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_PWM_RCAR)+= pwm-rcar.o
 obj-$(CONFIG_PWM_RENESAS_TPU)  += pwm-renesas-tpu.o
 obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o
 obj-$(CONFIG_PWM_SAMSUNG)  += pwm-samsung.o
+obj-$(CONFIG_PWM_SIFIVE)   += pwm-sifive.o
 obj-$(CONFIG_PWM_SPEAR)+= pwm-spear.o
 obj-$(CONFIG_PWM_STI)  += pwm-sti.o
 obj-$(CONFIG_PWM_STM32)+= pwm-stm32.o
diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c
new file mode 100644
index ..99580025
--- /dev/null
+++ b/drivers/pwm/pwm-sifive.c
@@ -0,0 +1,240 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 SiFive
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define MAX_PWM4
+
+/* Register offsets */
+#define REG_PWMCFG 0x0
+#define REG_PWMCOUNT   0x8
+#define REG_PWMS   0x10
+#defineREG_PWMCMP0 0x20
+
+/* PWMCFG fields */
+#define BIT_PWM_SCALE  0
+#define BIT_PWM_STICKY 8
+#define BIT_PWM_ZERO_ZMP   9
+#define BIT_PWM_DEGLITCH   10
+#define BIT_PWM_EN_ALWAYS  12
+#define BIT_PWM_EN_ONCE13
+#define BIT_PWM0_CENTER16
+#define BIT_PWM0_GANG  24
+#define BIT_PWM0_IP28
+
+#define SIZE_PWMCMP4
+#define MASK_PWM_SCALE 0xf
+
+struct sifive_pwm_device {
+   struct pwm_chip chip;
+   struct notifier_block   notifier;
+   struct clk  *clk;
+   void __iomem*regs;
+   unsigned intapprox_period;
+   unsigned intreal_period;
+};
+
+static inline struct sifive_pwm_device *to_sifive_pwm_chip(struct pwm_chip *c)
+{
+   return container_of(c, struct sifive_pwm_device, chip);
+}
+
+static int sifive_pwm_apply(struct pwm_chip *chip, struct pwm_device *dev,
+   struct pwm_state *state)
+{
+   struct sifive_pwm_device *pwm = to_sifive_pwm_chip(chip);
+   unsigned int duty_cycle;
+   u32 frac;
+
+   duty_cycle = state->duty_cycle;
+   if (!state->enabled)
+   duty_cycle = 0;
+   if (state->polarity == PWM_POLARITY_NORMAL)
+   duty_cycle = state->period - duty_cycle;
+
+   frac = ((u64)duty_cycle << 16) / state->period;
+   frac = min(frac, 0xU);
+
+   iowrite32(frac, pwm->regs + REG_PWMCMP0 + (dev->hwpwm * SIZE_PWMCMP));
+
+   if (state->enabled) {
+   state->period = pwm->real_period;
+   state->duty_cycle = ((u64)frac * pwm->real_period) >> 16;
+   if (state->polarity == PWM_POLARITY_NORMAL)
+   state->duty_cycle = state->period - state->duty_cycle;
+   }
+
+   return 0;
+}
+
+static void sifive_pwm_get_state(struct pwm_chip *chip, struct pwm_device *dev,
+struct pwm_state *state)
+{
+   struct sifive_pwm_device *pwm = to_sifive_pwm_chip(chip);
+   unsigned long duty;
+
+   duty = ioread32(pwm->regs + REG_PWMCMP0 + (dev->hwpwm * SIZE_PWMCMP));
+
+   state->period = pwm->real_period;
+   state->duty_cycle = ((u64)duty * pwm->real_period) >> 16;
+   state->polarity   = PWM_POLARITY_INVERSED;
+   state->enabled= duty > 0;
+}
+
+static const struct pwm_ops sifive_pwm_ops = {
+   .get_state  = sifive_pwm_get_state,
+   .apply  = sifive_pwm_apply,
+   .owner  = THIS_MODULE,
+};
+
+static struct pwm_device *sifive_pwm_xlate(struct pwm_chip *chip,
+  const struct of_phandle_args *args)
+{
+   struct sifive_pwm_device *pwm = to_sifive_pwm_chip(chip);
+