Re: [PATCH v2 5/7] counter: add FlexTimer Module Quadrature decoder counter driver

2019-03-11 Thread Jonathan Cameron
On Wed, 6 Mar 2019 12:12:06 +0100
Patrick Havelange  wrote:

> This driver exposes the counter for the quadrature decoder of the
> FlexTimer Module, present in the LS1021A soc.
> 
> Signed-off-by: Patrick Havelange 
A few really trivial bits inline to add to William's feedback.

Otherwise I'm happy enough,

Reviewed-by: Jonathan Cameron 

> ---
> Changes v2
>  - Rebased on new counter subsystem
>  - Cleaned up included headers
>  - Use devm_ioremap()
>  - Correct order of devm_ and unmanaged resources
> ---
>  drivers/counter/Kconfig   |   9 +
>  drivers/counter/Makefile  |   1 +
>  drivers/counter/ftm-quaddec.c | 356 ++
>  3 files changed, 366 insertions(+)
>  create mode 100644 drivers/counter/ftm-quaddec.c
> 
> diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig
> index 87c491a19c63..233ac305d878 100644
> --- a/drivers/counter/Kconfig
> +++ b/drivers/counter/Kconfig
> @@ -48,4 +48,13 @@ config STM32_LPTIMER_CNT
> To compile this driver as a module, choose M here: the
> module will be called stm32-lptimer-cnt.
>  
> +config FTM_QUADDEC
> + tristate "Flex Timer Module Quadrature decoder driver"
> + help
> +   Select this option to enable the Flex Timer Quadrature decoder
> +   driver.
> +
> +   To compile this driver as a module, choose M here: the
> +   module will be called ftm-quaddec.
> +
>  endif # COUNTER
> diff --git a/drivers/counter/Makefile b/drivers/counter/Makefile
> index 5589976d37f8..0c9e622a6bea 100644
> --- a/drivers/counter/Makefile
> +++ b/drivers/counter/Makefile
> @@ -7,3 +7,4 @@ obj-$(CONFIG_COUNTER) += counter.o
>  obj-$(CONFIG_104_QUAD_8) += 104-quad-8.o
>  obj-$(CONFIG_STM32_TIMER_CNT)+= stm32-timer-cnt.o
>  obj-$(CONFIG_STM32_LPTIMER_CNT)  += stm32-lptimer-cnt.o
> +obj-$(CONFIG_FTM_QUADDEC)+= ftm-quaddec.o
> diff --git a/drivers/counter/ftm-quaddec.c b/drivers/counter/ftm-quaddec.c
> new file mode 100644
> index ..1bc9e075a386
> --- /dev/null
> +++ b/drivers/counter/ftm-quaddec.c
> @@ -0,0 +1,356 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Flex Timer Module Quadrature decoder
> + *
> + * This module implements a driver for decoding the FTM quadrature
> + * of ex. a LS1021A
> + */
> +
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +struct ftm_quaddec {
> + struct counter_device counter;
> + struct platform_device *pdev;
> + void __iomem *ftm_base;
> + bool big_endian;
> + struct mutex ftm_quaddec_mutex;
> +};
> +
> +static void ftm_read(struct ftm_quaddec *ftm, uint32_t offset, uint32_t 
> *data)
> +{
> + if (ftm->big_endian)
> + *data = ioread32be(ftm->ftm_base + offset);
> + else
> + *data = ioread32(ftm->ftm_base + offset);
> +}
> +
> +static void ftm_write(struct ftm_quaddec *ftm, uint32_t offset, uint32_t 
> data)
> +{
> + if (ftm->big_endian)
> + iowrite32be(data, ftm->ftm_base + offset);
> + else
> + iowrite32(data, ftm->ftm_base + offset);
> +}
> +
> +/*
> + * take mutex
> + * call ftm_clear_write_protection
> + * update settings
> + * call ftm_set_write_protection
> + * release mutex
> + */
> +static void ftm_clear_write_protection(struct ftm_quaddec *ftm)
> +{
> + uint32_t flag;
> +
> + /* First see if it is enabled */
> + ftm_read(ftm, FTM_FMS, );
> +
> + if (flag & FTM_FMS_WPEN) {
> + ftm_read(ftm, FTM_MODE, );
> + ftm_write(ftm, FTM_MODE, flag | FTM_MODE_WPDIS);
> + }
> +}
> +
> +static void ftm_set_write_protection(struct ftm_quaddec *ftm)
> +{
> + ftm_write(ftm, FTM_FMS, FTM_FMS_WPEN);
> +}
> +
> +static void ftm_reset_counter(struct ftm_quaddec *ftm)
> +{
> + /* Reset hardware counter to CNTIN */
> + ftm_write(ftm, FTM_CNT, 0x0);
> +}
> +
> +static void ftm_quaddec_init(struct ftm_quaddec *ftm)
> +{
> + ftm_clear_write_protection(ftm);
> +
> + /*
> +  * Do not write in the region from the CNTIN register through the
> +  * PWMLOAD register when FTMEN = 0.
> +  */
> + ftm_write(ftm, FTM_MODE, FTM_MODE_FTMEN);
> + ftm_write(ftm, FTM_CNTIN, 0x);
> + ftm_write(ftm, FTM_MOD, 0x);
> + ftm_write(ftm, FTM_CNT, 0x0);
> + ftm_write(ftm, FTM_SC, FTM_SC_PS_1);
> +
> + /* Select quad mode */
> + ftm_write(ftm, FTM_QDCTRL, FTM_QDCTRL_QUADEN);
> +
> + /* Unused features and reset to default section */
> + ftm_write(ftm, FTM_POL, 0x0);
> + ftm_write(ftm, FTM_FLTCTRL, 0x0);
> + ftm_write(ftm, FTM_SYNCONF, 0x0);
> + ftm_write(ftm, FTM_SYNC, 0x);
> +
> + /* Lock the FTM */
> + ftm_set_write_protection(ftm);
> +}
> +
> +static void ftm_quaddec_disable(struct ftm_quaddec *ftm)
> +{
> + ftm_write(ftm, FTM_MODE, 0);
> +}
> +
> +static int ftm_quaddec_get_prescaler(struct counter_device *counter,
> +  struct counter_count *count,
> +  

Re: [PATCH v2 5/7] counter: add FlexTimer Module Quadrature decoder counter driver

2019-03-11 Thread Patrick Havelange
On Thu, Mar 7, 2019 at 12:32 PM William Breathitt Gray
 wrote:
> > +/*
> > + * take mutex
> > + * call ftm_clear_write_protection
> > + * update settings
> > + * call ftm_set_write_protection
> > + * release mutex
> > + */
>
> Jonathan mentioned it before in the previous review, and I think I agree
> too, that this comment block is superfluous: the context of this code is
> simple enough that the function call order is naturally obvious (i.e.
> write protection must be cleared before settings are modified).
>
> The only important thing to mention here is that the mutex must be held
> before the write protection state is modified so a comment along the
> following lines should suffice:
>
> /* hold mutex before modifying write protection state */

I think that keeping the more verbose comments is better. You directly see
what operations are needed, and is a good reminder, especially if you
are not familiar with the driver.
I'll use your comment on the next version if you insist (see below for
why new versoion).

> > +static void ftm_quaddec_disable(struct ftm_quaddec *ftm)
> > +{
> > + ftm_write(ftm, FTM_MODE, 0);
> > +}
>
> The ftm_quaddec_disable function is only used for cleanup when the
> driver is being removed. Is disabling the FTM counter on removal
> actually something we need to do?

It might provide some power-saving, so I would keep that function.

>
> While it's true that the register will keep updating, since the driver
> is no longer loaded, we don't care about that register value. Once we
> take control of the hardware again (by reloading our driver or via a new
> one), we reinitialize the counter and set the count value back to 0
> anyway -- so whatever value the register had no longer matters.
>
Indeed the previous values at start do not matter. It's there just to
shut down the device properly.
This discussion made me verify again the specs and in its current form
the disable doesn't even work at all :
 - That register should be written with write protection disabled (duh!)
 - It doesn't even stop the FTM from running, the clock must be
disabled for that.

So I'll probably provide a fix for that (in some days/weeks).

> > +
> > +enum ftm_quaddec_count_function {
> > + FTM_QUADDEC_COUNT_ENCODER_MODE_1,
> > +};
>
> The FlexTimer Module supports more than just a quadrature counter mode
> doesn't it?
>
> We should keep this initial patch simple since we are still introducing
> the Counter subsystem, but it'll be nice to add support in the future
> for the other counter modes such as single-edge capture.

yes it provides more features, those are in a backlog ;). I would
prefer if this simple version(I mean, with the disable/shutdown fixed)
of the driver could be merged already before extending support.

>
> > +
> > +static struct counter_signal ftm_quaddec_signals[] = {
> > + {
> > + .id = 0,
> > + .name = "Channel 1 Quadrature A"
> > + },
> > + {
> > + .id = 1,
> > + .name = "Channel 1 Quadrature B"
> > + }
> > +};
>
> If possible, these names should match the FTM datasheet naming
> convention. The reason is to make it easier for users to match the
> input signals described in the datasheet with the Signal data provided
> by the Generic Counter interface.
>
> I think the FTM datasheet describes these signals as "Phase A" and
> "Phase B", so perhaps "Channel 1 Phase A" and "Channel 1 Phase B" may be
> more appropriate names in this case.

I'll verify those,

> > +static int ftm_quaddec_remove(struct platform_device *pdev)
> > +{
> > + struct ftm_quaddec *ftm = platform_get_drvdata(pdev);
> > +
> > + counter_unregister(>counter);
> > +
> > + ftm_quaddec_disable(ftm);
> > +
> > + return 0;
> > +}
>
> If the ftm_quaddec_disable is not necessary, then we can eliminate the
> ftm_quaddec_remove function as well by replacing the counter_register
> call with a devm_counter_register call.

yes, but as stated before, I would keep it for potential energy saving.

Thanks for your feedback :)


Re: [PATCH v2 5/7] counter: add FlexTimer Module Quadrature decoder counter driver

2019-03-07 Thread William Breathitt Gray
On Wed, Mar 06, 2019 at 12:12:06PM +0100, Patrick Havelange wrote:
> This driver exposes the counter for the quadrature decoder of the
> FlexTimer Module, present in the LS1021A soc.
> 
> Signed-off-by: Patrick Havelange 
> ---
> Changes v2
>  - Rebased on new counter subsystem
>  - Cleaned up included headers
>  - Use devm_ioremap()
>  - Correct order of devm_ and unmanaged resources
> ---
>  drivers/counter/Kconfig   |   9 +
>  drivers/counter/Makefile  |   1 +
>  drivers/counter/ftm-quaddec.c | 356 ++
>  3 files changed, 366 insertions(+)
>  create mode 100644 drivers/counter/ftm-quaddec.c

Overall, I think you utilized the Generic Counter interface correctly.
So good job on the conversion from your initial patch. :-)

Some minor inline suggestions/comments follow.

> 
> diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig
> index 87c491a19c63..233ac305d878 100644
> --- a/drivers/counter/Kconfig
> +++ b/drivers/counter/Kconfig
> @@ -48,4 +48,13 @@ config STM32_LPTIMER_CNT
> To compile this driver as a module, choose M here: the
> module will be called stm32-lptimer-cnt.
>  
> +config FTM_QUADDEC
> + tristate "Flex Timer Module Quadrature decoder driver"
> + help
> +   Select this option to enable the Flex Timer Quadrature decoder
> +   driver.
> +
> +   To compile this driver as a module, choose M here: the
> +   module will be called ftm-quaddec.
> +
>  endif # COUNTER
> diff --git a/drivers/counter/Makefile b/drivers/counter/Makefile
> index 5589976d37f8..0c9e622a6bea 100644
> --- a/drivers/counter/Makefile
> +++ b/drivers/counter/Makefile
> @@ -7,3 +7,4 @@ obj-$(CONFIG_COUNTER) += counter.o
>  obj-$(CONFIG_104_QUAD_8) += 104-quad-8.o
>  obj-$(CONFIG_STM32_TIMER_CNT)+= stm32-timer-cnt.o
>  obj-$(CONFIG_STM32_LPTIMER_CNT)  += stm32-lptimer-cnt.o
> +obj-$(CONFIG_FTM_QUADDEC)+= ftm-quaddec.o
> diff --git a/drivers/counter/ftm-quaddec.c b/drivers/counter/ftm-quaddec.c
> new file mode 100644
> index ..1bc9e075a386
> --- /dev/null
> +++ b/drivers/counter/ftm-quaddec.c
> @@ -0,0 +1,356 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Flex Timer Module Quadrature decoder
> + *
> + * This module implements a driver for decoding the FTM quadrature
> + * of ex. a LS1021A
> + */
> +
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +struct ftm_quaddec {
> + struct counter_device counter;
> + struct platform_device *pdev;
> + void __iomem *ftm_base;
> + bool big_endian;
> + struct mutex ftm_quaddec_mutex;
> +};
> +
> +static void ftm_read(struct ftm_quaddec *ftm, uint32_t offset, uint32_t 
> *data)
> +{
> + if (ftm->big_endian)
> + *data = ioread32be(ftm->ftm_base + offset);
> + else
> + *data = ioread32(ftm->ftm_base + offset);
> +}
> +
> +static void ftm_write(struct ftm_quaddec *ftm, uint32_t offset, uint32_t 
> data)
> +{
> + if (ftm->big_endian)
> + iowrite32be(data, ftm->ftm_base + offset);
> + else
> + iowrite32(data, ftm->ftm_base + offset);
> +}
> +
> +/*
> + * take mutex
> + * call ftm_clear_write_protection
> + * update settings
> + * call ftm_set_write_protection
> + * release mutex
> + */

Jonathan mentioned it before in the previous review, and I think I agree
too, that this comment block is superfluous: the context of this code is
simple enough that the function call order is naturally obvious (i.e.
write protection must be cleared before settings are modified).

The only important thing to mention here is that the mutex must be held
before the write protection state is modified so a comment along the
following lines should suffice:

/* hold mutex before modifying write protection state */

> +static void ftm_clear_write_protection(struct ftm_quaddec *ftm)
> +{
> + uint32_t flag;
> +
> + /* First see if it is enabled */
> + ftm_read(ftm, FTM_FMS, );
> +
> + if (flag & FTM_FMS_WPEN) {
> + ftm_read(ftm, FTM_MODE, );
> + ftm_write(ftm, FTM_MODE, flag | FTM_MODE_WPDIS);
> + }
> +}
> +
> +static void ftm_set_write_protection(struct ftm_quaddec *ftm)
> +{
> + ftm_write(ftm, FTM_FMS, FTM_FMS_WPEN);
> +}
> +
> +static void ftm_reset_counter(struct ftm_quaddec *ftm)
> +{
> + /* Reset hardware counter to CNTIN */
> + ftm_write(ftm, FTM_CNT, 0x0);
> +}
> +
> +static void ftm_quaddec_init(struct ftm_quaddec *ftm)
> +{
> + ftm_clear_write_protection(ftm);
> +
> + /*
> +  * Do not write in the region from the CNTIN register through the
> +  * PWMLOAD register when FTMEN = 0.
> +  */
> + ftm_write(ftm, FTM_MODE, FTM_MODE_FTMEN);
> + ftm_write(ftm, FTM_CNTIN, 0x);
> + ftm_write(ftm, FTM_MOD, 0x);
> + ftm_write(ftm, FTM_CNT, 0x0);
> + ftm_write(ftm, FTM_SC, FTM_SC_PS_1);
> +
> + /* Select quad mode */
> + ftm_write(ftm, FTM_QDCTRL, FTM_QDCTRL_QUADEN);

[PATCH v2 5/7] counter: add FlexTimer Module Quadrature decoder counter driver

2019-03-06 Thread Patrick Havelange
This driver exposes the counter for the quadrature decoder of the
FlexTimer Module, present in the LS1021A soc.

Signed-off-by: Patrick Havelange 
---
Changes v2
 - Rebased on new counter subsystem
 - Cleaned up included headers
 - Use devm_ioremap()
 - Correct order of devm_ and unmanaged resources
---
 drivers/counter/Kconfig   |   9 +
 drivers/counter/Makefile  |   1 +
 drivers/counter/ftm-quaddec.c | 356 ++
 3 files changed, 366 insertions(+)
 create mode 100644 drivers/counter/ftm-quaddec.c

diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig
index 87c491a19c63..233ac305d878 100644
--- a/drivers/counter/Kconfig
+++ b/drivers/counter/Kconfig
@@ -48,4 +48,13 @@ config STM32_LPTIMER_CNT
  To compile this driver as a module, choose M here: the
  module will be called stm32-lptimer-cnt.
 
+config FTM_QUADDEC
+   tristate "Flex Timer Module Quadrature decoder driver"
+   help
+ Select this option to enable the Flex Timer Quadrature decoder
+ driver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ftm-quaddec.
+
 endif # COUNTER
diff --git a/drivers/counter/Makefile b/drivers/counter/Makefile
index 5589976d37f8..0c9e622a6bea 100644
--- a/drivers/counter/Makefile
+++ b/drivers/counter/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_COUNTER) += counter.o
 obj-$(CONFIG_104_QUAD_8)   += 104-quad-8.o
 obj-$(CONFIG_STM32_TIMER_CNT)  += stm32-timer-cnt.o
 obj-$(CONFIG_STM32_LPTIMER_CNT)+= stm32-lptimer-cnt.o
+obj-$(CONFIG_FTM_QUADDEC)  += ftm-quaddec.o
diff --git a/drivers/counter/ftm-quaddec.c b/drivers/counter/ftm-quaddec.c
new file mode 100644
index ..1bc9e075a386
--- /dev/null
+++ b/drivers/counter/ftm-quaddec.c
@@ -0,0 +1,356 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Flex Timer Module Quadrature decoder
+ *
+ * This module implements a driver for decoding the FTM quadrature
+ * of ex. a LS1021A
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+struct ftm_quaddec {
+   struct counter_device counter;
+   struct platform_device *pdev;
+   void __iomem *ftm_base;
+   bool big_endian;
+   struct mutex ftm_quaddec_mutex;
+};
+
+static void ftm_read(struct ftm_quaddec *ftm, uint32_t offset, uint32_t *data)
+{
+   if (ftm->big_endian)
+   *data = ioread32be(ftm->ftm_base + offset);
+   else
+   *data = ioread32(ftm->ftm_base + offset);
+}
+
+static void ftm_write(struct ftm_quaddec *ftm, uint32_t offset, uint32_t data)
+{
+   if (ftm->big_endian)
+   iowrite32be(data, ftm->ftm_base + offset);
+   else
+   iowrite32(data, ftm->ftm_base + offset);
+}
+
+/*
+ * take mutex
+ * call ftm_clear_write_protection
+ * update settings
+ * call ftm_set_write_protection
+ * release mutex
+ */
+static void ftm_clear_write_protection(struct ftm_quaddec *ftm)
+{
+   uint32_t flag;
+
+   /* First see if it is enabled */
+   ftm_read(ftm, FTM_FMS, );
+
+   if (flag & FTM_FMS_WPEN) {
+   ftm_read(ftm, FTM_MODE, );
+   ftm_write(ftm, FTM_MODE, flag | FTM_MODE_WPDIS);
+   }
+}
+
+static void ftm_set_write_protection(struct ftm_quaddec *ftm)
+{
+   ftm_write(ftm, FTM_FMS, FTM_FMS_WPEN);
+}
+
+static void ftm_reset_counter(struct ftm_quaddec *ftm)
+{
+   /* Reset hardware counter to CNTIN */
+   ftm_write(ftm, FTM_CNT, 0x0);
+}
+
+static void ftm_quaddec_init(struct ftm_quaddec *ftm)
+{
+   ftm_clear_write_protection(ftm);
+
+   /*
+* Do not write in the region from the CNTIN register through the
+* PWMLOAD register when FTMEN = 0.
+*/
+   ftm_write(ftm, FTM_MODE, FTM_MODE_FTMEN);
+   ftm_write(ftm, FTM_CNTIN, 0x);
+   ftm_write(ftm, FTM_MOD, 0x);
+   ftm_write(ftm, FTM_CNT, 0x0);
+   ftm_write(ftm, FTM_SC, FTM_SC_PS_1);
+
+   /* Select quad mode */
+   ftm_write(ftm, FTM_QDCTRL, FTM_QDCTRL_QUADEN);
+
+   /* Unused features and reset to default section */
+   ftm_write(ftm, FTM_POL, 0x0);
+   ftm_write(ftm, FTM_FLTCTRL, 0x0);
+   ftm_write(ftm, FTM_SYNCONF, 0x0);
+   ftm_write(ftm, FTM_SYNC, 0x);
+
+   /* Lock the FTM */
+   ftm_set_write_protection(ftm);
+}
+
+static void ftm_quaddec_disable(struct ftm_quaddec *ftm)
+{
+   ftm_write(ftm, FTM_MODE, 0);
+}
+
+static int ftm_quaddec_get_prescaler(struct counter_device *counter,
+struct counter_count *count,
+size_t *cnt_mode)
+{
+   struct ftm_quaddec *ftm = counter->priv;
+   uint32_t scflags;
+
+   ftm_read(ftm, FTM_SC, );
+
+   *cnt_mode = scflags & FTM_SC_PS_MASK;
+
+   return 0;
+}
+
+static int ftm_quaddec_set_prescaler(struct counter_device *counter,
+struct counter_count *count,
+