All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/7] Add pwm and IIO timer drivers for stm32
@ 2016-11-22 16:13 ` Benjamin Gaignard
  0 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-22 16:13 UTC (permalink / raw)
  To: lee.jones, robh+dt, mark.rutland, alexandre.torgue, devicetree,
	linux-kernel, thierry.reding, linux-pwm, jic23, knaack.h, lars,
	pmeerw, linux-iio, linux-arm-kernel
  Cc: fabrice.gasnier, gerald.baeza, arnaud.pouliquen, linus.walleij,
	linaro-kernel, Benjamin Gaignard

The following patches enable pwm and IIO Timer features for stm32 platforms.

Those two features are mixed into the registers of the same hardware block
(named timer) which lead to introduce a multifunctions driver on the top to
be able to share the registers.

In stm32 14 instances of timer hardware block exist, even if they all have
the same register mapping they could have a different number of pwm channels
and/or different triggers capabilities. To keep the code as simple as possible
we use compatible and platform_data to distinguish them.

The MFD (stm32-mfd-timer.c) takes care of clock, interrupt and register mapping
by using regmap. stm32_mfd_timer_dev structure is provided to its children to 
share those information.

PWM driver is implemented into pwm-stm32.c. Depending of the instance we may
have up to 4 channels, sometime with complementary outputs or 32 bits counter
instead of 16 bits. Some hardware blocks may also have a break input function
which allows to stop pwm depending of a level, defined in devicetree, on an
external pin.

IIO timer driver (stm32-iio-timer.c and stm32-iio-timers.h) define a list of 
hardware triggers usable by hardware blocks like ADC, DAC or other timers. 

The matrix of possible connections between blocks is quite complex so we use 
trigger names and is_stm32_iio_timer_trigger() function to be sure that
triggers are valid and configure the IPs.

Timer hardware blocks can configure (through "master_mode" IIO device attribute)
which internal signal (counter enable, reset, comparison block, etc...) is
used to generate the trigger.

By using "slave_mode" IIO device attribute timer can also configure on which
event (level, rising edge) of the block is enabled.

Since we can use trigger from one hardware to control an other block, we can
use a pwm to control an other one. The following example shows how to configure
pwm1 and pwm3 to make pwm3 generate pulse only when pwm1 pulse level is high.

/sys/bus/iio/devices # ls
iio:device0  iio:device1  trigger0     trigger1

configure timer1 to use pwm1 channel 0 as output trigger
/sys/bus/iio/devices # echo 4 > iio\:device0/master_mode
configure timer3 to enable only when input is high
/sys/bus/iio/devices # echo 5 > iio\:device1/slave_mode
/sys/bus/iio/devices # cat trigger0/name
tim1_trgo
configure timer2 to use timer1 trigger is input
/sys/bus/iio/devices # echo "tim1_trgo" > iio\:device1/trigger/current_trigger

configure pwm3 channel 0 to generate a signal with a period of 100ms and a
duty cycle of 50%
/sys/devices/platform/soc/40000400.mfdtimer3/pwm3/pwm/pwmchip4 # echo 0 > export
/sys/devices/platform/soc/40000400.mfdtimer3/pwm3/pwm/pwmchip4 # echo 100000000 > pwm0/period
/sys/devices/platform/soc/40000400.mfdtimer3/pwm3/pwm/pwmchip4 # echo 50000000 > pwm0/duty_cycle
/sys/devices/platform/soc/40000400.mfdtimer3/pwm3/pwm/pwmchip4 # echo 1 > pwm0/enable
here pwm3 channel 0, as expected, doesn't start because has to be triggered by
pwm1 channel 0

configure pwm1 channel 0 to generate a signal with a period of 1s and a
duty cycle of 50%
/sys/devices/platform/soc/40010000.mfdtimer1/pwm1/pwm/pwmchip0 # echo 0 > export
/sys/devices/platform/soc/40010000.mfdtimer1/pwm1/pwm/pwmchip0 # echo 1000000000 > pwm0/period
/sys/devices/platform/soc/40010000.mfdtimer1/pwm1/pwm/pwmchip0 # echo 500000000 > pwm0/duty_cycle
/sys/devices/platform/soc/40010000.mfdtimer1/pwm1/pwm/pwmchip0 # echo 1 > pwm0/enable 
finally pwm1 starts and pwm3 only generates pulse when pwm1 signal is high

An other example to use a timer as source of clock for another device.
Here timer1 is used a source clock for pwm3:

/sys/bus/iio/devices # echo 100000 > trigger0/sampling_frequency 
/sys/bus/iio/devices # echo tim1_trgo > iio\:device1/trigger/current_trigger 
/sys/bus/iio/devices # echo 7 > iio\:device1/slave_mode
/sys/devices/platform/soc/40000400.mfdtimer3/pwm3/pwm/pwmchip4 # echo 0 > export 
/sys/devices/platform/soc/40000400.mfdtimer3/pwm3/pwm/pwmchip4 # echo 1000000 > pwm0/period 
/sys/devices/platform/soc/40000400.mfdtimer3/pwm3/pwm/pwmchip4 # echo 500000 > pwm0/duty_cycle 
/sys/devices/platform/soc/40000400.mfdtimer3/pwm3/pwm/pwmchip4 # echo 1 > pwm0/enable 

Benjamin Gaignard (7):
  add binding for stm32 multifunctions timer driver
  add MFD for stm32 timer IP
  add pwm-stm32 DT bindings
  add pwm driver for stm32 plaftorm
  add bindings for stm32 IIO timer drivers
  add STM32 IIO timer driver
  add stm32 multi-functions timer driver in DT

 .../bindings/iio/timer/stm32-iio-timer.txt         |  33 +
 .../devicetree/bindings/mfd/stm32-timer.txt        |  53 ++
 .../devicetree/bindings/pwm/pwm-stm32.txt          |  43 ++
 arch/arm/boot/dts/stm32f429.dtsi                   | 246 +++++++
 arch/arm/boot/dts/stm32f469-disco.dts              |  29 +
 drivers/iio/Kconfig                                |   2 +-
 drivers/iio/Makefile                               |   1 +
 drivers/iio/timer/Kconfig                          |  15 +
 drivers/iio/timer/Makefile                         |   1 +
 drivers/iio/timer/stm32-iio-timer.c                | 766 +++++++++++++++++++++
 drivers/iio/trigger/Kconfig                        |   1 -
 drivers/mfd/Kconfig                                |  10 +
 drivers/mfd/Makefile                               |   2 +
 drivers/mfd/stm32-mfd-timer.c                      | 236 +++++++
 drivers/pwm/Kconfig                                |   8 +
 drivers/pwm/Makefile                               |   1 +
 drivers/pwm/pwm-stm32.c                            | 358 ++++++++++
 include/linux/iio/timer/stm32-iio-timers.h         |  25 +
 include/linux/mfd/stm32-mfd-timer.h                |  78 +++
 19 files changed, 1906 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt
 create mode 100644 Documentation/devicetree/bindings/mfd/stm32-timer.txt
 create mode 100644 Documentation/devicetree/bindings/pwm/pwm-stm32.txt
 create mode 100644 drivers/iio/timer/Kconfig
 create mode 100644 drivers/iio/timer/Makefile
 create mode 100644 drivers/iio/timer/stm32-iio-timer.c
 create mode 100644 drivers/mfd/stm32-mfd-timer.c
 create mode 100644 drivers/pwm/pwm-stm32.c
 create mode 100644 include/linux/iio/timer/stm32-iio-timers.h
 create mode 100644 include/linux/mfd/stm32-mfd-timer.h

-- 
1.9.1

^ permalink raw reply	[flat|nested] 64+ messages in thread

* [PATCH 0/7] Add pwm and IIO timer drivers for stm32
@ 2016-11-22 16:13 ` Benjamin Gaignard
  0 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-22 16:13 UTC (permalink / raw)
  To: linux-arm-kernel

The following patches enable pwm and IIO Timer features for stm32 platforms.

Those two features are mixed into the registers of the same hardware block
(named timer) which lead to introduce a multifunctions driver on the top to
be able to share the registers.

In stm32 14 instances of timer hardware block exist, even if they all have
the same register mapping they could have a different number of pwm channels
and/or different triggers capabilities. To keep the code as simple as possible
we use compatible and platform_data to distinguish them.

The MFD (stm32-mfd-timer.c) takes care of clock, interrupt and register mapping
by using regmap. stm32_mfd_timer_dev structure is provided to its children to 
share those information.

PWM driver is implemented into pwm-stm32.c. Depending of the instance we may
have up to 4 channels, sometime with complementary outputs or 32 bits counter
instead of 16 bits. Some hardware blocks may also have a break input function
which allows to stop pwm depending of a level, defined in devicetree, on an
external pin.

IIO timer driver (stm32-iio-timer.c and stm32-iio-timers.h) define a list of 
hardware triggers usable by hardware blocks like ADC, DAC or other timers. 

The matrix of possible connections between blocks is quite complex so we use 
trigger names and is_stm32_iio_timer_trigger() function to be sure that
triggers are valid and configure the IPs.

Timer hardware blocks can configure (through "master_mode" IIO device attribute)
which internal signal (counter enable, reset, comparison block, etc...) is
used to generate the trigger.

By using "slave_mode" IIO device attribute timer can also configure on which
event (level, rising edge) of the block is enabled.

Since we can use trigger from one hardware to control an other block, we can
use a pwm to control an other one. The following example shows how to configure
pwm1 and pwm3 to make pwm3 generate pulse only when pwm1 pulse level is high.

/sys/bus/iio/devices # ls
iio:device0  iio:device1  trigger0     trigger1

configure timer1 to use pwm1 channel 0 as output trigger
/sys/bus/iio/devices # echo 4 > iio\:device0/master_mode
configure timer3 to enable only when input is high
/sys/bus/iio/devices # echo 5 > iio\:device1/slave_mode
/sys/bus/iio/devices # cat trigger0/name
tim1_trgo
configure timer2 to use timer1 trigger is input
/sys/bus/iio/devices # echo "tim1_trgo" > iio\:device1/trigger/current_trigger

configure pwm3 channel 0 to generate a signal with a period of 100ms and a
duty cycle of 50%
/sys/devices/platform/soc/40000400.mfdtimer3/pwm3/pwm/pwmchip4 # echo 0 > export
/sys/devices/platform/soc/40000400.mfdtimer3/pwm3/pwm/pwmchip4 # echo 100000000 > pwm0/period
/sys/devices/platform/soc/40000400.mfdtimer3/pwm3/pwm/pwmchip4 # echo 50000000 > pwm0/duty_cycle
/sys/devices/platform/soc/40000400.mfdtimer3/pwm3/pwm/pwmchip4 # echo 1 > pwm0/enable
here pwm3 channel 0, as expected, doesn't start because has to be triggered by
pwm1 channel 0

configure pwm1 channel 0 to generate a signal with a period of 1s and a
duty cycle of 50%
/sys/devices/platform/soc/40010000.mfdtimer1/pwm1/pwm/pwmchip0 # echo 0 > export
/sys/devices/platform/soc/40010000.mfdtimer1/pwm1/pwm/pwmchip0 # echo 1000000000 > pwm0/period
/sys/devices/platform/soc/40010000.mfdtimer1/pwm1/pwm/pwmchip0 # echo 500000000 > pwm0/duty_cycle
/sys/devices/platform/soc/40010000.mfdtimer1/pwm1/pwm/pwmchip0 # echo 1 > pwm0/enable 
finally pwm1 starts and pwm3 only generates pulse when pwm1 signal is high

An other example to use a timer as source of clock for another device.
Here timer1 is used a source clock for pwm3:

/sys/bus/iio/devices # echo 100000 > trigger0/sampling_frequency 
/sys/bus/iio/devices # echo tim1_trgo > iio\:device1/trigger/current_trigger 
/sys/bus/iio/devices # echo 7 > iio\:device1/slave_mode
/sys/devices/platform/soc/40000400.mfdtimer3/pwm3/pwm/pwmchip4 # echo 0 > export 
/sys/devices/platform/soc/40000400.mfdtimer3/pwm3/pwm/pwmchip4 # echo 1000000 > pwm0/period 
/sys/devices/platform/soc/40000400.mfdtimer3/pwm3/pwm/pwmchip4 # echo 500000 > pwm0/duty_cycle 
/sys/devices/platform/soc/40000400.mfdtimer3/pwm3/pwm/pwmchip4 # echo 1 > pwm0/enable 

Benjamin Gaignard (7):
  add binding for stm32 multifunctions timer driver
  add MFD for stm32 timer IP
  add pwm-stm32 DT bindings
  add pwm driver for stm32 plaftorm
  add bindings for stm32 IIO timer drivers
  add STM32 IIO timer driver
  add stm32 multi-functions timer driver in DT

 .../bindings/iio/timer/stm32-iio-timer.txt         |  33 +
 .../devicetree/bindings/mfd/stm32-timer.txt        |  53 ++
 .../devicetree/bindings/pwm/pwm-stm32.txt          |  43 ++
 arch/arm/boot/dts/stm32f429.dtsi                   | 246 +++++++
 arch/arm/boot/dts/stm32f469-disco.dts              |  29 +
 drivers/iio/Kconfig                                |   2 +-
 drivers/iio/Makefile                               |   1 +
 drivers/iio/timer/Kconfig                          |  15 +
 drivers/iio/timer/Makefile                         |   1 +
 drivers/iio/timer/stm32-iio-timer.c                | 766 +++++++++++++++++++++
 drivers/iio/trigger/Kconfig                        |   1 -
 drivers/mfd/Kconfig                                |  10 +
 drivers/mfd/Makefile                               |   2 +
 drivers/mfd/stm32-mfd-timer.c                      | 236 +++++++
 drivers/pwm/Kconfig                                |   8 +
 drivers/pwm/Makefile                               |   1 +
 drivers/pwm/pwm-stm32.c                            | 358 ++++++++++
 include/linux/iio/timer/stm32-iio-timers.h         |  25 +
 include/linux/mfd/stm32-mfd-timer.h                |  78 +++
 19 files changed, 1906 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt
 create mode 100644 Documentation/devicetree/bindings/mfd/stm32-timer.txt
 create mode 100644 Documentation/devicetree/bindings/pwm/pwm-stm32.txt
 create mode 100644 drivers/iio/timer/Kconfig
 create mode 100644 drivers/iio/timer/Makefile
 create mode 100644 drivers/iio/timer/stm32-iio-timer.c
 create mode 100644 drivers/mfd/stm32-mfd-timer.c
 create mode 100644 drivers/pwm/pwm-stm32.c
 create mode 100644 include/linux/iio/timer/stm32-iio-timers.h
 create mode 100644 include/linux/mfd/stm32-mfd-timer.h

-- 
1.9.1

^ permalink raw reply	[flat|nested] 64+ messages in thread

* [PATCH 1/7] add binding for stm32 multifunctions timer driver
@ 2016-11-22 16:13   ` Benjamin Gaignard
  0 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-22 16:13 UTC (permalink / raw)
  To: lee.jones, robh+dt, mark.rutland, alexandre.torgue, devicetree,
	linux-kernel, thierry.reding, linux-pwm, jic23, knaack.h, lars,
	pmeerw, linux-iio, linux-arm-kernel
  Cc: fabrice.gasnier, gerald.baeza, arnaud.pouliquen, linus.walleij,
	linaro-kernel, Benjamin Gaignard

Add bindings information for stm32 timer MFD

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
---
 .../devicetree/bindings/mfd/stm32-timer.txt        | 53 ++++++++++++++++++++++
 1 file changed, 53 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/stm32-timer.txt

diff --git a/Documentation/devicetree/bindings/mfd/stm32-timer.txt b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
new file mode 100644
index 0000000..3cefce1
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
@@ -0,0 +1,53 @@
+STM32 multifunctions timer driver
+
+stm32 timer MFD allow to handle at the same time pwm and IIO timer devices
+
+Required parameters:
+- compatible: must be one of the follow value:
+	"st,stm32-mfd-timer1"
+	"st,stm32-mfd-timer2"
+	"st,stm32-mfd-timer3"
+	"st,stm32-mfd-timer4"
+	"st,stm32-mfd-timer5"
+	"st,stm32-mfd-timer6"
+	"st,stm32-mfd-timer7"
+	"st,stm32-mfd-timer8"
+	"st,stm32-mfd-timer9"
+	"st,stm32-mfd-timer10"
+	"st,stm32-mfd-timer11"
+	"st,stm32-mfd-timer12"
+	"st,stm32-mfd-timer13"
+	"st,stm32-mfd-timer14"
+
+- reg :			Physical base address and length of the controller's
+			registers.
+- clock-names: 		Set to "mfd_timer_clk".
+- clocks: 		Phandle of the clock used by the timer module.
+			For Clk properties, please refer to [1].
+- interrupts :		Reference to the timer interrupt
+
+Optional parameters:
+- resets :		Reference to a reset controller asserting the timer
+
+Optional subnodes:
+- pwm:			See Documentation/devicetree/bindings/pwm/pwm-stm32.txt
+- iiotimer:		See Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Example:
+	mfd_timer1: mfdtimer1@40010000 {
+		compatible = "st,stm32-mfd-timer1";
+		reg = <0x40010000 0x400>;
+		clocks = <&rcc 0 160>;
+		clock-names = "mfd_timer_clk";
+		interrupts = <27>;
+
+		pwm1: pwm1@40010000 {
+			compatible = "st,stm32-pwm1";
+		};
+
+		iiotimer1: iiotimer1@40010000 {
+			compatible = "st,stm32-iio-timer1";
+		};
+	};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 1/7] add binding for stm32 multifunctions timer driver
@ 2016-11-22 16:13   ` Benjamin Gaignard
  0 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-22 16:13 UTC (permalink / raw)
  To: lee.jones-QSEj5FYQhm4dnm+yROfE0A, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, alexandre.torgue-qxv4g6HH51o,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	linux-pwm-u79uwXL29TY76Z2rM5mHXA, jic23-DgEjT+Ai2ygdnm+yROfE0A,
	knaack.h-Mmb7MZpHnFY, lars-Qo5EllUWu/uELgA04lAiVw,
	pmeerw-jW+XmwGofnusTnJN9+BGXg, linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: fabrice.gasnier-qxv4g6HH51o, gerald.baeza-qxv4g6HH51o,
	arnaud.pouliquen-qxv4g6HH51o,
	linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
	linaro-kernel-cunTk1MwBs8s++Sfvej+rw, Benjamin Gaignard

Add bindings information for stm32 timer MFD

Signed-off-by: Benjamin Gaignard <benjamin.gaignard-qxv4g6HH51o@public.gmane.org>
---
 .../devicetree/bindings/mfd/stm32-timer.txt        | 53 ++++++++++++++++++++++
 1 file changed, 53 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/stm32-timer.txt

diff --git a/Documentation/devicetree/bindings/mfd/stm32-timer.txt b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
new file mode 100644
index 0000000..3cefce1
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
@@ -0,0 +1,53 @@
+STM32 multifunctions timer driver
+
+stm32 timer MFD allow to handle at the same time pwm and IIO timer devices
+
+Required parameters:
+- compatible: must be one of the follow value:
+	"st,stm32-mfd-timer1"
+	"st,stm32-mfd-timer2"
+	"st,stm32-mfd-timer3"
+	"st,stm32-mfd-timer4"
+	"st,stm32-mfd-timer5"
+	"st,stm32-mfd-timer6"
+	"st,stm32-mfd-timer7"
+	"st,stm32-mfd-timer8"
+	"st,stm32-mfd-timer9"
+	"st,stm32-mfd-timer10"
+	"st,stm32-mfd-timer11"
+	"st,stm32-mfd-timer12"
+	"st,stm32-mfd-timer13"
+	"st,stm32-mfd-timer14"
+
+- reg :			Physical base address and length of the controller's
+			registers.
+- clock-names: 		Set to "mfd_timer_clk".
+- clocks: 		Phandle of the clock used by the timer module.
+			For Clk properties, please refer to [1].
+- interrupts :		Reference to the timer interrupt
+
+Optional parameters:
+- resets :		Reference to a reset controller asserting the timer
+
+Optional subnodes:
+- pwm:			See Documentation/devicetree/bindings/pwm/pwm-stm32.txt
+- iiotimer:		See Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Example:
+	mfd_timer1: mfdtimer1@40010000 {
+		compatible = "st,stm32-mfd-timer1";
+		reg = <0x40010000 0x400>;
+		clocks = <&rcc 0 160>;
+		clock-names = "mfd_timer_clk";
+		interrupts = <27>;
+
+		pwm1: pwm1@40010000 {
+			compatible = "st,stm32-pwm1";
+		};
+
+		iiotimer1: iiotimer1@40010000 {
+			compatible = "st,stm32-iio-timer1";
+		};
+	};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 1/7] add binding for stm32 multifunctions timer driver
@ 2016-11-22 16:13   ` Benjamin Gaignard
  0 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-22 16:13 UTC (permalink / raw)
  To: linux-arm-kernel

Add bindings information for stm32 timer MFD

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
---
 .../devicetree/bindings/mfd/stm32-timer.txt        | 53 ++++++++++++++++++++++
 1 file changed, 53 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/stm32-timer.txt

diff --git a/Documentation/devicetree/bindings/mfd/stm32-timer.txt b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
new file mode 100644
index 0000000..3cefce1
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
@@ -0,0 +1,53 @@
+STM32 multifunctions timer driver
+
+stm32 timer MFD allow to handle at the same time pwm and IIO timer devices
+
+Required parameters:
+- compatible: must be one of the follow value:
+	"st,stm32-mfd-timer1"
+	"st,stm32-mfd-timer2"
+	"st,stm32-mfd-timer3"
+	"st,stm32-mfd-timer4"
+	"st,stm32-mfd-timer5"
+	"st,stm32-mfd-timer6"
+	"st,stm32-mfd-timer7"
+	"st,stm32-mfd-timer8"
+	"st,stm32-mfd-timer9"
+	"st,stm32-mfd-timer10"
+	"st,stm32-mfd-timer11"
+	"st,stm32-mfd-timer12"
+	"st,stm32-mfd-timer13"
+	"st,stm32-mfd-timer14"
+
+- reg :			Physical base address and length of the controller's
+			registers.
+- clock-names: 		Set to "mfd_timer_clk".
+- clocks: 		Phandle of the clock used by the timer module.
+			For Clk properties, please refer to [1].
+- interrupts :		Reference to the timer interrupt
+
+Optional parameters:
+- resets :		Reference to a reset controller asserting the timer
+
+Optional subnodes:
+- pwm:			See Documentation/devicetree/bindings/pwm/pwm-stm32.txt
+- iiotimer:		See Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Example:
+	mfd_timer1: mfdtimer1 at 40010000 {
+		compatible = "st,stm32-mfd-timer1";
+		reg = <0x40010000 0x400>;
+		clocks = <&rcc 0 160>;
+		clock-names = "mfd_timer_clk";
+		interrupts = <27>;
+
+		pwm1: pwm1 at 40010000 {
+			compatible = "st,stm32-pwm1";
+		};
+
+		iiotimer1: iiotimer1 at 40010000 {
+			compatible = "st,stm32-iio-timer1";
+		};
+	};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 2/7] add MFD for stm32 timer IP
@ 2016-11-22 16:13   ` Benjamin Gaignard
  0 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-22 16:13 UTC (permalink / raw)
  To: lee.jones, robh+dt, mark.rutland, alexandre.torgue, devicetree,
	linux-kernel, thierry.reding, linux-pwm, jic23, knaack.h, lars,
	pmeerw, linux-iio, linux-arm-kernel
  Cc: fabrice.gasnier, gerald.baeza, arnaud.pouliquen, linus.walleij,
	linaro-kernel, Benjamin Gaignard

This hardware block could at used at same time for PWM generation
and IIO timer for other IPs like DAC, ADC or other timers.
PWM and IIO timer configuration are mixed in the same registers
so we need a MFD to be able to share those registers.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
---
 drivers/mfd/Kconfig                 |  10 ++
 drivers/mfd/Makefile                |   2 +
 drivers/mfd/stm32-mfd-timer.c       | 236 ++++++++++++++++++++++++++++++++++++
 include/linux/mfd/stm32-mfd-timer.h |  78 ++++++++++++
 4 files changed, 326 insertions(+)
 create mode 100644 drivers/mfd/stm32-mfd-timer.c
 create mode 100644 include/linux/mfd/stm32-mfd-timer.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index c6df644..63aee36 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1607,6 +1607,15 @@ config MFD_STW481X
 	  in various ST Microelectronics and ST-Ericsson embedded
 	  Nomadik series.
 
+config MFD_STM32_TIMER
+	tristate "Support for STM32 multifunctions timer"
+	select MFD_CORE
+	select REGMAP
+	depends on ARCH_STM32
+	depends on OF
+	help
+	  Select multifunction driver (pwm, IIO trigger) for stm32 timers
+
 menu "Multimedia Capabilities Port drivers"
 	depends on ARCH_SA1100
 
@@ -1644,4 +1653,5 @@ config MFD_VEXPRESS_SYSREG
 	  on the ARM Ltd. Versatile Express board.
 
 endmenu
+
 endif
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 9834e66..b348c3e 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -211,3 +211,5 @@ obj-$(CONFIG_INTEL_SOC_PMIC)	+= intel-soc-pmic.o
 obj-$(CONFIG_MFD_MT6397)	+= mt6397-core.o
 
 obj-$(CONFIG_MFD_ALTERA_A10SR)	+= altera-a10sr.o
+
+obj-$(CONFIG_MFD_STM32_TIMER) 	+= stm32-mfd-timer.o
diff --git a/drivers/mfd/stm32-mfd-timer.c b/drivers/mfd/stm32-mfd-timer.c
new file mode 100644
index 0000000..67e7db3
--- /dev/null
+++ b/drivers/mfd/stm32-mfd-timer.c
@@ -0,0 +1,236 @@
+/*
+ * stm32-timer.c
+ *
+ * Copyright (C) STMicroelectronics 2016
+ * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+#include <linux/mfd/stm32-mfd-timer.h>
+
+static const struct stm32_mfd_timer_cfg mfd_cells_cfg[] = {
+	{
+		.pwm_name = "pwm1",
+		.pwm_compatible = "st,stm32-pwm1",
+		.trigger_name = "iiotimer1",
+		.trigger_compatible = "st,stm32-iio-timer1",
+	},
+	{
+		.pwm_name = "pwm2",
+		.pwm_compatible = "st,stm32-pwm2",
+		.trigger_name = "iiotimer2",
+		.trigger_compatible = "st,stm32-iio-timer2",
+	},
+	{
+		.pwm_name = "pwm3",
+		.pwm_compatible = "st,stm32-pwm3",
+		.trigger_name = "iiotimer3",
+		.trigger_compatible = "st,stm32-iio-timer3",
+	},
+	{
+		.pwm_name = "pwm4",
+		.pwm_compatible = "st,stm32-pwm4",
+		.trigger_name = "iiotimer4",
+		.trigger_compatible = "st,stm32-iio-timer4",
+	},
+	{
+		.pwm_name = "pwm5",
+		.pwm_compatible = "st,stm32-pwm5",
+		.trigger_name = "iiotimer5",
+		.trigger_compatible = "st,stm32-iio-timer5",
+	},
+	{
+		.trigger_name = "iiotimer6",
+		.trigger_compatible = "st,stm32-iio-timer6",
+	},
+	{
+		.trigger_name = "iiotimer7",
+		.trigger_compatible = "st,stm32-iio-timer7",
+	},
+	{
+		.pwm_name = "pwm8",
+		.pwm_compatible = "st,stm32-pwm8",
+		.trigger_name = "iiotimer8",
+		.trigger_compatible = "st,stm32-iio-timer8",
+	},
+	{
+		.pwm_name = "pwm9",
+		.pwm_compatible = "st,stm32-pwm9",
+		.trigger_name = "iiotimer9",
+		.trigger_compatible = "st,stm32-iio-timer9",
+	},
+	{
+		.pwm_name = "pwm10",
+		.pwm_compatible = "st,stm32-pwm10",
+	},
+	{
+		.pwm_name = "pwm11",
+		.pwm_compatible = "st,stm32-pwm11",
+	},
+	{
+		.pwm_name = "pwm12",
+		.pwm_compatible = "st,stm32-pwm12",
+		.trigger_name = "iiotimer12",
+		.trigger_compatible = "st,stm32-iio-timer12",
+	},
+	{
+		.pwm_name = "pwm13",
+		.pwm_compatible = "st,stm32-pwm13",
+	},
+	{
+		.pwm_name = "pwm14",
+		.pwm_compatible = "st,stm32-pwm14",
+	},
+};
+
+static const struct of_device_id stm32_timer_of_match[] = {
+	{
+		.compatible = "st,stm32-mfd-timer1",
+		.data = &mfd_cells_cfg[0],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer2",
+		.data = &mfd_cells_cfg[1],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer3",
+		.data = &mfd_cells_cfg[2],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer4",
+		.data = &mfd_cells_cfg[3],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer5",
+		.data = &mfd_cells_cfg[4],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer6",
+		.data = &mfd_cells_cfg[5],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer7",
+		.data = &mfd_cells_cfg[6],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer8",
+		.data = &mfd_cells_cfg[7],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer9",
+		.data = &mfd_cells_cfg[8],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer10",
+		.data = &mfd_cells_cfg[9],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer11",
+		.data = &mfd_cells_cfg[10],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer12",
+		.data = &mfd_cells_cfg[11],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer13",
+		.data = &mfd_cells_cfg[12],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer14",
+		.data = &mfd_cells_cfg[13],
+	},
+};
+
+static const struct regmap_config stm32_timer_regmap_cfg = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = sizeof(u32),
+	.max_register = 0x400,
+	.fast_io = true,
+};
+
+static int stm32_mfd_timer_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct stm32_mfd_timer_dev *mfd;
+	struct resource *res;
+	int ret, nb_cells = 0;
+	struct mfd_cell *cell = NULL;
+	void __iomem *mmio;
+
+	mfd = devm_kzalloc(dev, sizeof(*mfd), GFP_KERNEL);
+	if (!mfd)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENOMEM;
+
+	mmio = devm_ioremap_resource(dev, res);
+	if (IS_ERR(mmio))
+		return PTR_ERR(mmio);
+
+	mfd->regmap = devm_regmap_init_mmio_clk(dev, "mfd_timer_clk", mmio,
+						&stm32_timer_regmap_cfg);
+	if (IS_ERR(mfd->regmap))
+		return PTR_ERR(mfd->regmap);
+
+	mfd->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(mfd->clk))
+		return PTR_ERR(mfd->clk);
+
+	mfd->irq = platform_get_irq(pdev, 0);
+	if (mfd->irq < 0)
+		return -EINVAL;
+
+	/* populate data structure depending on compatibility */
+	if (!of_match_node(stm32_timer_of_match, np)->data)
+		return -EINVAL;
+
+	mfd->cfg =
+	(struct stm32_mfd_timer_cfg *)of_match_node(stm32_timer_of_match, np)->data;
+
+	if (mfd->cfg->pwm_name && mfd->cfg->pwm_compatible) {
+		cell = &mfd->cells[nb_cells++];
+		cell->name = mfd->cfg->pwm_name;
+		cell->of_compatible = mfd->cfg->pwm_compatible;
+		cell->platform_data = mfd;
+		cell->pdata_size = sizeof(*mfd);
+	}
+
+	if (mfd->cfg->trigger_name && mfd->cfg->trigger_compatible) {
+		cell = &mfd->cells[nb_cells++];
+		cell->name = mfd->cfg->trigger_name;
+		cell->of_compatible = mfd->cfg->trigger_compatible;
+		cell->platform_data = mfd;
+		cell->pdata_size = sizeof(*mfd);
+	}
+
+	ret = devm_mfd_add_devices(&pdev->dev, pdev->id, mfd->cells,
+				   nb_cells, NULL, 0, NULL);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, mfd);
+
+	return 0;
+}
+
+static struct platform_driver stm32_mfd_timer_driver = {
+	.probe		= stm32_mfd_timer_probe,
+	.driver	= {
+		.name	= "stm32-mfd-timer",
+		.of_match_table = stm32_timer_of_match,
+	},
+};
+module_platform_driver(stm32_mfd_timer_driver);
+
+MODULE_DESCRIPTION("STMicroelectronics STM32 Timer MFD");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/stm32-mfd-timer.h b/include/linux/mfd/stm32-mfd-timer.h
new file mode 100644
index 0000000..4a79c22
--- /dev/null
+++ b/include/linux/mfd/stm32-mfd-timer.h
@@ -0,0 +1,78 @@
+/*
+ * stm32-mfd-timer.h
+ *
+ * Copyright (C) STMicroelectronics 2016
+ * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef _LINUX_MFD_STM32_TIMER_H_
+#define _LINUX_MFD_STM32_TIMER_H_
+
+#include <linux/clk.h>
+#include <linux/mfd/core.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+#define TIM_CR1		0x00	/* Control Register 1      */
+#define TIM_CR2		0x04	/* Control Register 2      */
+#define TIM_SMCR	0x08	/* Slave mode control reg  */
+#define TIM_DIER	0x0C	/* DMA/interrupt register  */
+#define TIM_SR		0x10	/* Status register	   */
+#define TIM_EGR		0x14	/* Event Generation Reg    */
+#define TIM_CCMR1	0x18	/* Capt/Comp 1 Mode Reg    */
+#define TIM_CCMR2	0x1C	/* Capt/Comp 2 Mode Reg    */
+#define TIM_CCER	0x20	/* Capt/Comp Enable Reg    */
+#define TIM_PSC		0x28	/* Prescaler               */
+#define TIM_ARR		0x2c	/* Auto-Reload Register    */
+#define TIM_CCR1	0x34	/* Capt/Comp Register 1    */
+#define TIM_CCR2	0x38	/* Capt/Comp Register 2    */
+#define TIM_CCR3	0x3C	/* Capt/Comp Register 3    */
+#define TIM_CCR4	0x40	/* Capt/Comp Register 4    */
+#define TIM_BDTR	0x44	/* Break and Dead-Time Reg */
+
+#define TIM_CR1_CEN	BIT(0)	/* Counter Enable	   */
+#define TIM_CR1_ARPE	BIT(7)	/* Auto-reload Preload Ena */
+#define TIM_CR2_MMS	(BIT(4) | BIT(5) | BIT(6)) /* Master mode selection */
+#define TIM_SMCR_SMS	(BIT(0) | BIT(1) | BIT(2)) /* Slave mode selection */
+#define TIM_SMCR_TS	(BIT(4) | BIT(5) | BIT(6)) /* Trigger selection */
+#define TIM_DIER_UIE	BIT(0)	/* Update interrupt	   */
+#define TIM_SR_UIF	BIT(0)	/* Update interrupt flag   */
+#define TIM_EGR_UG	BIT(0)	/* Update Generation       */
+#define TIM_CCMR_PE	BIT(3)	/* Channel Preload Enable  */
+#define TIM_CCMR_M1	(BIT(6) | BIT(5))  /* Channel PWM Mode 1 */
+#define TIM_CCER_CC1E	BIT(0)	/* Capt/Comp 1  out Ena    */
+#define TIM_CCER_CC1P	BIT(1)	/* Capt/Comp 1  Polarity   */
+#define TIM_CCER_CC1NE	BIT(2)	/* Capt/Comp 1N out Ena    */
+#define TIM_CCER_CC1NP	BIT(3)	/* Capt/Comp 1N Polarity   */
+#define TIM_CCER_CCXE	(BIT(0) | BIT(4) | BIT(8) | BIT(12))
+#define TIM_BDTR_BKE	BIT(12) /* Break input enable	   */
+#define TIM_BDTR_BKP	BIT(13) /* Break input polarity	   */
+#define TIM_BDTR_AOE	BIT(14)	/* Automatic Output Enable */
+#define TIM_BDTR_MOE	BIT(15)	/* Main Output Enable      */
+
+#define STM32_TIMER_CELLS	2
+#define MAX_TIM_PSC		0xFFFF
+
+struct stm32_mfd_timer_cfg {
+	const char *pwm_name;
+	const char *pwm_compatible;
+	const char *trigger_name;
+	const char *trigger_compatible;
+};
+
+struct stm32_mfd_timer_dev {
+	/* Device data */
+	struct device *dev;
+	struct clk *clk;
+	int irq;
+
+	/* Registers mapping */
+	struct regmap *regmap;
+
+	/* Private data */
+	struct mfd_cell cells[STM32_TIMER_CELLS];
+	struct stm32_mfd_timer_cfg *cfg;
+};
+
+#endif
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 2/7] add MFD for stm32 timer IP
@ 2016-11-22 16:13   ` Benjamin Gaignard
  0 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-22 16:13 UTC (permalink / raw)
  To: lee.jones-QSEj5FYQhm4dnm+yROfE0A, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, alexandre.torgue-qxv4g6HH51o,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	linux-pwm-u79uwXL29TY76Z2rM5mHXA, jic23-DgEjT+Ai2ygdnm+yROfE0A,
	knaack.h-Mmb7MZpHnFY, lars-Qo5EllUWu/uELgA04lAiVw,
	pmeerw-jW+XmwGofnusTnJN9+BGXg, linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: fabrice.gasnier-qxv4g6HH51o, gerald.baeza-qxv4g6HH51o,
	arnaud.pouliquen-qxv4g6HH51o,
	linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
	linaro-kernel-cunTk1MwBs8s++Sfvej+rw, Benjamin Gaignard

This hardware block could at used at same time for PWM generation
and IIO timer for other IPs like DAC, ADC or other timers.
PWM and IIO timer configuration are mixed in the same registers
so we need a MFD to be able to share those registers.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard-qxv4g6HH51o@public.gmane.org>
---
 drivers/mfd/Kconfig                 |  10 ++
 drivers/mfd/Makefile                |   2 +
 drivers/mfd/stm32-mfd-timer.c       | 236 ++++++++++++++++++++++++++++++++++++
 include/linux/mfd/stm32-mfd-timer.h |  78 ++++++++++++
 4 files changed, 326 insertions(+)
 create mode 100644 drivers/mfd/stm32-mfd-timer.c
 create mode 100644 include/linux/mfd/stm32-mfd-timer.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index c6df644..63aee36 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1607,6 +1607,15 @@ config MFD_STW481X
 	  in various ST Microelectronics and ST-Ericsson embedded
 	  Nomadik series.
 
+config MFD_STM32_TIMER
+	tristate "Support for STM32 multifunctions timer"
+	select MFD_CORE
+	select REGMAP
+	depends on ARCH_STM32
+	depends on OF
+	help
+	  Select multifunction driver (pwm, IIO trigger) for stm32 timers
+
 menu "Multimedia Capabilities Port drivers"
 	depends on ARCH_SA1100
 
@@ -1644,4 +1653,5 @@ config MFD_VEXPRESS_SYSREG
 	  on the ARM Ltd. Versatile Express board.
 
 endmenu
+
 endif
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 9834e66..b348c3e 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -211,3 +211,5 @@ obj-$(CONFIG_INTEL_SOC_PMIC)	+= intel-soc-pmic.o
 obj-$(CONFIG_MFD_MT6397)	+= mt6397-core.o
 
 obj-$(CONFIG_MFD_ALTERA_A10SR)	+= altera-a10sr.o
+
+obj-$(CONFIG_MFD_STM32_TIMER) 	+= stm32-mfd-timer.o
diff --git a/drivers/mfd/stm32-mfd-timer.c b/drivers/mfd/stm32-mfd-timer.c
new file mode 100644
index 0000000..67e7db3
--- /dev/null
+++ b/drivers/mfd/stm32-mfd-timer.c
@@ -0,0 +1,236 @@
+/*
+ * stm32-timer.c
+ *
+ * Copyright (C) STMicroelectronics 2016
+ * Author: Benjamin Gaignard <benjamin.gaignard-qxv4g6HH51o@public.gmane.org> for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+#include <linux/mfd/stm32-mfd-timer.h>
+
+static const struct stm32_mfd_timer_cfg mfd_cells_cfg[] = {
+	{
+		.pwm_name = "pwm1",
+		.pwm_compatible = "st,stm32-pwm1",
+		.trigger_name = "iiotimer1",
+		.trigger_compatible = "st,stm32-iio-timer1",
+	},
+	{
+		.pwm_name = "pwm2",
+		.pwm_compatible = "st,stm32-pwm2",
+		.trigger_name = "iiotimer2",
+		.trigger_compatible = "st,stm32-iio-timer2",
+	},
+	{
+		.pwm_name = "pwm3",
+		.pwm_compatible = "st,stm32-pwm3",
+		.trigger_name = "iiotimer3",
+		.trigger_compatible = "st,stm32-iio-timer3",
+	},
+	{
+		.pwm_name = "pwm4",
+		.pwm_compatible = "st,stm32-pwm4",
+		.trigger_name = "iiotimer4",
+		.trigger_compatible = "st,stm32-iio-timer4",
+	},
+	{
+		.pwm_name = "pwm5",
+		.pwm_compatible = "st,stm32-pwm5",
+		.trigger_name = "iiotimer5",
+		.trigger_compatible = "st,stm32-iio-timer5",
+	},
+	{
+		.trigger_name = "iiotimer6",
+		.trigger_compatible = "st,stm32-iio-timer6",
+	},
+	{
+		.trigger_name = "iiotimer7",
+		.trigger_compatible = "st,stm32-iio-timer7",
+	},
+	{
+		.pwm_name = "pwm8",
+		.pwm_compatible = "st,stm32-pwm8",
+		.trigger_name = "iiotimer8",
+		.trigger_compatible = "st,stm32-iio-timer8",
+	},
+	{
+		.pwm_name = "pwm9",
+		.pwm_compatible = "st,stm32-pwm9",
+		.trigger_name = "iiotimer9",
+		.trigger_compatible = "st,stm32-iio-timer9",
+	},
+	{
+		.pwm_name = "pwm10",
+		.pwm_compatible = "st,stm32-pwm10",
+	},
+	{
+		.pwm_name = "pwm11",
+		.pwm_compatible = "st,stm32-pwm11",
+	},
+	{
+		.pwm_name = "pwm12",
+		.pwm_compatible = "st,stm32-pwm12",
+		.trigger_name = "iiotimer12",
+		.trigger_compatible = "st,stm32-iio-timer12",
+	},
+	{
+		.pwm_name = "pwm13",
+		.pwm_compatible = "st,stm32-pwm13",
+	},
+	{
+		.pwm_name = "pwm14",
+		.pwm_compatible = "st,stm32-pwm14",
+	},
+};
+
+static const struct of_device_id stm32_timer_of_match[] = {
+	{
+		.compatible = "st,stm32-mfd-timer1",
+		.data = &mfd_cells_cfg[0],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer2",
+		.data = &mfd_cells_cfg[1],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer3",
+		.data = &mfd_cells_cfg[2],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer4",
+		.data = &mfd_cells_cfg[3],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer5",
+		.data = &mfd_cells_cfg[4],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer6",
+		.data = &mfd_cells_cfg[5],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer7",
+		.data = &mfd_cells_cfg[6],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer8",
+		.data = &mfd_cells_cfg[7],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer9",
+		.data = &mfd_cells_cfg[8],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer10",
+		.data = &mfd_cells_cfg[9],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer11",
+		.data = &mfd_cells_cfg[10],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer12",
+		.data = &mfd_cells_cfg[11],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer13",
+		.data = &mfd_cells_cfg[12],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer14",
+		.data = &mfd_cells_cfg[13],
+	},
+};
+
+static const struct regmap_config stm32_timer_regmap_cfg = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = sizeof(u32),
+	.max_register = 0x400,
+	.fast_io = true,
+};
+
+static int stm32_mfd_timer_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct stm32_mfd_timer_dev *mfd;
+	struct resource *res;
+	int ret, nb_cells = 0;
+	struct mfd_cell *cell = NULL;
+	void __iomem *mmio;
+
+	mfd = devm_kzalloc(dev, sizeof(*mfd), GFP_KERNEL);
+	if (!mfd)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENOMEM;
+
+	mmio = devm_ioremap_resource(dev, res);
+	if (IS_ERR(mmio))
+		return PTR_ERR(mmio);
+
+	mfd->regmap = devm_regmap_init_mmio_clk(dev, "mfd_timer_clk", mmio,
+						&stm32_timer_regmap_cfg);
+	if (IS_ERR(mfd->regmap))
+		return PTR_ERR(mfd->regmap);
+
+	mfd->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(mfd->clk))
+		return PTR_ERR(mfd->clk);
+
+	mfd->irq = platform_get_irq(pdev, 0);
+	if (mfd->irq < 0)
+		return -EINVAL;
+
+	/* populate data structure depending on compatibility */
+	if (!of_match_node(stm32_timer_of_match, np)->data)
+		return -EINVAL;
+
+	mfd->cfg =
+	(struct stm32_mfd_timer_cfg *)of_match_node(stm32_timer_of_match, np)->data;
+
+	if (mfd->cfg->pwm_name && mfd->cfg->pwm_compatible) {
+		cell = &mfd->cells[nb_cells++];
+		cell->name = mfd->cfg->pwm_name;
+		cell->of_compatible = mfd->cfg->pwm_compatible;
+		cell->platform_data = mfd;
+		cell->pdata_size = sizeof(*mfd);
+	}
+
+	if (mfd->cfg->trigger_name && mfd->cfg->trigger_compatible) {
+		cell = &mfd->cells[nb_cells++];
+		cell->name = mfd->cfg->trigger_name;
+		cell->of_compatible = mfd->cfg->trigger_compatible;
+		cell->platform_data = mfd;
+		cell->pdata_size = sizeof(*mfd);
+	}
+
+	ret = devm_mfd_add_devices(&pdev->dev, pdev->id, mfd->cells,
+				   nb_cells, NULL, 0, NULL);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, mfd);
+
+	return 0;
+}
+
+static struct platform_driver stm32_mfd_timer_driver = {
+	.probe		= stm32_mfd_timer_probe,
+	.driver	= {
+		.name	= "stm32-mfd-timer",
+		.of_match_table = stm32_timer_of_match,
+	},
+};
+module_platform_driver(stm32_mfd_timer_driver);
+
+MODULE_DESCRIPTION("STMicroelectronics STM32 Timer MFD");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/stm32-mfd-timer.h b/include/linux/mfd/stm32-mfd-timer.h
new file mode 100644
index 0000000..4a79c22
--- /dev/null
+++ b/include/linux/mfd/stm32-mfd-timer.h
@@ -0,0 +1,78 @@
+/*
+ * stm32-mfd-timer.h
+ *
+ * Copyright (C) STMicroelectronics 2016
+ * Author: Benjamin Gaignard <benjamin.gaignard-qxv4g6HH51o@public.gmane.org> for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef _LINUX_MFD_STM32_TIMER_H_
+#define _LINUX_MFD_STM32_TIMER_H_
+
+#include <linux/clk.h>
+#include <linux/mfd/core.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+#define TIM_CR1		0x00	/* Control Register 1      */
+#define TIM_CR2		0x04	/* Control Register 2      */
+#define TIM_SMCR	0x08	/* Slave mode control reg  */
+#define TIM_DIER	0x0C	/* DMA/interrupt register  */
+#define TIM_SR		0x10	/* Status register	   */
+#define TIM_EGR		0x14	/* Event Generation Reg    */
+#define TIM_CCMR1	0x18	/* Capt/Comp 1 Mode Reg    */
+#define TIM_CCMR2	0x1C	/* Capt/Comp 2 Mode Reg    */
+#define TIM_CCER	0x20	/* Capt/Comp Enable Reg    */
+#define TIM_PSC		0x28	/* Prescaler               */
+#define TIM_ARR		0x2c	/* Auto-Reload Register    */
+#define TIM_CCR1	0x34	/* Capt/Comp Register 1    */
+#define TIM_CCR2	0x38	/* Capt/Comp Register 2    */
+#define TIM_CCR3	0x3C	/* Capt/Comp Register 3    */
+#define TIM_CCR4	0x40	/* Capt/Comp Register 4    */
+#define TIM_BDTR	0x44	/* Break and Dead-Time Reg */
+
+#define TIM_CR1_CEN	BIT(0)	/* Counter Enable	   */
+#define TIM_CR1_ARPE	BIT(7)	/* Auto-reload Preload Ena */
+#define TIM_CR2_MMS	(BIT(4) | BIT(5) | BIT(6)) /* Master mode selection */
+#define TIM_SMCR_SMS	(BIT(0) | BIT(1) | BIT(2)) /* Slave mode selection */
+#define TIM_SMCR_TS	(BIT(4) | BIT(5) | BIT(6)) /* Trigger selection */
+#define TIM_DIER_UIE	BIT(0)	/* Update interrupt	   */
+#define TIM_SR_UIF	BIT(0)	/* Update interrupt flag   */
+#define TIM_EGR_UG	BIT(0)	/* Update Generation       */
+#define TIM_CCMR_PE	BIT(3)	/* Channel Preload Enable  */
+#define TIM_CCMR_M1	(BIT(6) | BIT(5))  /* Channel PWM Mode 1 */
+#define TIM_CCER_CC1E	BIT(0)	/* Capt/Comp 1  out Ena    */
+#define TIM_CCER_CC1P	BIT(1)	/* Capt/Comp 1  Polarity   */
+#define TIM_CCER_CC1NE	BIT(2)	/* Capt/Comp 1N out Ena    */
+#define TIM_CCER_CC1NP	BIT(3)	/* Capt/Comp 1N Polarity   */
+#define TIM_CCER_CCXE	(BIT(0) | BIT(4) | BIT(8) | BIT(12))
+#define TIM_BDTR_BKE	BIT(12) /* Break input enable	   */
+#define TIM_BDTR_BKP	BIT(13) /* Break input polarity	   */
+#define TIM_BDTR_AOE	BIT(14)	/* Automatic Output Enable */
+#define TIM_BDTR_MOE	BIT(15)	/* Main Output Enable      */
+
+#define STM32_TIMER_CELLS	2
+#define MAX_TIM_PSC		0xFFFF
+
+struct stm32_mfd_timer_cfg {
+	const char *pwm_name;
+	const char *pwm_compatible;
+	const char *trigger_name;
+	const char *trigger_compatible;
+};
+
+struct stm32_mfd_timer_dev {
+	/* Device data */
+	struct device *dev;
+	struct clk *clk;
+	int irq;
+
+	/* Registers mapping */
+	struct regmap *regmap;
+
+	/* Private data */
+	struct mfd_cell cells[STM32_TIMER_CELLS];
+	struct stm32_mfd_timer_cfg *cfg;
+};
+
+#endif
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 2/7] add MFD for stm32 timer IP
@ 2016-11-22 16:13   ` Benjamin Gaignard
  0 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-22 16:13 UTC (permalink / raw)
  To: linux-arm-kernel

This hardware block could at used at same time for PWM generation
and IIO timer for other IPs like DAC, ADC or other timers.
PWM and IIO timer configuration are mixed in the same registers
so we need a MFD to be able to share those registers.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
---
 drivers/mfd/Kconfig                 |  10 ++
 drivers/mfd/Makefile                |   2 +
 drivers/mfd/stm32-mfd-timer.c       | 236 ++++++++++++++++++++++++++++++++++++
 include/linux/mfd/stm32-mfd-timer.h |  78 ++++++++++++
 4 files changed, 326 insertions(+)
 create mode 100644 drivers/mfd/stm32-mfd-timer.c
 create mode 100644 include/linux/mfd/stm32-mfd-timer.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index c6df644..63aee36 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1607,6 +1607,15 @@ config MFD_STW481X
 	  in various ST Microelectronics and ST-Ericsson embedded
 	  Nomadik series.
 
+config MFD_STM32_TIMER
+	tristate "Support for STM32 multifunctions timer"
+	select MFD_CORE
+	select REGMAP
+	depends on ARCH_STM32
+	depends on OF
+	help
+	  Select multifunction driver (pwm, IIO trigger) for stm32 timers
+
 menu "Multimedia Capabilities Port drivers"
 	depends on ARCH_SA1100
 
@@ -1644,4 +1653,5 @@ config MFD_VEXPRESS_SYSREG
 	  on the ARM Ltd. Versatile Express board.
 
 endmenu
+
 endif
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 9834e66..b348c3e 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -211,3 +211,5 @@ obj-$(CONFIG_INTEL_SOC_PMIC)	+= intel-soc-pmic.o
 obj-$(CONFIG_MFD_MT6397)	+= mt6397-core.o
 
 obj-$(CONFIG_MFD_ALTERA_A10SR)	+= altera-a10sr.o
+
+obj-$(CONFIG_MFD_STM32_TIMER) 	+= stm32-mfd-timer.o
diff --git a/drivers/mfd/stm32-mfd-timer.c b/drivers/mfd/stm32-mfd-timer.c
new file mode 100644
index 0000000..67e7db3
--- /dev/null
+++ b/drivers/mfd/stm32-mfd-timer.c
@@ -0,0 +1,236 @@
+/*
+ * stm32-timer.c
+ *
+ * Copyright (C) STMicroelectronics 2016
+ * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+#include <linux/mfd/stm32-mfd-timer.h>
+
+static const struct stm32_mfd_timer_cfg mfd_cells_cfg[] = {
+	{
+		.pwm_name = "pwm1",
+		.pwm_compatible = "st,stm32-pwm1",
+		.trigger_name = "iiotimer1",
+		.trigger_compatible = "st,stm32-iio-timer1",
+	},
+	{
+		.pwm_name = "pwm2",
+		.pwm_compatible = "st,stm32-pwm2",
+		.trigger_name = "iiotimer2",
+		.trigger_compatible = "st,stm32-iio-timer2",
+	},
+	{
+		.pwm_name = "pwm3",
+		.pwm_compatible = "st,stm32-pwm3",
+		.trigger_name = "iiotimer3",
+		.trigger_compatible = "st,stm32-iio-timer3",
+	},
+	{
+		.pwm_name = "pwm4",
+		.pwm_compatible = "st,stm32-pwm4",
+		.trigger_name = "iiotimer4",
+		.trigger_compatible = "st,stm32-iio-timer4",
+	},
+	{
+		.pwm_name = "pwm5",
+		.pwm_compatible = "st,stm32-pwm5",
+		.trigger_name = "iiotimer5",
+		.trigger_compatible = "st,stm32-iio-timer5",
+	},
+	{
+		.trigger_name = "iiotimer6",
+		.trigger_compatible = "st,stm32-iio-timer6",
+	},
+	{
+		.trigger_name = "iiotimer7",
+		.trigger_compatible = "st,stm32-iio-timer7",
+	},
+	{
+		.pwm_name = "pwm8",
+		.pwm_compatible = "st,stm32-pwm8",
+		.trigger_name = "iiotimer8",
+		.trigger_compatible = "st,stm32-iio-timer8",
+	},
+	{
+		.pwm_name = "pwm9",
+		.pwm_compatible = "st,stm32-pwm9",
+		.trigger_name = "iiotimer9",
+		.trigger_compatible = "st,stm32-iio-timer9",
+	},
+	{
+		.pwm_name = "pwm10",
+		.pwm_compatible = "st,stm32-pwm10",
+	},
+	{
+		.pwm_name = "pwm11",
+		.pwm_compatible = "st,stm32-pwm11",
+	},
+	{
+		.pwm_name = "pwm12",
+		.pwm_compatible = "st,stm32-pwm12",
+		.trigger_name = "iiotimer12",
+		.trigger_compatible = "st,stm32-iio-timer12",
+	},
+	{
+		.pwm_name = "pwm13",
+		.pwm_compatible = "st,stm32-pwm13",
+	},
+	{
+		.pwm_name = "pwm14",
+		.pwm_compatible = "st,stm32-pwm14",
+	},
+};
+
+static const struct of_device_id stm32_timer_of_match[] = {
+	{
+		.compatible = "st,stm32-mfd-timer1",
+		.data = &mfd_cells_cfg[0],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer2",
+		.data = &mfd_cells_cfg[1],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer3",
+		.data = &mfd_cells_cfg[2],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer4",
+		.data = &mfd_cells_cfg[3],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer5",
+		.data = &mfd_cells_cfg[4],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer6",
+		.data = &mfd_cells_cfg[5],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer7",
+		.data = &mfd_cells_cfg[6],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer8",
+		.data = &mfd_cells_cfg[7],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer9",
+		.data = &mfd_cells_cfg[8],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer10",
+		.data = &mfd_cells_cfg[9],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer11",
+		.data = &mfd_cells_cfg[10],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer12",
+		.data = &mfd_cells_cfg[11],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer13",
+		.data = &mfd_cells_cfg[12],
+	},
+	{
+		.compatible = "st,stm32-mfd-timer14",
+		.data = &mfd_cells_cfg[13],
+	},
+};
+
+static const struct regmap_config stm32_timer_regmap_cfg = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = sizeof(u32),
+	.max_register = 0x400,
+	.fast_io = true,
+};
+
+static int stm32_mfd_timer_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct stm32_mfd_timer_dev *mfd;
+	struct resource *res;
+	int ret, nb_cells = 0;
+	struct mfd_cell *cell = NULL;
+	void __iomem *mmio;
+
+	mfd = devm_kzalloc(dev, sizeof(*mfd), GFP_KERNEL);
+	if (!mfd)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENOMEM;
+
+	mmio = devm_ioremap_resource(dev, res);
+	if (IS_ERR(mmio))
+		return PTR_ERR(mmio);
+
+	mfd->regmap = devm_regmap_init_mmio_clk(dev, "mfd_timer_clk", mmio,
+						&stm32_timer_regmap_cfg);
+	if (IS_ERR(mfd->regmap))
+		return PTR_ERR(mfd->regmap);
+
+	mfd->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(mfd->clk))
+		return PTR_ERR(mfd->clk);
+
+	mfd->irq = platform_get_irq(pdev, 0);
+	if (mfd->irq < 0)
+		return -EINVAL;
+
+	/* populate data structure depending on compatibility */
+	if (!of_match_node(stm32_timer_of_match, np)->data)
+		return -EINVAL;
+
+	mfd->cfg =
+	(struct stm32_mfd_timer_cfg *)of_match_node(stm32_timer_of_match, np)->data;
+
+	if (mfd->cfg->pwm_name && mfd->cfg->pwm_compatible) {
+		cell = &mfd->cells[nb_cells++];
+		cell->name = mfd->cfg->pwm_name;
+		cell->of_compatible = mfd->cfg->pwm_compatible;
+		cell->platform_data = mfd;
+		cell->pdata_size = sizeof(*mfd);
+	}
+
+	if (mfd->cfg->trigger_name && mfd->cfg->trigger_compatible) {
+		cell = &mfd->cells[nb_cells++];
+		cell->name = mfd->cfg->trigger_name;
+		cell->of_compatible = mfd->cfg->trigger_compatible;
+		cell->platform_data = mfd;
+		cell->pdata_size = sizeof(*mfd);
+	}
+
+	ret = devm_mfd_add_devices(&pdev->dev, pdev->id, mfd->cells,
+				   nb_cells, NULL, 0, NULL);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, mfd);
+
+	return 0;
+}
+
+static struct platform_driver stm32_mfd_timer_driver = {
+	.probe		= stm32_mfd_timer_probe,
+	.driver	= {
+		.name	= "stm32-mfd-timer",
+		.of_match_table = stm32_timer_of_match,
+	},
+};
+module_platform_driver(stm32_mfd_timer_driver);
+
+MODULE_DESCRIPTION("STMicroelectronics STM32 Timer MFD");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/stm32-mfd-timer.h b/include/linux/mfd/stm32-mfd-timer.h
new file mode 100644
index 0000000..4a79c22
--- /dev/null
+++ b/include/linux/mfd/stm32-mfd-timer.h
@@ -0,0 +1,78 @@
+/*
+ * stm32-mfd-timer.h
+ *
+ * Copyright (C) STMicroelectronics 2016
+ * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef _LINUX_MFD_STM32_TIMER_H_
+#define _LINUX_MFD_STM32_TIMER_H_
+
+#include <linux/clk.h>
+#include <linux/mfd/core.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+#define TIM_CR1		0x00	/* Control Register 1      */
+#define TIM_CR2		0x04	/* Control Register 2      */
+#define TIM_SMCR	0x08	/* Slave mode control reg  */
+#define TIM_DIER	0x0C	/* DMA/interrupt register  */
+#define TIM_SR		0x10	/* Status register	   */
+#define TIM_EGR		0x14	/* Event Generation Reg    */
+#define TIM_CCMR1	0x18	/* Capt/Comp 1 Mode Reg    */
+#define TIM_CCMR2	0x1C	/* Capt/Comp 2 Mode Reg    */
+#define TIM_CCER	0x20	/* Capt/Comp Enable Reg    */
+#define TIM_PSC		0x28	/* Prescaler               */
+#define TIM_ARR		0x2c	/* Auto-Reload Register    */
+#define TIM_CCR1	0x34	/* Capt/Comp Register 1    */
+#define TIM_CCR2	0x38	/* Capt/Comp Register 2    */
+#define TIM_CCR3	0x3C	/* Capt/Comp Register 3    */
+#define TIM_CCR4	0x40	/* Capt/Comp Register 4    */
+#define TIM_BDTR	0x44	/* Break and Dead-Time Reg */
+
+#define TIM_CR1_CEN	BIT(0)	/* Counter Enable	   */
+#define TIM_CR1_ARPE	BIT(7)	/* Auto-reload Preload Ena */
+#define TIM_CR2_MMS	(BIT(4) | BIT(5) | BIT(6)) /* Master mode selection */
+#define TIM_SMCR_SMS	(BIT(0) | BIT(1) | BIT(2)) /* Slave mode selection */
+#define TIM_SMCR_TS	(BIT(4) | BIT(5) | BIT(6)) /* Trigger selection */
+#define TIM_DIER_UIE	BIT(0)	/* Update interrupt	   */
+#define TIM_SR_UIF	BIT(0)	/* Update interrupt flag   */
+#define TIM_EGR_UG	BIT(0)	/* Update Generation       */
+#define TIM_CCMR_PE	BIT(3)	/* Channel Preload Enable  */
+#define TIM_CCMR_M1	(BIT(6) | BIT(5))  /* Channel PWM Mode 1 */
+#define TIM_CCER_CC1E	BIT(0)	/* Capt/Comp 1  out Ena    */
+#define TIM_CCER_CC1P	BIT(1)	/* Capt/Comp 1  Polarity   */
+#define TIM_CCER_CC1NE	BIT(2)	/* Capt/Comp 1N out Ena    */
+#define TIM_CCER_CC1NP	BIT(3)	/* Capt/Comp 1N Polarity   */
+#define TIM_CCER_CCXE	(BIT(0) | BIT(4) | BIT(8) | BIT(12))
+#define TIM_BDTR_BKE	BIT(12) /* Break input enable	   */
+#define TIM_BDTR_BKP	BIT(13) /* Break input polarity	   */
+#define TIM_BDTR_AOE	BIT(14)	/* Automatic Output Enable */
+#define TIM_BDTR_MOE	BIT(15)	/* Main Output Enable      */
+
+#define STM32_TIMER_CELLS	2
+#define MAX_TIM_PSC		0xFFFF
+
+struct stm32_mfd_timer_cfg {
+	const char *pwm_name;
+	const char *pwm_compatible;
+	const char *trigger_name;
+	const char *trigger_compatible;
+};
+
+struct stm32_mfd_timer_dev {
+	/* Device data */
+	struct device *dev;
+	struct clk *clk;
+	int irq;
+
+	/* Registers mapping */
+	struct regmap *regmap;
+
+	/* Private data */
+	struct mfd_cell cells[STM32_TIMER_CELLS];
+	struct stm32_mfd_timer_cfg *cfg;
+};
+
+#endif
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 3/7] add pwm-stm32 DT bindings
@ 2016-11-22 16:13   ` Benjamin Gaignard
  0 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-22 16:13 UTC (permalink / raw)
  To: lee.jones, robh+dt, mark.rutland, alexandre.torgue, devicetree,
	linux-kernel, thierry.reding, linux-pwm, jic23, knaack.h, lars,
	pmeerw, linux-iio, linux-arm-kernel
  Cc: fabrice.gasnier, gerald.baeza, arnaud.pouliquen, linus.walleij,
	linaro-kernel, Benjamin Gaignard

Define binding for pwm-stm32

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
---
 .../devicetree/bindings/pwm/pwm-stm32.txt          | 43 ++++++++++++++++++++++
 1 file changed, 43 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pwm/pwm-stm32.txt

diff --git a/Documentation/devicetree/bindings/pwm/pwm-stm32.txt b/Documentation/devicetree/bindings/pwm/pwm-stm32.txt
new file mode 100644
index 0000000..819e024
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/pwm-stm32.txt
@@ -0,0 +1,43 @@
+STMicroelectronics PWM driver bindings for STM32
+--------------------------------------
+
+Must be a child of STM32 multifunctions timer driver
+
+Required parameters:
+- compatible :		"st,stm32-pwm1"
+			"st,stm32-pwm2"
+			"st,stm32-pwm3"
+			"st,stm32-pwm4"
+			"st,stm32-pwm5"
+			"st,stm32-pwm8"
+			"st,stm32-pwm9"
+			"st,stm32-pwm10"
+			"st,stm32-pwm11"
+			"st,stm32-pwm12"
+			"st,stm32-pwm13"
+			"st,stm32-pwm14"
+- pinctrl-names: 	Set to "default".
+- pinctrl-0: 		List of phandles pointing to pin configuration nodes
+			for PWM module.
+			For Pinctrl properties, please refer to [1].
+
+Optional parameters:
+- st,breakinput-polarity if set enable break input feature.
+			 The value define the active polarity:
+			  - 0 (active LOW)
+			  - 1 (active HIGH)
+
+[1] Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
+
+Example:
+	mfd_timer1: mfdtimer1@40010000 {
+		compatible = "st,stm32-mfd-timer1";
+		reg = <0x40010000 0x400>;
+		clocks = <&rcc 0 160>;
+		clock-names = "mfd_timer_clk";
+		interrupts = <27>;
+
+		pwm1: pwm1@40010000 {
+			compatible = "st,stm32-pwm1";
+		};
+	};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 3/7] add pwm-stm32 DT bindings
@ 2016-11-22 16:13   ` Benjamin Gaignard
  0 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-22 16:13 UTC (permalink / raw)
  To: lee.jones-QSEj5FYQhm4dnm+yROfE0A, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, alexandre.torgue-qxv4g6HH51o,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	linux-pwm-u79uwXL29TY76Z2rM5mHXA, jic23-DgEjT+Ai2ygdnm+yROfE0A,
	knaack.h-Mmb7MZpHnFY, lars-Qo5EllUWu/uELgA04lAiVw,
	pmeerw-jW+XmwGofnusTnJN9+BGXg, linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: fabrice.gasnier-qxv4g6HH51o, gerald.baeza-qxv4g6HH51o,
	arnaud.pouliquen-qxv4g6HH51o,
	linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
	linaro-kernel-cunTk1MwBs8s++Sfvej+rw, Benjamin Gaignard

Define binding for pwm-stm32

Signed-off-by: Benjamin Gaignard <benjamin.gaignard-qxv4g6HH51o@public.gmane.org>
---
 .../devicetree/bindings/pwm/pwm-stm32.txt          | 43 ++++++++++++++++++++++
 1 file changed, 43 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pwm/pwm-stm32.txt

diff --git a/Documentation/devicetree/bindings/pwm/pwm-stm32.txt b/Documentation/devicetree/bindings/pwm/pwm-stm32.txt
new file mode 100644
index 0000000..819e024
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/pwm-stm32.txt
@@ -0,0 +1,43 @@
+STMicroelectronics PWM driver bindings for STM32
+--------------------------------------
+
+Must be a child of STM32 multifunctions timer driver
+
+Required parameters:
+- compatible :		"st,stm32-pwm1"
+			"st,stm32-pwm2"
+			"st,stm32-pwm3"
+			"st,stm32-pwm4"
+			"st,stm32-pwm5"
+			"st,stm32-pwm8"
+			"st,stm32-pwm9"
+			"st,stm32-pwm10"
+			"st,stm32-pwm11"
+			"st,stm32-pwm12"
+			"st,stm32-pwm13"
+			"st,stm32-pwm14"
+- pinctrl-names: 	Set to "default".
+- pinctrl-0: 		List of phandles pointing to pin configuration nodes
+			for PWM module.
+			For Pinctrl properties, please refer to [1].
+
+Optional parameters:
+- st,breakinput-polarity if set enable break input feature.
+			 The value define the active polarity:
+			  - 0 (active LOW)
+			  - 1 (active HIGH)
+
+[1] Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
+
+Example:
+	mfd_timer1: mfdtimer1@40010000 {
+		compatible = "st,stm32-mfd-timer1";
+		reg = <0x40010000 0x400>;
+		clocks = <&rcc 0 160>;
+		clock-names = "mfd_timer_clk";
+		interrupts = <27>;
+
+		pwm1: pwm1@40010000 {
+			compatible = "st,stm32-pwm1";
+		};
+	};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 3/7] add pwm-stm32 DT bindings
@ 2016-11-22 16:13   ` Benjamin Gaignard
  0 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-22 16:13 UTC (permalink / raw)
  To: linux-arm-kernel

Define binding for pwm-stm32

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
---
 .../devicetree/bindings/pwm/pwm-stm32.txt          | 43 ++++++++++++++++++++++
 1 file changed, 43 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pwm/pwm-stm32.txt

diff --git a/Documentation/devicetree/bindings/pwm/pwm-stm32.txt b/Documentation/devicetree/bindings/pwm/pwm-stm32.txt
new file mode 100644
index 0000000..819e024
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/pwm-stm32.txt
@@ -0,0 +1,43 @@
+STMicroelectronics PWM driver bindings for STM32
+--------------------------------------
+
+Must be a child of STM32 multifunctions timer driver
+
+Required parameters:
+- compatible :		"st,stm32-pwm1"
+			"st,stm32-pwm2"
+			"st,stm32-pwm3"
+			"st,stm32-pwm4"
+			"st,stm32-pwm5"
+			"st,stm32-pwm8"
+			"st,stm32-pwm9"
+			"st,stm32-pwm10"
+			"st,stm32-pwm11"
+			"st,stm32-pwm12"
+			"st,stm32-pwm13"
+			"st,stm32-pwm14"
+- pinctrl-names: 	Set to "default".
+- pinctrl-0: 		List of phandles pointing to pin configuration nodes
+			for PWM module.
+			For Pinctrl properties, please refer to [1].
+
+Optional parameters:
+- st,breakinput-polarity if set enable break input feature.
+			 The value define the active polarity:
+			  - 0 (active LOW)
+			  - 1 (active HIGH)
+
+[1] Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
+
+Example:
+	mfd_timer1: mfdtimer1 at 40010000 {
+		compatible = "st,stm32-mfd-timer1";
+		reg = <0x40010000 0x400>;
+		clocks = <&rcc 0 160>;
+		clock-names = "mfd_timer_clk";
+		interrupts = <27>;
+
+		pwm1: pwm1 at 40010000 {
+			compatible = "st,stm32-pwm1";
+		};
+	};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 4/7] add pwm driver for stm32 plaftorm
@ 2016-11-22 16:13   ` Benjamin Gaignard
  0 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-22 16:13 UTC (permalink / raw)
  To: lee.jones, robh+dt, mark.rutland, alexandre.torgue, devicetree,
	linux-kernel, thierry.reding, linux-pwm, jic23, knaack.h, lars,
	pmeerw, linux-iio, linux-arm-kernel
  Cc: fabrice.gasnier, gerald.baeza, arnaud.pouliquen, linus.walleij,
	linaro-kernel, Benjamin Gaignard

This driver add support for pwm driver on stm32 platform.
The SoC have multiple instances of the hardware IP and each
of them could have small differences: number of channels,
complementary output, counter register size...
To handle those variations each block have its own compatible
linked to internal table that describe them.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
---
 drivers/pwm/Kconfig     |   8 ++
 drivers/pwm/Makefile    |   1 +
 drivers/pwm/pwm-stm32.c | 358 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 367 insertions(+)
 create mode 100644 drivers/pwm/pwm-stm32.c

diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index bf01288..aeee045 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -388,6 +388,14 @@ config PWM_STI
 	  To compile this driver as a module, choose M here: the module
 	  will be called pwm-sti.
 
+config PWM_STM32
+	bool "STMicroelectronics STM32 PWM"
+	depends on ARCH_STM32
+	depends on OF
+	select MFD_STM32_TIMER
+	help
+	  Generic PWM framework driver for STM32 SoCs.
+
 config PWM_STMPE
 	bool "STMPE expander PWM export"
 	depends on MFD_STMPE
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 1194c54..5aa9308 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_PWM_ROCKCHIP)	+= pwm-rockchip.o
 obj-$(CONFIG_PWM_SAMSUNG)	+= pwm-samsung.o
 obj-$(CONFIG_PWM_SPEAR)		+= pwm-spear.o
 obj-$(CONFIG_PWM_STI)		+= pwm-sti.o
+obj-$(CONFIG_PWM_STM32)		+= pwm-stm32.o
 obj-$(CONFIG_PWM_STMPE)		+= pwm-stmpe.o
 obj-$(CONFIG_PWM_SUN4I)		+= pwm-sun4i.o
 obj-$(CONFIG_PWM_TEGRA)		+= pwm-tegra.o
diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c
new file mode 100644
index 0000000..2d71ee7
--- /dev/null
+++ b/drivers/pwm/pwm-stm32.c
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) STMicroelectronics 2016
+ * Author:  Gerald Baeza <gerald.baeza@st.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ *
+ * Inspired by timer-stm32.c from Maxime Coquelin
+ *             pwm-atmel.c from Bo Shen
+ */
+
+#include <linux/module.h>
+#include <linux/pwm.h>
+
+#include <linux/mfd/stm32-mfd-timer.h>
+
+#define DRIVER_NAME "stm32-pwm"
+
+#define CAP_COMPLEMENTARY	BIT(0)
+#define CAP_32BIT_COUNTER	BIT(1)
+#define CAP_BREAKINPUT		BIT(2)
+
+struct stm32_pwm_cfg {
+	int npwm;
+	int caps;
+};
+
+static struct stm32_pwm_cfg f4_pwm_cfg[] = {
+	/* for pwm 1 and 8 */
+	{
+		.npwm = 4,
+		.caps = CAP_COMPLEMENTARY | CAP_BREAKINPUT,
+	},
+	/* for pwm 2 and 5 */
+	{
+		.npwm = 4,
+		.caps = CAP_32BIT_COUNTER,
+	},
+	/* for pwm 3 and 4 */
+	{
+		.npwm = 4,
+		.caps = 0,
+	},
+	/* for pwm 9 and 12 */
+	{
+		.npwm = 2,
+		.caps = 0,
+	},
+	/* for pwm 10, 11, 13 and 14 */
+	{
+		.npwm = 1,
+		.caps = 0,
+	},
+};
+
+struct stm32_pwm_dev {
+	struct device *dev;
+	struct clk *clk;
+	struct regmap *regmap;
+	struct pwm_chip chip;
+	struct stm32_pwm_cfg *cfg;
+	bool have_breakinput;
+	u32 breakinput_polarity;
+};
+
+#define to_stm32_pwm_dev(x) container_of(chip, struct stm32_pwm_dev, chip)
+
+static u32 __active_channels(struct stm32_pwm_dev *pwm_dev)
+{
+	u32 ccer;
+
+	regmap_read(pwm_dev->regmap, TIM_CCER, &ccer);
+
+	return ccer & TIM_CCER_CCXE;
+}
+
+static int write_ccrx(struct stm32_pwm_dev *dev, struct pwm_device *pwm,
+		      u32 ccr)
+{
+	switch (pwm->hwpwm) {
+	case 0:
+		return regmap_write(dev->regmap, TIM_CCR1, ccr);
+	case 1:
+		return regmap_write(dev->regmap, TIM_CCR2, ccr);
+	case 2:
+		return regmap_write(dev->regmap, TIM_CCR3, ccr);
+	case 3:
+		return regmap_write(dev->regmap, TIM_CCR4, ccr);
+	}
+	return -EINVAL;
+}
+
+static int stm32_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+			    int duty_ns, int period_ns)
+{
+	struct stm32_pwm_dev *dev = to_stm32_pwm_dev(chip);
+	unsigned long long prd, div, dty;
+	int prescaler = 0;
+	u32 max_arr = 0xFFFF, ccmr, mask, shift, bdtr;
+
+	if (dev->cfg->caps & CAP_32BIT_COUNTER)
+		max_arr = 0xFFFFFFFF;
+
+	/* Period and prescaler values depends of clock rate */
+	div = (unsigned long long)clk_get_rate(dev->clk) * period_ns;
+
+	do_div(div, NSEC_PER_SEC);
+	prd = div;
+
+	while (div > max_arr) {
+		prescaler++;
+		div = prd;
+		do_div(div, (prescaler + 1));
+	}
+	prd = div;
+
+	if (prescaler > MAX_TIM_PSC) {
+		dev_err(chip->dev, "prescaler exceeds the maximum value\n");
+		return -EINVAL;
+	}
+
+	/* All channels share the same prescaler and counter so
+	 * when two channels are active at the same we can't change them
+	 */
+	if (__active_channels(dev) & ~(1 << pwm->hwpwm * 4)) {
+		u32 psc, arr;
+
+		regmap_read(dev->regmap, TIM_PSC, &psc);
+		regmap_read(dev->regmap, TIM_ARR, &arr);
+
+		if ((psc != prescaler) || (arr != prd - 1))
+			return -EINVAL;
+	}
+
+	regmap_write(dev->regmap, TIM_PSC, prescaler);
+	regmap_write(dev->regmap, TIM_ARR, prd - 1);
+	regmap_update_bits(dev->regmap, TIM_CR1, TIM_CR1_ARPE, TIM_CR1_ARPE);
+
+	/* Calculate the duty cycles */
+	dty = prd * duty_ns;
+	do_div(dty, period_ns);
+
+	write_ccrx(dev, pwm, dty);
+
+	/* Configure output mode */
+	shift = (pwm->hwpwm & 0x1) * 8;
+	ccmr = (TIM_CCMR_PE | TIM_CCMR_M1) << shift;
+	mask = 0xFF << shift;
+
+	if (pwm->hwpwm & 0x2)
+		regmap_update_bits(dev->regmap, TIM_CCMR2, mask, ccmr);
+	else
+		regmap_update_bits(dev->regmap, TIM_CCMR1, mask, ccmr);
+
+	bdtr = TIM_BDTR_MOE | TIM_BDTR_AOE;
+	if (dev->have_breakinput) {
+		bdtr |= TIM_BDTR_BKE;
+		if (dev->breakinput_polarity)
+			bdtr |= TIM_BDTR_BKP;
+	}
+
+	regmap_update_bits(dev->regmap, TIM_BDTR,
+			   TIM_BDTR_MOE | TIM_BDTR_AOE |
+			   TIM_BDTR_BKP | TIM_BDTR_BKE,
+			   bdtr);
+
+	return 0;
+}
+
+static int stm32_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
+				  enum pwm_polarity polarity)
+{
+	u32 mask;
+	struct stm32_pwm_dev *dev = to_stm32_pwm_dev(chip);
+
+	mask = TIM_CCER_CC1P << (pwm->hwpwm * 4);
+	if (dev->cfg->caps & CAP_COMPLEMENTARY)
+		mask |= TIM_CCER_CC1NP << (pwm->hwpwm * 4);
+
+	regmap_update_bits(dev->regmap, TIM_CCER, mask,
+			   polarity == PWM_POLARITY_NORMAL ? 0 : mask);
+
+	return 0;
+}
+
+static int stm32_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	u32 mask;
+	struct stm32_pwm_dev *dev = to_stm32_pwm_dev(chip);
+
+	clk_enable(dev->clk);
+
+	/* Enable channel */
+	mask = TIM_CCER_CC1E << (pwm->hwpwm * 4);
+	if (dev->cfg->caps & CAP_COMPLEMENTARY)
+		mask |= TIM_CCER_CC1NE << (pwm->hwpwm * 4);
+
+	regmap_update_bits(dev->regmap, TIM_CCER, mask, mask);
+
+	/* Make sure that registers are updated */
+	regmap_update_bits(dev->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG);
+
+	/* Enable controller */
+	regmap_update_bits(dev->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN);
+
+	return 0;
+}
+
+static void stm32_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	u32 mask;
+	struct stm32_pwm_dev *dev = to_stm32_pwm_dev(chip);
+
+	/* Disable channel */
+	mask = TIM_CCER_CC1E << (pwm->hwpwm * 4);
+	if (dev->cfg->caps & CAP_COMPLEMENTARY)
+		mask |= TIM_CCER_CC1NE << (pwm->hwpwm * 4);
+
+	regmap_update_bits(dev->regmap, TIM_CCER, mask, 0);
+
+	/* When all channels are disabled, we can disable the controller */
+	if (!__active_channels(dev))
+		regmap_update_bits(dev->regmap, TIM_CR1, TIM_CR1_CEN, 0);
+
+	clk_disable(dev->clk);
+}
+
+static const struct pwm_ops stm32pwm_ops = {
+	.config = stm32_pwm_config,
+	.set_polarity = stm32_pwm_set_polarity,
+	.enable = stm32_pwm_enable,
+	.disable = stm32_pwm_disable,
+};
+
+static const struct of_device_id stm32_pwm_of_match[] = {
+	{
+		.compatible = "st,stm32-pwm1",
+		.data = &f4_pwm_cfg[0],
+	},
+	{
+		.compatible = "st,stm32-pwm2",
+		.data = &f4_pwm_cfg[1],
+	},
+	{
+		.compatible = "st,stm32-pwm3",
+		.data = &f4_pwm_cfg[2],
+	},
+	{
+		.compatible = "st,stm32-pwm4",
+		.data = &f4_pwm_cfg[2],
+	},
+	{
+		.compatible = "st,stm32-pwm5",
+		.data = &f4_pwm_cfg[1],
+	},
+	{
+		.compatible = "st,stm32-pwm8",
+		.data = &f4_pwm_cfg[0],
+	},
+	{
+		.compatible = "st,stm32-pwm9",
+		.data = &f4_pwm_cfg[3],
+	},
+	{
+		.compatible = "st,stm32-pwm10",
+		.data = &f4_pwm_cfg[4],
+	},
+	{
+		.compatible = "st,stm32-pwm11",
+		.data = &f4_pwm_cfg[4],
+	},
+	{
+		.compatible = "st,stm32-pwm12",
+		.data = &f4_pwm_cfg[3],
+	},
+	{
+		.compatible = "st,stm32-pwm13",
+		.data = &f4_pwm_cfg[4],
+	},
+	{
+		.compatible = "st,stm32-pwm14",
+		.data = &f4_pwm_cfg[4],
+	},
+	{
+		/* end node */
+	},
+};
+MODULE_DEVICE_TABLE(of, stm32_pwm_of_match);
+
+static int stm32_pwm_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct stm32_mfd_timer_dev *mfd = pdev->dev.platform_data;
+	struct stm32_pwm_dev *pwm;
+	int ret;
+
+	pwm = devm_kzalloc(dev, sizeof(*pwm), GFP_KERNEL);
+	if (!pwm)
+		return -ENOMEM;
+
+	pwm->regmap = mfd->regmap;
+	pwm->clk = mfd->clk;
+
+	if (!pwm->regmap || !pwm->clk)
+		return -EINVAL;
+
+	/* populate data structure depending on compatibility */
+	if (!of_match_node(stm32_pwm_of_match, np)->data)
+		return -EINVAL;
+
+	pwm->cfg =
+	(struct stm32_pwm_cfg *)of_match_node(stm32_pwm_of_match, np)->data;
+
+	if (pwm->cfg->caps & CAP_BREAKINPUT) {
+		if (!of_property_read_u32(np, "st,breakinput-polarity",
+					  &pwm->breakinput_polarity))
+			pwm->have_breakinput = true;
+	}
+
+	pwm->chip.base = -1;
+	pwm->chip.dev = dev;
+	pwm->chip.ops = &stm32pwm_ops;
+	pwm->chip.npwm = pwm->cfg->npwm;
+
+	ret = pwmchip_add(&pwm->chip);
+	if (ret < 0)
+		return ret;
+
+	platform_set_drvdata(pdev, pwm);
+
+	return 0;
+}
+
+static int stm32_pwm_remove(struct platform_device *pdev)
+{
+	struct stm32_pwm_dev *pwm = platform_get_drvdata(pdev);
+	int i;
+
+	for (i = 0; i < pwm->cfg->npwm; i++)
+		pwm_disable(&pwm->chip.pwms[i]);
+
+	pwmchip_remove(&pwm->chip);
+
+	return 0;
+}
+
+static struct platform_driver stm32_pwm_driver = {
+	.probe		= stm32_pwm_probe,
+	.remove		= stm32_pwm_remove,
+	.driver	= {
+		.name	= DRIVER_NAME,
+		.of_match_table = stm32_pwm_of_match,
+	},
+};
+module_platform_driver(stm32_pwm_driver);
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_DESCRIPTION("STMicroelectronics STM32 PWM driver");
+MODULE_LICENSE("GPL");
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 4/7] add pwm driver for stm32 plaftorm
@ 2016-11-22 16:13   ` Benjamin Gaignard
  0 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-22 16:13 UTC (permalink / raw)
  To: lee.jones-QSEj5FYQhm4dnm+yROfE0A, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, alexandre.torgue-qxv4g6HH51o,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	linux-pwm-u79uwXL29TY76Z2rM5mHXA, jic23-DgEjT+Ai2ygdnm+yROfE0A,
	knaack.h-Mmb7MZpHnFY, lars-Qo5EllUWu/uELgA04lAiVw,
	pmeerw-jW+XmwGofnusTnJN9+BGXg, linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: fabrice.gasnier-qxv4g6HH51o, gerald.baeza-qxv4g6HH51o,
	arnaud.pouliquen-qxv4g6HH51o,
	linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
	linaro-kernel-cunTk1MwBs8s++Sfvej+rw, Benjamin Gaignard

This driver add support for pwm driver on stm32 platform.
The SoC have multiple instances of the hardware IP and each
of them could have small differences: number of channels,
complementary output, counter register size...
To handle those variations each block have its own compatible
linked to internal table that describe them.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard-qxv4g6HH51o@public.gmane.org>
---
 drivers/pwm/Kconfig     |   8 ++
 drivers/pwm/Makefile    |   1 +
 drivers/pwm/pwm-stm32.c | 358 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 367 insertions(+)
 create mode 100644 drivers/pwm/pwm-stm32.c

diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index bf01288..aeee045 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -388,6 +388,14 @@ config PWM_STI
 	  To compile this driver as a module, choose M here: the module
 	  will be called pwm-sti.
 
+config PWM_STM32
+	bool "STMicroelectronics STM32 PWM"
+	depends on ARCH_STM32
+	depends on OF
+	select MFD_STM32_TIMER
+	help
+	  Generic PWM framework driver for STM32 SoCs.
+
 config PWM_STMPE
 	bool "STMPE expander PWM export"
 	depends on MFD_STMPE
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 1194c54..5aa9308 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_PWM_ROCKCHIP)	+= pwm-rockchip.o
 obj-$(CONFIG_PWM_SAMSUNG)	+= pwm-samsung.o
 obj-$(CONFIG_PWM_SPEAR)		+= pwm-spear.o
 obj-$(CONFIG_PWM_STI)		+= pwm-sti.o
+obj-$(CONFIG_PWM_STM32)		+= pwm-stm32.o
 obj-$(CONFIG_PWM_STMPE)		+= pwm-stmpe.o
 obj-$(CONFIG_PWM_SUN4I)		+= pwm-sun4i.o
 obj-$(CONFIG_PWM_TEGRA)		+= pwm-tegra.o
diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c
new file mode 100644
index 0000000..2d71ee7
--- /dev/null
+++ b/drivers/pwm/pwm-stm32.c
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) STMicroelectronics 2016
+ * Author:  Gerald Baeza <gerald.baeza-qxv4g6HH51o@public.gmane.org>
+ * License terms:  GNU General Public License (GPL), version 2
+ *
+ * Inspired by timer-stm32.c from Maxime Coquelin
+ *             pwm-atmel.c from Bo Shen
+ */
+
+#include <linux/module.h>
+#include <linux/pwm.h>
+
+#include <linux/mfd/stm32-mfd-timer.h>
+
+#define DRIVER_NAME "stm32-pwm"
+
+#define CAP_COMPLEMENTARY	BIT(0)
+#define CAP_32BIT_COUNTER	BIT(1)
+#define CAP_BREAKINPUT		BIT(2)
+
+struct stm32_pwm_cfg {
+	int npwm;
+	int caps;
+};
+
+static struct stm32_pwm_cfg f4_pwm_cfg[] = {
+	/* for pwm 1 and 8 */
+	{
+		.npwm = 4,
+		.caps = CAP_COMPLEMENTARY | CAP_BREAKINPUT,
+	},
+	/* for pwm 2 and 5 */
+	{
+		.npwm = 4,
+		.caps = CAP_32BIT_COUNTER,
+	},
+	/* for pwm 3 and 4 */
+	{
+		.npwm = 4,
+		.caps = 0,
+	},
+	/* for pwm 9 and 12 */
+	{
+		.npwm = 2,
+		.caps = 0,
+	},
+	/* for pwm 10, 11, 13 and 14 */
+	{
+		.npwm = 1,
+		.caps = 0,
+	},
+};
+
+struct stm32_pwm_dev {
+	struct device *dev;
+	struct clk *clk;
+	struct regmap *regmap;
+	struct pwm_chip chip;
+	struct stm32_pwm_cfg *cfg;
+	bool have_breakinput;
+	u32 breakinput_polarity;
+};
+
+#define to_stm32_pwm_dev(x) container_of(chip, struct stm32_pwm_dev, chip)
+
+static u32 __active_channels(struct stm32_pwm_dev *pwm_dev)
+{
+	u32 ccer;
+
+	regmap_read(pwm_dev->regmap, TIM_CCER, &ccer);
+
+	return ccer & TIM_CCER_CCXE;
+}
+
+static int write_ccrx(struct stm32_pwm_dev *dev, struct pwm_device *pwm,
+		      u32 ccr)
+{
+	switch (pwm->hwpwm) {
+	case 0:
+		return regmap_write(dev->regmap, TIM_CCR1, ccr);
+	case 1:
+		return regmap_write(dev->regmap, TIM_CCR2, ccr);
+	case 2:
+		return regmap_write(dev->regmap, TIM_CCR3, ccr);
+	case 3:
+		return regmap_write(dev->regmap, TIM_CCR4, ccr);
+	}
+	return -EINVAL;
+}
+
+static int stm32_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+			    int duty_ns, int period_ns)
+{
+	struct stm32_pwm_dev *dev = to_stm32_pwm_dev(chip);
+	unsigned long long prd, div, dty;
+	int prescaler = 0;
+	u32 max_arr = 0xFFFF, ccmr, mask, shift, bdtr;
+
+	if (dev->cfg->caps & CAP_32BIT_COUNTER)
+		max_arr = 0xFFFFFFFF;
+
+	/* Period and prescaler values depends of clock rate */
+	div = (unsigned long long)clk_get_rate(dev->clk) * period_ns;
+
+	do_div(div, NSEC_PER_SEC);
+	prd = div;
+
+	while (div > max_arr) {
+		prescaler++;
+		div = prd;
+		do_div(div, (prescaler + 1));
+	}
+	prd = div;
+
+	if (prescaler > MAX_TIM_PSC) {
+		dev_err(chip->dev, "prescaler exceeds the maximum value\n");
+		return -EINVAL;
+	}
+
+	/* All channels share the same prescaler and counter so
+	 * when two channels are active at the same we can't change them
+	 */
+	if (__active_channels(dev) & ~(1 << pwm->hwpwm * 4)) {
+		u32 psc, arr;
+
+		regmap_read(dev->regmap, TIM_PSC, &psc);
+		regmap_read(dev->regmap, TIM_ARR, &arr);
+
+		if ((psc != prescaler) || (arr != prd - 1))
+			return -EINVAL;
+	}
+
+	regmap_write(dev->regmap, TIM_PSC, prescaler);
+	regmap_write(dev->regmap, TIM_ARR, prd - 1);
+	regmap_update_bits(dev->regmap, TIM_CR1, TIM_CR1_ARPE, TIM_CR1_ARPE);
+
+	/* Calculate the duty cycles */
+	dty = prd * duty_ns;
+	do_div(dty, period_ns);
+
+	write_ccrx(dev, pwm, dty);
+
+	/* Configure output mode */
+	shift = (pwm->hwpwm & 0x1) * 8;
+	ccmr = (TIM_CCMR_PE | TIM_CCMR_M1) << shift;
+	mask = 0xFF << shift;
+
+	if (pwm->hwpwm & 0x2)
+		regmap_update_bits(dev->regmap, TIM_CCMR2, mask, ccmr);
+	else
+		regmap_update_bits(dev->regmap, TIM_CCMR1, mask, ccmr);
+
+	bdtr = TIM_BDTR_MOE | TIM_BDTR_AOE;
+	if (dev->have_breakinput) {
+		bdtr |= TIM_BDTR_BKE;
+		if (dev->breakinput_polarity)
+			bdtr |= TIM_BDTR_BKP;
+	}
+
+	regmap_update_bits(dev->regmap, TIM_BDTR,
+			   TIM_BDTR_MOE | TIM_BDTR_AOE |
+			   TIM_BDTR_BKP | TIM_BDTR_BKE,
+			   bdtr);
+
+	return 0;
+}
+
+static int stm32_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
+				  enum pwm_polarity polarity)
+{
+	u32 mask;
+	struct stm32_pwm_dev *dev = to_stm32_pwm_dev(chip);
+
+	mask = TIM_CCER_CC1P << (pwm->hwpwm * 4);
+	if (dev->cfg->caps & CAP_COMPLEMENTARY)
+		mask |= TIM_CCER_CC1NP << (pwm->hwpwm * 4);
+
+	regmap_update_bits(dev->regmap, TIM_CCER, mask,
+			   polarity == PWM_POLARITY_NORMAL ? 0 : mask);
+
+	return 0;
+}
+
+static int stm32_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	u32 mask;
+	struct stm32_pwm_dev *dev = to_stm32_pwm_dev(chip);
+
+	clk_enable(dev->clk);
+
+	/* Enable channel */
+	mask = TIM_CCER_CC1E << (pwm->hwpwm * 4);
+	if (dev->cfg->caps & CAP_COMPLEMENTARY)
+		mask |= TIM_CCER_CC1NE << (pwm->hwpwm * 4);
+
+	regmap_update_bits(dev->regmap, TIM_CCER, mask, mask);
+
+	/* Make sure that registers are updated */
+	regmap_update_bits(dev->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG);
+
+	/* Enable controller */
+	regmap_update_bits(dev->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN);
+
+	return 0;
+}
+
+static void stm32_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	u32 mask;
+	struct stm32_pwm_dev *dev = to_stm32_pwm_dev(chip);
+
+	/* Disable channel */
+	mask = TIM_CCER_CC1E << (pwm->hwpwm * 4);
+	if (dev->cfg->caps & CAP_COMPLEMENTARY)
+		mask |= TIM_CCER_CC1NE << (pwm->hwpwm * 4);
+
+	regmap_update_bits(dev->regmap, TIM_CCER, mask, 0);
+
+	/* When all channels are disabled, we can disable the controller */
+	if (!__active_channels(dev))
+		regmap_update_bits(dev->regmap, TIM_CR1, TIM_CR1_CEN, 0);
+
+	clk_disable(dev->clk);
+}
+
+static const struct pwm_ops stm32pwm_ops = {
+	.config = stm32_pwm_config,
+	.set_polarity = stm32_pwm_set_polarity,
+	.enable = stm32_pwm_enable,
+	.disable = stm32_pwm_disable,
+};
+
+static const struct of_device_id stm32_pwm_of_match[] = {
+	{
+		.compatible = "st,stm32-pwm1",
+		.data = &f4_pwm_cfg[0],
+	},
+	{
+		.compatible = "st,stm32-pwm2",
+		.data = &f4_pwm_cfg[1],
+	},
+	{
+		.compatible = "st,stm32-pwm3",
+		.data = &f4_pwm_cfg[2],
+	},
+	{
+		.compatible = "st,stm32-pwm4",
+		.data = &f4_pwm_cfg[2],
+	},
+	{
+		.compatible = "st,stm32-pwm5",
+		.data = &f4_pwm_cfg[1],
+	},
+	{
+		.compatible = "st,stm32-pwm8",
+		.data = &f4_pwm_cfg[0],
+	},
+	{
+		.compatible = "st,stm32-pwm9",
+		.data = &f4_pwm_cfg[3],
+	},
+	{
+		.compatible = "st,stm32-pwm10",
+		.data = &f4_pwm_cfg[4],
+	},
+	{
+		.compatible = "st,stm32-pwm11",
+		.data = &f4_pwm_cfg[4],
+	},
+	{
+		.compatible = "st,stm32-pwm12",
+		.data = &f4_pwm_cfg[3],
+	},
+	{
+		.compatible = "st,stm32-pwm13",
+		.data = &f4_pwm_cfg[4],
+	},
+	{
+		.compatible = "st,stm32-pwm14",
+		.data = &f4_pwm_cfg[4],
+	},
+	{
+		/* end node */
+	},
+};
+MODULE_DEVICE_TABLE(of, stm32_pwm_of_match);
+
+static int stm32_pwm_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct stm32_mfd_timer_dev *mfd = pdev->dev.platform_data;
+	struct stm32_pwm_dev *pwm;
+	int ret;
+
+	pwm = devm_kzalloc(dev, sizeof(*pwm), GFP_KERNEL);
+	if (!pwm)
+		return -ENOMEM;
+
+	pwm->regmap = mfd->regmap;
+	pwm->clk = mfd->clk;
+
+	if (!pwm->regmap || !pwm->clk)
+		return -EINVAL;
+
+	/* populate data structure depending on compatibility */
+	if (!of_match_node(stm32_pwm_of_match, np)->data)
+		return -EINVAL;
+
+	pwm->cfg =
+	(struct stm32_pwm_cfg *)of_match_node(stm32_pwm_of_match, np)->data;
+
+	if (pwm->cfg->caps & CAP_BREAKINPUT) {
+		if (!of_property_read_u32(np, "st,breakinput-polarity",
+					  &pwm->breakinput_polarity))
+			pwm->have_breakinput = true;
+	}
+
+	pwm->chip.base = -1;
+	pwm->chip.dev = dev;
+	pwm->chip.ops = &stm32pwm_ops;
+	pwm->chip.npwm = pwm->cfg->npwm;
+
+	ret = pwmchip_add(&pwm->chip);
+	if (ret < 0)
+		return ret;
+
+	platform_set_drvdata(pdev, pwm);
+
+	return 0;
+}
+
+static int stm32_pwm_remove(struct platform_device *pdev)
+{
+	struct stm32_pwm_dev *pwm = platform_get_drvdata(pdev);
+	int i;
+
+	for (i = 0; i < pwm->cfg->npwm; i++)
+		pwm_disable(&pwm->chip.pwms[i]);
+
+	pwmchip_remove(&pwm->chip);
+
+	return 0;
+}
+
+static struct platform_driver stm32_pwm_driver = {
+	.probe		= stm32_pwm_probe,
+	.remove		= stm32_pwm_remove,
+	.driver	= {
+		.name	= DRIVER_NAME,
+		.of_match_table = stm32_pwm_of_match,
+	},
+};
+module_platform_driver(stm32_pwm_driver);
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_DESCRIPTION("STMicroelectronics STM32 PWM driver");
+MODULE_LICENSE("GPL");
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 4/7] add pwm driver for stm32 plaftorm
@ 2016-11-22 16:13   ` Benjamin Gaignard
  0 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-22 16:13 UTC (permalink / raw)
  To: linux-arm-kernel

This driver add support for pwm driver on stm32 platform.
The SoC have multiple instances of the hardware IP and each
of them could have small differences: number of channels,
complementary output, counter register size...
To handle those variations each block have its own compatible
linked to internal table that describe them.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
---
 drivers/pwm/Kconfig     |   8 ++
 drivers/pwm/Makefile    |   1 +
 drivers/pwm/pwm-stm32.c | 358 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 367 insertions(+)
 create mode 100644 drivers/pwm/pwm-stm32.c

diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index bf01288..aeee045 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -388,6 +388,14 @@ config PWM_STI
 	  To compile this driver as a module, choose M here: the module
 	  will be called pwm-sti.
 
+config PWM_STM32
+	bool "STMicroelectronics STM32 PWM"
+	depends on ARCH_STM32
+	depends on OF
+	select MFD_STM32_TIMER
+	help
+	  Generic PWM framework driver for STM32 SoCs.
+
 config PWM_STMPE
 	bool "STMPE expander PWM export"
 	depends on MFD_STMPE
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 1194c54..5aa9308 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_PWM_ROCKCHIP)	+= pwm-rockchip.o
 obj-$(CONFIG_PWM_SAMSUNG)	+= pwm-samsung.o
 obj-$(CONFIG_PWM_SPEAR)		+= pwm-spear.o
 obj-$(CONFIG_PWM_STI)		+= pwm-sti.o
+obj-$(CONFIG_PWM_STM32)		+= pwm-stm32.o
 obj-$(CONFIG_PWM_STMPE)		+= pwm-stmpe.o
 obj-$(CONFIG_PWM_SUN4I)		+= pwm-sun4i.o
 obj-$(CONFIG_PWM_TEGRA)		+= pwm-tegra.o
diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c
new file mode 100644
index 0000000..2d71ee7
--- /dev/null
+++ b/drivers/pwm/pwm-stm32.c
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) STMicroelectronics 2016
+ * Author:  Gerald Baeza <gerald.baeza@st.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ *
+ * Inspired by timer-stm32.c from Maxime Coquelin
+ *             pwm-atmel.c from Bo Shen
+ */
+
+#include <linux/module.h>
+#include <linux/pwm.h>
+
+#include <linux/mfd/stm32-mfd-timer.h>
+
+#define DRIVER_NAME "stm32-pwm"
+
+#define CAP_COMPLEMENTARY	BIT(0)
+#define CAP_32BIT_COUNTER	BIT(1)
+#define CAP_BREAKINPUT		BIT(2)
+
+struct stm32_pwm_cfg {
+	int npwm;
+	int caps;
+};
+
+static struct stm32_pwm_cfg f4_pwm_cfg[] = {
+	/* for pwm 1 and 8 */
+	{
+		.npwm = 4,
+		.caps = CAP_COMPLEMENTARY | CAP_BREAKINPUT,
+	},
+	/* for pwm 2 and 5 */
+	{
+		.npwm = 4,
+		.caps = CAP_32BIT_COUNTER,
+	},
+	/* for pwm 3 and 4 */
+	{
+		.npwm = 4,
+		.caps = 0,
+	},
+	/* for pwm 9 and 12 */
+	{
+		.npwm = 2,
+		.caps = 0,
+	},
+	/* for pwm 10, 11, 13 and 14 */
+	{
+		.npwm = 1,
+		.caps = 0,
+	},
+};
+
+struct stm32_pwm_dev {
+	struct device *dev;
+	struct clk *clk;
+	struct regmap *regmap;
+	struct pwm_chip chip;
+	struct stm32_pwm_cfg *cfg;
+	bool have_breakinput;
+	u32 breakinput_polarity;
+};
+
+#define to_stm32_pwm_dev(x) container_of(chip, struct stm32_pwm_dev, chip)
+
+static u32 __active_channels(struct stm32_pwm_dev *pwm_dev)
+{
+	u32 ccer;
+
+	regmap_read(pwm_dev->regmap, TIM_CCER, &ccer);
+
+	return ccer & TIM_CCER_CCXE;
+}
+
+static int write_ccrx(struct stm32_pwm_dev *dev, struct pwm_device *pwm,
+		      u32 ccr)
+{
+	switch (pwm->hwpwm) {
+	case 0:
+		return regmap_write(dev->regmap, TIM_CCR1, ccr);
+	case 1:
+		return regmap_write(dev->regmap, TIM_CCR2, ccr);
+	case 2:
+		return regmap_write(dev->regmap, TIM_CCR3, ccr);
+	case 3:
+		return regmap_write(dev->regmap, TIM_CCR4, ccr);
+	}
+	return -EINVAL;
+}
+
+static int stm32_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+			    int duty_ns, int period_ns)
+{
+	struct stm32_pwm_dev *dev = to_stm32_pwm_dev(chip);
+	unsigned long long prd, div, dty;
+	int prescaler = 0;
+	u32 max_arr = 0xFFFF, ccmr, mask, shift, bdtr;
+
+	if (dev->cfg->caps & CAP_32BIT_COUNTER)
+		max_arr = 0xFFFFFFFF;
+
+	/* Period and prescaler values depends of clock rate */
+	div = (unsigned long long)clk_get_rate(dev->clk) * period_ns;
+
+	do_div(div, NSEC_PER_SEC);
+	prd = div;
+
+	while (div > max_arr) {
+		prescaler++;
+		div = prd;
+		do_div(div, (prescaler + 1));
+	}
+	prd = div;
+
+	if (prescaler > MAX_TIM_PSC) {
+		dev_err(chip->dev, "prescaler exceeds the maximum value\n");
+		return -EINVAL;
+	}
+
+	/* All channels share the same prescaler and counter so
+	 * when two channels are active at the same we can't change them
+	 */
+	if (__active_channels(dev) & ~(1 << pwm->hwpwm * 4)) {
+		u32 psc, arr;
+
+		regmap_read(dev->regmap, TIM_PSC, &psc);
+		regmap_read(dev->regmap, TIM_ARR, &arr);
+
+		if ((psc != prescaler) || (arr != prd - 1))
+			return -EINVAL;
+	}
+
+	regmap_write(dev->regmap, TIM_PSC, prescaler);
+	regmap_write(dev->regmap, TIM_ARR, prd - 1);
+	regmap_update_bits(dev->regmap, TIM_CR1, TIM_CR1_ARPE, TIM_CR1_ARPE);
+
+	/* Calculate the duty cycles */
+	dty = prd * duty_ns;
+	do_div(dty, period_ns);
+
+	write_ccrx(dev, pwm, dty);
+
+	/* Configure output mode */
+	shift = (pwm->hwpwm & 0x1) * 8;
+	ccmr = (TIM_CCMR_PE | TIM_CCMR_M1) << shift;
+	mask = 0xFF << shift;
+
+	if (pwm->hwpwm & 0x2)
+		regmap_update_bits(dev->regmap, TIM_CCMR2, mask, ccmr);
+	else
+		regmap_update_bits(dev->regmap, TIM_CCMR1, mask, ccmr);
+
+	bdtr = TIM_BDTR_MOE | TIM_BDTR_AOE;
+	if (dev->have_breakinput) {
+		bdtr |= TIM_BDTR_BKE;
+		if (dev->breakinput_polarity)
+			bdtr |= TIM_BDTR_BKP;
+	}
+
+	regmap_update_bits(dev->regmap, TIM_BDTR,
+			   TIM_BDTR_MOE | TIM_BDTR_AOE |
+			   TIM_BDTR_BKP | TIM_BDTR_BKE,
+			   bdtr);
+
+	return 0;
+}
+
+static int stm32_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
+				  enum pwm_polarity polarity)
+{
+	u32 mask;
+	struct stm32_pwm_dev *dev = to_stm32_pwm_dev(chip);
+
+	mask = TIM_CCER_CC1P << (pwm->hwpwm * 4);
+	if (dev->cfg->caps & CAP_COMPLEMENTARY)
+		mask |= TIM_CCER_CC1NP << (pwm->hwpwm * 4);
+
+	regmap_update_bits(dev->regmap, TIM_CCER, mask,
+			   polarity == PWM_POLARITY_NORMAL ? 0 : mask);
+
+	return 0;
+}
+
+static int stm32_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	u32 mask;
+	struct stm32_pwm_dev *dev = to_stm32_pwm_dev(chip);
+
+	clk_enable(dev->clk);
+
+	/* Enable channel */
+	mask = TIM_CCER_CC1E << (pwm->hwpwm * 4);
+	if (dev->cfg->caps & CAP_COMPLEMENTARY)
+		mask |= TIM_CCER_CC1NE << (pwm->hwpwm * 4);
+
+	regmap_update_bits(dev->regmap, TIM_CCER, mask, mask);
+
+	/* Make sure that registers are updated */
+	regmap_update_bits(dev->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG);
+
+	/* Enable controller */
+	regmap_update_bits(dev->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN);
+
+	return 0;
+}
+
+static void stm32_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	u32 mask;
+	struct stm32_pwm_dev *dev = to_stm32_pwm_dev(chip);
+
+	/* Disable channel */
+	mask = TIM_CCER_CC1E << (pwm->hwpwm * 4);
+	if (dev->cfg->caps & CAP_COMPLEMENTARY)
+		mask |= TIM_CCER_CC1NE << (pwm->hwpwm * 4);
+
+	regmap_update_bits(dev->regmap, TIM_CCER, mask, 0);
+
+	/* When all channels are disabled, we can disable the controller */
+	if (!__active_channels(dev))
+		regmap_update_bits(dev->regmap, TIM_CR1, TIM_CR1_CEN, 0);
+
+	clk_disable(dev->clk);
+}
+
+static const struct pwm_ops stm32pwm_ops = {
+	.config = stm32_pwm_config,
+	.set_polarity = stm32_pwm_set_polarity,
+	.enable = stm32_pwm_enable,
+	.disable = stm32_pwm_disable,
+};
+
+static const struct of_device_id stm32_pwm_of_match[] = {
+	{
+		.compatible = "st,stm32-pwm1",
+		.data = &f4_pwm_cfg[0],
+	},
+	{
+		.compatible = "st,stm32-pwm2",
+		.data = &f4_pwm_cfg[1],
+	},
+	{
+		.compatible = "st,stm32-pwm3",
+		.data = &f4_pwm_cfg[2],
+	},
+	{
+		.compatible = "st,stm32-pwm4",
+		.data = &f4_pwm_cfg[2],
+	},
+	{
+		.compatible = "st,stm32-pwm5",
+		.data = &f4_pwm_cfg[1],
+	},
+	{
+		.compatible = "st,stm32-pwm8",
+		.data = &f4_pwm_cfg[0],
+	},
+	{
+		.compatible = "st,stm32-pwm9",
+		.data = &f4_pwm_cfg[3],
+	},
+	{
+		.compatible = "st,stm32-pwm10",
+		.data = &f4_pwm_cfg[4],
+	},
+	{
+		.compatible = "st,stm32-pwm11",
+		.data = &f4_pwm_cfg[4],
+	},
+	{
+		.compatible = "st,stm32-pwm12",
+		.data = &f4_pwm_cfg[3],
+	},
+	{
+		.compatible = "st,stm32-pwm13",
+		.data = &f4_pwm_cfg[4],
+	},
+	{
+		.compatible = "st,stm32-pwm14",
+		.data = &f4_pwm_cfg[4],
+	},
+	{
+		/* end node */
+	},
+};
+MODULE_DEVICE_TABLE(of, stm32_pwm_of_match);
+
+static int stm32_pwm_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct stm32_mfd_timer_dev *mfd = pdev->dev.platform_data;
+	struct stm32_pwm_dev *pwm;
+	int ret;
+
+	pwm = devm_kzalloc(dev, sizeof(*pwm), GFP_KERNEL);
+	if (!pwm)
+		return -ENOMEM;
+
+	pwm->regmap = mfd->regmap;
+	pwm->clk = mfd->clk;
+
+	if (!pwm->regmap || !pwm->clk)
+		return -EINVAL;
+
+	/* populate data structure depending on compatibility */
+	if (!of_match_node(stm32_pwm_of_match, np)->data)
+		return -EINVAL;
+
+	pwm->cfg =
+	(struct stm32_pwm_cfg *)of_match_node(stm32_pwm_of_match, np)->data;
+
+	if (pwm->cfg->caps & CAP_BREAKINPUT) {
+		if (!of_property_read_u32(np, "st,breakinput-polarity",
+					  &pwm->breakinput_polarity))
+			pwm->have_breakinput = true;
+	}
+
+	pwm->chip.base = -1;
+	pwm->chip.dev = dev;
+	pwm->chip.ops = &stm32pwm_ops;
+	pwm->chip.npwm = pwm->cfg->npwm;
+
+	ret = pwmchip_add(&pwm->chip);
+	if (ret < 0)
+		return ret;
+
+	platform_set_drvdata(pdev, pwm);
+
+	return 0;
+}
+
+static int stm32_pwm_remove(struct platform_device *pdev)
+{
+	struct stm32_pwm_dev *pwm = platform_get_drvdata(pdev);
+	int i;
+
+	for (i = 0; i < pwm->cfg->npwm; i++)
+		pwm_disable(&pwm->chip.pwms[i]);
+
+	pwmchip_remove(&pwm->chip);
+
+	return 0;
+}
+
+static struct platform_driver stm32_pwm_driver = {
+	.probe		= stm32_pwm_probe,
+	.remove		= stm32_pwm_remove,
+	.driver	= {
+		.name	= DRIVER_NAME,
+		.of_match_table = stm32_pwm_of_match,
+	},
+};
+module_platform_driver(stm32_pwm_driver);
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_DESCRIPTION("STMicroelectronics STM32 PWM driver");
+MODULE_LICENSE("GPL");
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 5/7] add bindings for stm32 IIO timer drivers
  2016-11-22 16:13 ` Benjamin Gaignard
@ 2016-11-22 16:13   ` Benjamin Gaignard
  -1 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-22 16:13 UTC (permalink / raw)
  To: lee.jones, robh+dt, mark.rutland, alexandre.torgue, devicetree,
	linux-kernel, thierry.reding, linux-pwm, jic23, knaack.h, lars,
	pmeerw, linux-iio, linux-arm-kernel
  Cc: fabrice.gasnier, gerald.baeza, arnaud.pouliquen, linus.walleij,
	linaro-kernel, Benjamin Gaignard

Define bindings for stm32 IIO timer

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
---
 .../bindings/iio/timer/stm32-iio-timer.txt         | 33 ++++++++++++++++++++++
 1 file changed, 33 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt

diff --git a/Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt b/Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt
new file mode 100644
index 0000000..b80025e
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt
@@ -0,0 +1,33 @@
+timer IIO trigger bindings for STM32
+
+Must be a child of STM32 multifunctions timer driver
+
+Required parameters:
+- compatible: must be one of the follow value:
+	"st,stm32-iio-timer1"
+	"st,stm32-iio-timer2"
+	"st,stm32-iio-timer3"
+	"st,stm32-iio-timer4"
+	"st,stm32-iio-timer5"
+	"st,stm32-iio-timer6"
+	"st,stm32-iio-timer7"
+	"st,stm32-iio-timer8"
+	"st,stm32-iio-timer9"
+	"st,stm32-iio-timer10"
+	"st,stm32-iio-timer11"
+	"st,stm32-iio-timer12"
+	"st,stm32-iio-timer13"
+	"st,stm32-iio-timer14"
+
+Example:
+	mfd_timer1: mfdtimer1@40010000 {
+		compatible = "st,stm32-mfd-timer1";
+		reg = <0x40010000 0x400>;
+		clocks = <&rcc 0 160>;
+		clock-names = "mfd_timer_clk";
+		interrupts = <27>;
+
+		trigger1: trigger1@40010000 {
+			compatible = "st,stm32-iio-timer1";
+		};
+	};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 5/7] add bindings for stm32 IIO timer drivers
@ 2016-11-22 16:13   ` Benjamin Gaignard
  0 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-22 16:13 UTC (permalink / raw)
  To: linux-arm-kernel

Define bindings for stm32 IIO timer

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
---
 .../bindings/iio/timer/stm32-iio-timer.txt         | 33 ++++++++++++++++++++++
 1 file changed, 33 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt

diff --git a/Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt b/Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt
new file mode 100644
index 0000000..b80025e
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt
@@ -0,0 +1,33 @@
+timer IIO trigger bindings for STM32
+
+Must be a child of STM32 multifunctions timer driver
+
+Required parameters:
+- compatible: must be one of the follow value:
+	"st,stm32-iio-timer1"
+	"st,stm32-iio-timer2"
+	"st,stm32-iio-timer3"
+	"st,stm32-iio-timer4"
+	"st,stm32-iio-timer5"
+	"st,stm32-iio-timer6"
+	"st,stm32-iio-timer7"
+	"st,stm32-iio-timer8"
+	"st,stm32-iio-timer9"
+	"st,stm32-iio-timer10"
+	"st,stm32-iio-timer11"
+	"st,stm32-iio-timer12"
+	"st,stm32-iio-timer13"
+	"st,stm32-iio-timer14"
+
+Example:
+	mfd_timer1: mfdtimer1 at 40010000 {
+		compatible = "st,stm32-mfd-timer1";
+		reg = <0x40010000 0x400>;
+		clocks = <&rcc 0 160>;
+		clock-names = "mfd_timer_clk";
+		interrupts = <27>;
+
+		trigger1: trigger1 at 40010000 {
+			compatible = "st,stm32-iio-timer1";
+		};
+	};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 6/7] add STM32 IIO timer driver
  2016-11-22 16:13 ` Benjamin Gaignard
@ 2016-11-22 16:13   ` Benjamin Gaignard
  -1 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-22 16:13 UTC (permalink / raw)
  To: lee.jones, robh+dt, mark.rutland, alexandre.torgue, devicetree,
	linux-kernel, thierry.reding, linux-pwm, jic23, knaack.h, lars,
	pmeerw, linux-iio, linux-arm-kernel
  Cc: fabrice.gasnier, gerald.baeza, arnaud.pouliquen, linus.walleij,
	linaro-kernel, Benjamin Gaignard

Timers IPs can be used to generate triggers for other IPs like
DAC, ADC or other timers.
Each trigger may result of timer internals signals like counter enable,
reset or edge, this configuration could be done through "master_mode"
device attribute.

A timer device could be triggered by other timers, we use the trigger
name and is_stm32_iio_timer_trigger() function to distinguish them
and configure IP input switch.

Timer may also decide on which event (edge, level) they could
be activated by a trigger, this configuration is done by writing in
"slave_mode" device attribute.

Since triggers could also be used by DAC or ADC their names are defined
in include/linux/iio/timer/stm32-iio-timers.h so those IPs will be able
to configure themselves in valid_trigger function

Trigger have a "sampling_frequency" attribute which allow to configure
timer sampling frequency without using pwm interface

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
---
 drivers/iio/Kconfig                        |   2 +-
 drivers/iio/Makefile                       |   1 +
 drivers/iio/timer/Kconfig                  |  15 +
 drivers/iio/timer/Makefile                 |   1 +
 drivers/iio/timer/stm32-iio-timer.c        | 766 +++++++++++++++++++++++++++++
 drivers/iio/trigger/Kconfig                |   1 -
 include/linux/iio/timer/stm32-iio-timers.h |  25 +
 7 files changed, 809 insertions(+), 2 deletions(-)
 create mode 100644 drivers/iio/timer/Kconfig
 create mode 100644 drivers/iio/timer/Makefile
 create mode 100644 drivers/iio/timer/stm32-iio-timer.c
 create mode 100644 include/linux/iio/timer/stm32-iio-timers.h

diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index 6743b18..2de2a80 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -90,5 +90,5 @@ source "drivers/iio/potentiometer/Kconfig"
 source "drivers/iio/pressure/Kconfig"
 source "drivers/iio/proximity/Kconfig"
 source "drivers/iio/temperature/Kconfig"
-
+source "drivers/iio/timer/Kconfig"
 endif # IIO
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index 87e4c43..b797c08 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -32,4 +32,5 @@ obj-y += potentiometer/
 obj-y += pressure/
 obj-y += proximity/
 obj-y += temperature/
+obj-y += timer/
 obj-y += trigger/
diff --git a/drivers/iio/timer/Kconfig b/drivers/iio/timer/Kconfig
new file mode 100644
index 0000000..55764e8
--- /dev/null
+++ b/drivers/iio/timer/Kconfig
@@ -0,0 +1,15 @@
+#
+# Timers drivers
+
+menu "Timers"
+
+config IIO_STM32_TIMER
+	tristate "stm32 iio timer"
+	depends on ARCH_STM32
+	depends on OF
+	select IIO_TRIGGERED_EVENT
+	select MFD_STM32_TIMER
+	help
+	  Select this option to enable stm32 timers hardware IPs
+
+endmenu
diff --git a/drivers/iio/timer/Makefile b/drivers/iio/timer/Makefile
new file mode 100644
index 0000000..a360c9f
--- /dev/null
+++ b/drivers/iio/timer/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_IIO_STM32_TIMER) += stm32-iio-timer.o
diff --git a/drivers/iio/timer/stm32-iio-timer.c b/drivers/iio/timer/stm32-iio-timer.c
new file mode 100644
index 0000000..a1d54c4
--- /dev/null
+++ b/drivers/iio/timer/stm32-iio-timer.c
@@ -0,0 +1,766 @@
+/*
+ * stm32-iio-timer.c
+ *
+ * Copyright (C) STMicroelectronics 2016
+ * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/timer/stm32-iio-timers.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/triggered_event.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/stm32-mfd-timer.h>
+#include <linux/module.h>
+
+#define DRIVER_NAME "stm32-iio-timer"
+
+struct stm32_trigger {
+	const char *name;
+};
+
+struct stm32_valid_trigger {
+	const char *name;
+	int ts_value;
+};
+
+struct stm32_trig_cfg {
+	const struct stm32_trigger *triggers;
+	int nb_triggers;
+	const struct stm32_valid_trigger *valids;
+	int nb_valids;
+};
+
+struct stm32_iio_timer_dev {
+	struct device *dev;
+	struct regmap *regmap;
+	struct clk *clk;
+	int irq;
+	struct stm32_trig_cfg *cfg;
+	bool own_timer;
+	unsigned int sampling_frequency;
+	struct iio_trigger *active_trigger;
+};
+
+static ssize_t _store_frequency(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t len)
+{
+	struct iio_trigger *trig = to_iio_trigger(dev);
+	struct stm32_iio_timer_dev *stm32 = iio_trigger_get_drvdata(trig);
+	unsigned int freq;
+	int ret;
+
+	ret = kstrtouint(buf, 10, &freq);
+	if (ret)
+		return ret;
+
+	stm32->sampling_frequency = freq;
+
+	return len;
+}
+
+static ssize_t _read_frequency(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct iio_trigger *trig = to_iio_trigger(dev);
+	struct stm32_iio_timer_dev *stm32 = iio_trigger_get_drvdata(trig);
+	unsigned long long freq = stm32->sampling_frequency;
+	u32 psc, arr, cr1;
+
+	regmap_read(stm32->regmap, TIM_CR1, &cr1);
+	regmap_read(stm32->regmap, TIM_PSC, &psc);
+	regmap_read(stm32->regmap, TIM_ARR, &arr);
+
+	if (psc && arr && (cr1 & TIM_CR1_CEN)) {
+		freq = (unsigned long long)clk_get_rate(stm32->clk);
+		do_div(freq, psc);
+		do_div(freq, arr);
+	}
+
+	return sprintf(buf, "%d\n", (unsigned int) freq);
+}
+
+static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
+			      _read_frequency,
+			      _store_frequency);
+
+static struct attribute *stm32_trigger_attrs[] = {
+	&iio_dev_attr_sampling_frequency.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group stm32_trigger_attr_group = {
+	.attrs = stm32_trigger_attrs,
+};
+
+static const struct attribute_group *stm32_trigger_attr_groups[] = {
+	&stm32_trigger_attr_group,
+	NULL,
+};
+
+static
+ssize_t _show_master_mode(struct device *dev,
+			  struct device_attribute *attr, char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct stm32_iio_timer_dev *stm32 = iio_priv(indio_dev);
+	u32 cr2;
+
+	regmap_read(stm32->regmap, TIM_CR2, &cr2);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", (cr2 >> 4) & 0x7);
+}
+
+static
+ssize_t _store_master_mode(struct device *dev,
+			   struct device_attribute *attr,
+			   const char *buf, size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct stm32_iio_timer_dev *stm32 = iio_priv(indio_dev);
+	u8 mode;
+	int ret;
+
+	ret = kstrtou8(buf, 10, &mode);
+	if (ret)
+		return ret;
+
+	if (mode > 0x7)
+		return -EINVAL;
+
+	regmap_update_bits(stm32->regmap, TIM_CR2, TIM_CR2_MMS, mode << 4);
+
+	return len;
+}
+
+static IIO_DEVICE_ATTR(master_mode, S_IRUGO | S_IWUSR,
+		       _show_master_mode,
+		       _store_master_mode,
+		       0);
+
+static
+ssize_t _show_slave_mode(struct device *dev,
+			 struct device_attribute *attr, char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct stm32_iio_timer_dev *stm32 = iio_priv(indio_dev);
+	u32 smcr;
+
+	regmap_read(stm32->regmap, TIM_SMCR, &smcr);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", smcr & 0x3);
+}
+
+static
+ssize_t _store_slave_mode(struct device *dev,
+			  struct device_attribute *attr,
+			  const char *buf, size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct stm32_iio_timer_dev *stm32 = iio_priv(indio_dev);
+	u8 mode;
+	int ret;
+
+	ret = kstrtou8(buf, 10, &mode);
+	if (ret)
+		return ret;
+
+	if (mode > 0x7)
+		return -EINVAL;
+
+	regmap_update_bits(stm32->regmap, TIM_SMCR, TIM_SMCR_SMS, mode);
+
+	return len;
+}
+
+static IIO_DEVICE_ATTR(slave_mode, S_IRUGO | S_IWUSR,
+		       _show_slave_mode,
+		       _store_slave_mode,
+		       0);
+
+static struct attribute *stm32_timer_attrs[] = {
+	&iio_dev_attr_master_mode.dev_attr.attr,
+	&iio_dev_attr_slave_mode.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group stm32_timer_attr_group = {
+	.attrs = stm32_timer_attrs,
+};
+
+static const struct stm32_trigger trigger1[] = {
+	{
+		.name = TIM1_TRGO,
+	},
+};
+
+static const struct stm32_valid_trigger valid1[] = {
+	{
+		.name = TIM5_TRGO,
+		.ts_value = 0,
+	},
+	{
+		.name = TIM2_TRGO,
+		.ts_value = 1,
+	},
+	{
+		.name = TIM3_TRGO,
+		.ts_value = 2,
+	},
+	{
+		.name = TIM4_TRGO,
+		.ts_value = 3,
+	},
+};
+
+static const struct stm32_trig_cfg trigger1_cfg = {
+	.triggers = trigger1,
+	.nb_triggers = ARRAY_SIZE(trigger1),
+	.valids = valid1,
+	.nb_valids = ARRAY_SIZE(valid1),
+};
+
+static const struct stm32_trigger trigger2[] = {
+	{
+		.name = TIM2_TRGO,
+	},
+};
+
+static const struct stm32_valid_trigger valid2[] = {
+	{
+		.name = TIM1_TRGO,
+		.ts_value = 0,
+	},
+	{
+		.name = TIM8_TRGO,
+		.ts_value = 1,
+	},
+	{
+		.name = TIM3_TRGO,
+		.ts_value = 2,
+	},
+	{
+		.name = TIM4_TRGO,
+		.ts_value = 3,
+	},
+};
+
+static const struct stm32_trig_cfg trigger2_cfg = {
+	.triggers = trigger2,
+	.nb_triggers = ARRAY_SIZE(trigger2),
+	.valids = valid2,
+	.nb_valids = ARRAY_SIZE(valid2),
+};
+
+static const struct stm32_trigger trigger3[] = {
+	{
+		.name = TIM3_TRGO,
+	},
+};
+
+static const struct stm32_valid_trigger valid3[] = {
+	{
+		.name = TIM1_TRGO,
+		.ts_value = 0,
+	},
+	{
+		.name = TIM8_TRGO,
+		.ts_value = 1,
+	},
+	{
+		.name = TIM5_TRGO,
+		.ts_value = 2,
+	},
+	{
+		.name = TIM4_TRGO,
+		.ts_value = 3,
+	},
+};
+
+static const struct stm32_trig_cfg trigger3_cfg = {
+	.triggers = trigger3,
+	.nb_triggers = ARRAY_SIZE(trigger3),
+	.valids = valid3,
+	.nb_valids = ARRAY_SIZE(valid3),
+};
+
+static const struct stm32_trigger trigger4[] = {
+	{
+		.name = TIM4_TRGO,
+	},
+};
+
+static const struct stm32_valid_trigger valid4[] = {
+	{
+		.name = TIM1_TRGO,
+		.ts_value = 0,
+	},
+	{
+		.name = TIM2_TRGO,
+		.ts_value = 1,
+	},
+	{
+		.name = TIM3_TRGO,
+		.ts_value = 2,
+	},
+	{
+		.name = TIM8_TRGO,
+		.ts_value = 3,
+	},
+};
+
+static const struct stm32_trig_cfg trigger4_cfg = {
+	.triggers = trigger4,
+	.nb_triggers = ARRAY_SIZE(trigger4),
+	.valids = valid4,
+	.nb_valids = ARRAY_SIZE(valid4),
+};
+
+static const struct stm32_trigger trigger5[] = {
+	{
+		.name = TIM5_TRGO,
+	},
+};
+
+static const struct stm32_valid_trigger valid5[] = {
+	{
+		.name = TIM2_TRGO,
+		.ts_value = 0,
+	},
+	{
+		.name = TIM3_TRGO,
+		.ts_value = 1,
+	},
+	{
+		.name = TIM4_TRGO,
+		.ts_value = 2,
+	},
+	{
+		.name = TIM8_TRGO,
+		.ts_value = 3,
+	},
+};
+
+static const struct stm32_trig_cfg trigger5_cfg = {
+	.triggers = trigger5,
+	.nb_triggers = ARRAY_SIZE(trigger5),
+	.valids = valid5,
+	.nb_valids = ARRAY_SIZE(valid5),
+};
+
+static const struct stm32_trigger trigger6[] = {
+	{
+		.name = TIM6_TRGO,
+	},
+};
+
+static const struct stm32_trig_cfg trigger6_cfg = {
+	.triggers = trigger6,
+	.nb_triggers = ARRAY_SIZE(trigger6),
+	.nb_valids = 0,
+};
+
+static const struct stm32_trigger trigger7[] = {
+	{
+		.name = TIM7_TRGO,
+	},
+};
+
+static const struct stm32_trig_cfg trigger7_cfg = {
+	.triggers = trigger7,
+	.nb_triggers = ARRAY_SIZE(trigger7),
+	.nb_valids = 0,
+};
+
+static const struct stm32_trigger trigger8[] = {
+	{
+		.name = TIM8_TRGO,
+	},
+};
+
+static const struct stm32_valid_trigger valid8[] = {
+	{
+		.name = TIM1_TRGO,
+		.ts_value = 0,
+	},
+	{
+		.name = TIM2_TRGO,
+		.ts_value = 1,
+	},
+	{
+		.name = TIM4_TRGO,
+		.ts_value = 2,
+	},
+	{
+		.name = TIM5_TRGO,
+		.ts_value = 3,
+	},
+};
+
+static const struct stm32_trig_cfg trigger8_cfg = {
+	.triggers = trigger8,
+	.nb_triggers = ARRAY_SIZE(trigger8),
+	.valids = valid8,
+	.nb_valids = ARRAY_SIZE(valid8),
+};
+
+static const struct stm32_trigger trigger9[] = {
+	{
+		.name = TIM9_TRGO,
+	},
+};
+
+static const struct stm32_valid_trigger valid9[] = {
+	{
+		.name = TIM2_TRGO,
+		.ts_value = 0,
+	},
+	{
+		.name = TIM3_TRGO,
+		.ts_value = 1,
+	},
+};
+
+static const struct stm32_trig_cfg trigger9_cfg = {
+	.triggers = trigger9,
+	.nb_triggers = ARRAY_SIZE(trigger9),
+	.valids = valid9,
+	.nb_valids = ARRAY_SIZE(valid9),
+};
+
+static const struct stm32_trigger trigger12[] = {
+	{
+		.name = TIM12_TRGO,
+	},
+};
+
+static const struct stm32_valid_trigger valid12[] = {
+	{
+		.name = TIM4_TRGO,
+		.ts_value = 0,
+	},
+	{
+		.name = TIM5_TRGO,
+		.ts_value = 1,
+	},
+};
+
+static const struct stm32_trig_cfg trigger12_cfg = {
+	.triggers = trigger12,
+	.nb_triggers = ARRAY_SIZE(trigger12),
+	.valids = valid12,
+	.nb_valids = ARRAY_SIZE(valid12),
+};
+
+static const struct of_device_id stm32_trig_of_match[] = {
+	{
+		.compatible = "st,stm32-iio-timer1",
+		.data = &trigger1_cfg,
+	},
+	{
+		.compatible = "st,stm32-iio-timer2",
+		.data = &trigger2_cfg,
+	},
+	{
+		.compatible = "st,stm32-iio-timer3",
+		.data = &trigger3_cfg,
+	},
+	{
+		.compatible = "st,stm32-iio-timer4",
+		.data = &trigger4_cfg,
+	},
+	{
+		.compatible = "st,stm32-iio-timer5",
+		.data = &trigger5_cfg,
+	},
+	{
+		.compatible = "st,stm32-iio-timer6",
+		.data = &trigger6_cfg,
+	},
+	{
+		.compatible = "st,stm32-iio-timer7",
+		.data = &trigger7_cfg,
+	},
+	{
+		.compatible = "st,stm32-iio-timer8",
+		.data = &trigger8_cfg,
+	},
+	{
+		.compatible = "st,stm32-iio-timer9",
+		.data = &trigger9_cfg,
+	},
+	{
+		.compatible = "st,stm32-iio-timer12",
+		.data = &trigger12_cfg,
+	},
+};
+MODULE_DEVICE_TABLE(of, stm32_trig_of_match);
+
+static int stm32_timer_start(struct stm32_iio_timer_dev *stm32)
+{
+	unsigned long long prd, div;
+	int prescaler = 0;
+	u32 max_arr = 0xFFFF, cr1;
+
+	if (stm32->sampling_frequency == 0)
+		return 0;
+
+	/* Period and prescaler values depends of clock rate */
+	div = (unsigned long long)clk_get_rate(stm32->clk);
+
+	do_div(div, stm32->sampling_frequency);
+
+	prd = div;
+
+	while (div > max_arr) {
+		prescaler++;
+		div = prd;
+		do_div(div, (prescaler + 1));
+	}
+	prd = div;
+
+	if (prescaler > MAX_TIM_PSC) {
+		dev_err(stm32->dev, "prescaler exceeds the maximum value\n");
+		return -EINVAL;
+	}
+
+	/* Check that we own the timer */
+	regmap_read(stm32->regmap, TIM_CR1, &cr1);
+	if ((cr1 & TIM_CR1_CEN) && !stm32->own_timer)
+		return -EBUSY;
+
+	if (!stm32->own_timer) {
+		stm32->own_timer = true;
+		clk_enable(stm32->clk);
+	}
+
+	regmap_write(stm32->regmap, TIM_PSC, prescaler);
+	regmap_write(stm32->regmap, TIM_ARR, prd - 1);
+	regmap_update_bits(stm32->regmap, TIM_CR1, TIM_CR1_ARPE, TIM_CR1_ARPE);
+
+	/* Force master mode to update mode */
+	regmap_update_bits(stm32->regmap, TIM_CR2, TIM_CR2_MMS, 0x20);
+
+	/* Make sure that registers are updated */
+	regmap_update_bits(stm32->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG);
+
+	/* Enable interrupt */
+	regmap_write(stm32->regmap, TIM_SR, 0);
+	regmap_update_bits(stm32->regmap, TIM_DIER, TIM_DIER_UIE, TIM_DIER_UIE);
+
+	/* Enable controller */
+	regmap_update_bits(stm32->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN);
+
+	return 0;
+}
+
+static int stm32_timer_stop(struct stm32_iio_timer_dev *stm32)
+{
+	if (!stm32->own_timer)
+		return 0;
+
+	/* Stop timer */
+	regmap_update_bits(stm32->regmap, TIM_DIER, TIM_DIER_UIE, 0);
+	regmap_update_bits(stm32->regmap, TIM_CR1, TIM_CR1_CEN, 0);
+	regmap_write(stm32->regmap, TIM_PSC, 0);
+	regmap_write(stm32->regmap, TIM_ARR, 0);
+
+	clk_disable(stm32->clk);
+
+	stm32->own_timer = false;
+	stm32->active_trigger = NULL;
+
+	return 0;
+}
+
+static int stm32_set_trigger_state(struct iio_trigger *trig, bool state)
+{
+	struct stm32_iio_timer_dev *stm32 = iio_trigger_get_drvdata(trig);
+
+	stm32->active_trigger = trig;
+
+	if (state)
+		return stm32_timer_start(stm32);
+	else
+		return stm32_timer_stop(stm32);
+}
+
+static irqreturn_t stm32_timer_irq_handler(int irq, void *private)
+{
+	struct stm32_iio_timer_dev *stm32 = private;
+	u32 sr;
+
+	regmap_read(stm32->regmap, TIM_SR, &sr);
+	regmap_write(stm32->regmap, TIM_SR, 0);
+
+	if ((sr & TIM_SR_UIF) && stm32->active_trigger)
+		iio_trigger_poll(stm32->active_trigger);
+
+	return IRQ_HANDLED;
+}
+
+static const struct iio_trigger_ops timer_trigger_ops = {
+	.owner = THIS_MODULE,
+	.set_trigger_state = stm32_set_trigger_state,
+};
+
+static int stm32_setup_iio_triggers(struct stm32_iio_timer_dev *stm32)
+{
+	int i, ret;
+	const struct stm32_trigger *triggers = stm32->cfg->triggers;
+
+	for (i = 0; i < stm32->cfg->nb_triggers; i++) {
+		struct iio_trigger *trig;
+
+		trig = devm_iio_trigger_alloc(stm32->dev,
+					      "%s", triggers[i].name);
+		if  (!trig)
+			return -ENOMEM;
+
+		ret = devm_request_irq(stm32->dev, stm32->irq,
+				       stm32_timer_irq_handler, IRQF_SHARED,
+				       "timer_event", stm32);
+		if (ret)
+			return ret;
+
+		trig->dev.parent = stm32->dev->parent;
+		trig->ops = &timer_trigger_ops;
+		trig->dev.groups = stm32_trigger_attr_groups;
+		iio_trigger_set_drvdata(trig, stm32);
+
+		ret = devm_iio_trigger_register(stm32->dev, trig);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * is_stm32_iio_timer_trigger
+ * @trig: trigger to be checked
+ *
+ * return true if the trigger is a valid stm32 iio timer trigger
+ * either return false
+ */
+bool is_stm32_iio_timer_trigger(struct iio_trigger *trig)
+{
+	return (trig->ops == &timer_trigger_ops);
+}
+EXPORT_SYMBOL(is_stm32_iio_timer_trigger);
+
+static int stm32_validate_trigger(struct iio_dev *indio_dev,
+				  struct iio_trigger *trig)
+{
+	struct stm32_iio_timer_dev *dev = iio_priv(indio_dev);
+	const struct stm32_valid_trigger *valids = dev->cfg->valids;
+	int i;
+
+	if (!is_stm32_iio_timer_trigger(trig))
+		return -EINVAL;
+
+	for (i = 0; i < dev->cfg->nb_valids; i++) {
+		if (strcmp(valids[i].name, trig->name) == 0) {
+			regmap_update_bits(dev->regmap, TIM_SMCR, TIM_SMCR_TS,
+					   valids[i].ts_value << 4);
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static const struct iio_info stm32_trigger_info = {
+	.driver_module = THIS_MODULE,
+	.validate_trigger = stm32_validate_trigger,
+	.attrs = &stm32_timer_attr_group,
+};
+
+static struct stm32_iio_timer_dev *stm32_setup_iio_device(struct device *dev)
+{
+	struct iio_dev *indio_dev;
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof(struct stm32_iio_timer_dev));
+	if (!indio_dev)
+		return NULL;
+
+	indio_dev->name = dev_name(dev);
+	indio_dev->dev.parent = dev;
+	indio_dev->info = &stm32_trigger_info;
+	indio_dev->modes = INDIO_EVENT_TRIGGERED;
+	indio_dev->num_channels = 0;
+	indio_dev->dev.of_node = dev->of_node;
+
+	ret = iio_triggered_event_setup(indio_dev,
+					NULL,
+					stm32_timer_irq_handler);
+	if (ret)
+		return NULL;
+
+	ret = devm_iio_device_register(dev, indio_dev);
+	if (ret) {
+		iio_triggered_event_cleanup(indio_dev);
+		return NULL;
+	}
+
+	return iio_priv(indio_dev);
+}
+
+static int stm32_iio_timer_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct stm32_iio_timer_dev *stm32;
+	struct stm32_mfd_timer_dev *mfd = pdev->dev.platform_data;
+	int ret;
+
+	stm32 = stm32_setup_iio_device(dev);
+	if (!stm32)
+		return -ENOMEM;
+
+	stm32->dev = dev;
+	stm32->regmap = mfd->regmap;
+	stm32->clk = mfd->clk;
+	stm32->irq = mfd->irq;
+
+	if (!of_match_node(stm32_trig_of_match, np)->data)
+		return -EINVAL;
+
+	stm32->cfg =
+	(struct stm32_trig_cfg *)of_match_node(stm32_trig_of_match, np)->data;
+
+	ret = stm32_setup_iio_triggers(stm32);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, stm32);
+
+	return 0;
+}
+
+static int stm32_iio_timer_remove(struct platform_device *pdev)
+{
+	struct stm32_iio_timer_dev *stm32 = platform_get_drvdata(pdev);
+
+	iio_triggered_event_cleanup((struct iio_dev *)stm32);
+
+	return 0;
+}
+
+static struct platform_driver stm32_iio_timer_driver = {
+	.probe = stm32_iio_timer_probe,
+	.remove = stm32_iio_timer_remove,
+	.driver = {
+		.name = DRIVER_NAME,
+		.of_match_table = stm32_trig_of_match,
+	},
+};
+module_platform_driver(stm32_iio_timer_driver);
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_DESCRIPTION("STMicroelectronics STM32 iio timer driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/trigger/Kconfig b/drivers/iio/trigger/Kconfig
index 809b2e7..f2af4fe 100644
--- a/drivers/iio/trigger/Kconfig
+++ b/drivers/iio/trigger/Kconfig
@@ -46,5 +46,4 @@ config IIO_SYSFS_TRIGGER
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called iio-trig-sysfs.
-
 endmenu
diff --git a/include/linux/iio/timer/stm32-iio-timers.h b/include/linux/iio/timer/stm32-iio-timers.h
new file mode 100644
index 0000000..c91ddbd
--- /dev/null
+++ b/include/linux/iio/timer/stm32-iio-timers.h
@@ -0,0 +1,25 @@
+/*
+ * stm32-iio-timers.h
+ *
+ * Copyright (C) STMicroelectronics 2016
+ * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef _STM32_TRIGGERS_H_
+#define _STM32_TRIGGERS_H_
+
+#define TIM1_TRGO	"tim1_trgo"
+#define TIM2_TRGO	"tim2_trgo"
+#define TIM3_TRGO	"tim3_trgo"
+#define TIM4_TRGO	"tim4_trgo"
+#define TIM5_TRGO	"tim5_trgo"
+#define TIM6_TRGO	"tim6_trgo"
+#define TIM7_TRGO	"tim7_trgo"
+#define TIM8_TRGO	"tim8_trgo"
+#define TIM9_TRGO	"tim9_trgo"
+#define TIM12_TRGO	"tim12_trgo"
+
+bool is_stm32_iio_timer_trigger(struct iio_trigger *trig);
+
+#endif
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 6/7] add STM32 IIO timer driver
@ 2016-11-22 16:13   ` Benjamin Gaignard
  0 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-22 16:13 UTC (permalink / raw)
  To: linux-arm-kernel

Timers IPs can be used to generate triggers for other IPs like
DAC, ADC or other timers.
Each trigger may result of timer internals signals like counter enable,
reset or edge, this configuration could be done through "master_mode"
device attribute.

A timer device could be triggered by other timers, we use the trigger
name and is_stm32_iio_timer_trigger() function to distinguish them
and configure IP input switch.

Timer may also decide on which event (edge, level) they could
be activated by a trigger, this configuration is done by writing in
"slave_mode" device attribute.

Since triggers could also be used by DAC or ADC their names are defined
in include/linux/iio/timer/stm32-iio-timers.h so those IPs will be able
to configure themselves in valid_trigger function

Trigger have a "sampling_frequency" attribute which allow to configure
timer sampling frequency without using pwm interface

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
---
 drivers/iio/Kconfig                        |   2 +-
 drivers/iio/Makefile                       |   1 +
 drivers/iio/timer/Kconfig                  |  15 +
 drivers/iio/timer/Makefile                 |   1 +
 drivers/iio/timer/stm32-iio-timer.c        | 766 +++++++++++++++++++++++++++++
 drivers/iio/trigger/Kconfig                |   1 -
 include/linux/iio/timer/stm32-iio-timers.h |  25 +
 7 files changed, 809 insertions(+), 2 deletions(-)
 create mode 100644 drivers/iio/timer/Kconfig
 create mode 100644 drivers/iio/timer/Makefile
 create mode 100644 drivers/iio/timer/stm32-iio-timer.c
 create mode 100644 include/linux/iio/timer/stm32-iio-timers.h

diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index 6743b18..2de2a80 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -90,5 +90,5 @@ source "drivers/iio/potentiometer/Kconfig"
 source "drivers/iio/pressure/Kconfig"
 source "drivers/iio/proximity/Kconfig"
 source "drivers/iio/temperature/Kconfig"
-
+source "drivers/iio/timer/Kconfig"
 endif # IIO
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index 87e4c43..b797c08 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -32,4 +32,5 @@ obj-y += potentiometer/
 obj-y += pressure/
 obj-y += proximity/
 obj-y += temperature/
+obj-y += timer/
 obj-y += trigger/
diff --git a/drivers/iio/timer/Kconfig b/drivers/iio/timer/Kconfig
new file mode 100644
index 0000000..55764e8
--- /dev/null
+++ b/drivers/iio/timer/Kconfig
@@ -0,0 +1,15 @@
+#
+# Timers drivers
+
+menu "Timers"
+
+config IIO_STM32_TIMER
+	tristate "stm32 iio timer"
+	depends on ARCH_STM32
+	depends on OF
+	select IIO_TRIGGERED_EVENT
+	select MFD_STM32_TIMER
+	help
+	  Select this option to enable stm32 timers hardware IPs
+
+endmenu
diff --git a/drivers/iio/timer/Makefile b/drivers/iio/timer/Makefile
new file mode 100644
index 0000000..a360c9f
--- /dev/null
+++ b/drivers/iio/timer/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_IIO_STM32_TIMER) += stm32-iio-timer.o
diff --git a/drivers/iio/timer/stm32-iio-timer.c b/drivers/iio/timer/stm32-iio-timer.c
new file mode 100644
index 0000000..a1d54c4
--- /dev/null
+++ b/drivers/iio/timer/stm32-iio-timer.c
@@ -0,0 +1,766 @@
+/*
+ * stm32-iio-timer.c
+ *
+ * Copyright (C) STMicroelectronics 2016
+ * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/timer/stm32-iio-timers.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/triggered_event.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/stm32-mfd-timer.h>
+#include <linux/module.h>
+
+#define DRIVER_NAME "stm32-iio-timer"
+
+struct stm32_trigger {
+	const char *name;
+};
+
+struct stm32_valid_trigger {
+	const char *name;
+	int ts_value;
+};
+
+struct stm32_trig_cfg {
+	const struct stm32_trigger *triggers;
+	int nb_triggers;
+	const struct stm32_valid_trigger *valids;
+	int nb_valids;
+};
+
+struct stm32_iio_timer_dev {
+	struct device *dev;
+	struct regmap *regmap;
+	struct clk *clk;
+	int irq;
+	struct stm32_trig_cfg *cfg;
+	bool own_timer;
+	unsigned int sampling_frequency;
+	struct iio_trigger *active_trigger;
+};
+
+static ssize_t _store_frequency(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t len)
+{
+	struct iio_trigger *trig = to_iio_trigger(dev);
+	struct stm32_iio_timer_dev *stm32 = iio_trigger_get_drvdata(trig);
+	unsigned int freq;
+	int ret;
+
+	ret = kstrtouint(buf, 10, &freq);
+	if (ret)
+		return ret;
+
+	stm32->sampling_frequency = freq;
+
+	return len;
+}
+
+static ssize_t _read_frequency(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct iio_trigger *trig = to_iio_trigger(dev);
+	struct stm32_iio_timer_dev *stm32 = iio_trigger_get_drvdata(trig);
+	unsigned long long freq = stm32->sampling_frequency;
+	u32 psc, arr, cr1;
+
+	regmap_read(stm32->regmap, TIM_CR1, &cr1);
+	regmap_read(stm32->regmap, TIM_PSC, &psc);
+	regmap_read(stm32->regmap, TIM_ARR, &arr);
+
+	if (psc && arr && (cr1 & TIM_CR1_CEN)) {
+		freq = (unsigned long long)clk_get_rate(stm32->clk);
+		do_div(freq, psc);
+		do_div(freq, arr);
+	}
+
+	return sprintf(buf, "%d\n", (unsigned int) freq);
+}
+
+static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
+			      _read_frequency,
+			      _store_frequency);
+
+static struct attribute *stm32_trigger_attrs[] = {
+	&iio_dev_attr_sampling_frequency.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group stm32_trigger_attr_group = {
+	.attrs = stm32_trigger_attrs,
+};
+
+static const struct attribute_group *stm32_trigger_attr_groups[] = {
+	&stm32_trigger_attr_group,
+	NULL,
+};
+
+static
+ssize_t _show_master_mode(struct device *dev,
+			  struct device_attribute *attr, char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct stm32_iio_timer_dev *stm32 = iio_priv(indio_dev);
+	u32 cr2;
+
+	regmap_read(stm32->regmap, TIM_CR2, &cr2);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", (cr2 >> 4) & 0x7);
+}
+
+static
+ssize_t _store_master_mode(struct device *dev,
+			   struct device_attribute *attr,
+			   const char *buf, size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct stm32_iio_timer_dev *stm32 = iio_priv(indio_dev);
+	u8 mode;
+	int ret;
+
+	ret = kstrtou8(buf, 10, &mode);
+	if (ret)
+		return ret;
+
+	if (mode > 0x7)
+		return -EINVAL;
+
+	regmap_update_bits(stm32->regmap, TIM_CR2, TIM_CR2_MMS, mode << 4);
+
+	return len;
+}
+
+static IIO_DEVICE_ATTR(master_mode, S_IRUGO | S_IWUSR,
+		       _show_master_mode,
+		       _store_master_mode,
+		       0);
+
+static
+ssize_t _show_slave_mode(struct device *dev,
+			 struct device_attribute *attr, char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct stm32_iio_timer_dev *stm32 = iio_priv(indio_dev);
+	u32 smcr;
+
+	regmap_read(stm32->regmap, TIM_SMCR, &smcr);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", smcr & 0x3);
+}
+
+static
+ssize_t _store_slave_mode(struct device *dev,
+			  struct device_attribute *attr,
+			  const char *buf, size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct stm32_iio_timer_dev *stm32 = iio_priv(indio_dev);
+	u8 mode;
+	int ret;
+
+	ret = kstrtou8(buf, 10, &mode);
+	if (ret)
+		return ret;
+
+	if (mode > 0x7)
+		return -EINVAL;
+
+	regmap_update_bits(stm32->regmap, TIM_SMCR, TIM_SMCR_SMS, mode);
+
+	return len;
+}
+
+static IIO_DEVICE_ATTR(slave_mode, S_IRUGO | S_IWUSR,
+		       _show_slave_mode,
+		       _store_slave_mode,
+		       0);
+
+static struct attribute *stm32_timer_attrs[] = {
+	&iio_dev_attr_master_mode.dev_attr.attr,
+	&iio_dev_attr_slave_mode.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group stm32_timer_attr_group = {
+	.attrs = stm32_timer_attrs,
+};
+
+static const struct stm32_trigger trigger1[] = {
+	{
+		.name = TIM1_TRGO,
+	},
+};
+
+static const struct stm32_valid_trigger valid1[] = {
+	{
+		.name = TIM5_TRGO,
+		.ts_value = 0,
+	},
+	{
+		.name = TIM2_TRGO,
+		.ts_value = 1,
+	},
+	{
+		.name = TIM3_TRGO,
+		.ts_value = 2,
+	},
+	{
+		.name = TIM4_TRGO,
+		.ts_value = 3,
+	},
+};
+
+static const struct stm32_trig_cfg trigger1_cfg = {
+	.triggers = trigger1,
+	.nb_triggers = ARRAY_SIZE(trigger1),
+	.valids = valid1,
+	.nb_valids = ARRAY_SIZE(valid1),
+};
+
+static const struct stm32_trigger trigger2[] = {
+	{
+		.name = TIM2_TRGO,
+	},
+};
+
+static const struct stm32_valid_trigger valid2[] = {
+	{
+		.name = TIM1_TRGO,
+		.ts_value = 0,
+	},
+	{
+		.name = TIM8_TRGO,
+		.ts_value = 1,
+	},
+	{
+		.name = TIM3_TRGO,
+		.ts_value = 2,
+	},
+	{
+		.name = TIM4_TRGO,
+		.ts_value = 3,
+	},
+};
+
+static const struct stm32_trig_cfg trigger2_cfg = {
+	.triggers = trigger2,
+	.nb_triggers = ARRAY_SIZE(trigger2),
+	.valids = valid2,
+	.nb_valids = ARRAY_SIZE(valid2),
+};
+
+static const struct stm32_trigger trigger3[] = {
+	{
+		.name = TIM3_TRGO,
+	},
+};
+
+static const struct stm32_valid_trigger valid3[] = {
+	{
+		.name = TIM1_TRGO,
+		.ts_value = 0,
+	},
+	{
+		.name = TIM8_TRGO,
+		.ts_value = 1,
+	},
+	{
+		.name = TIM5_TRGO,
+		.ts_value = 2,
+	},
+	{
+		.name = TIM4_TRGO,
+		.ts_value = 3,
+	},
+};
+
+static const struct stm32_trig_cfg trigger3_cfg = {
+	.triggers = trigger3,
+	.nb_triggers = ARRAY_SIZE(trigger3),
+	.valids = valid3,
+	.nb_valids = ARRAY_SIZE(valid3),
+};
+
+static const struct stm32_trigger trigger4[] = {
+	{
+		.name = TIM4_TRGO,
+	},
+};
+
+static const struct stm32_valid_trigger valid4[] = {
+	{
+		.name = TIM1_TRGO,
+		.ts_value = 0,
+	},
+	{
+		.name = TIM2_TRGO,
+		.ts_value = 1,
+	},
+	{
+		.name = TIM3_TRGO,
+		.ts_value = 2,
+	},
+	{
+		.name = TIM8_TRGO,
+		.ts_value = 3,
+	},
+};
+
+static const struct stm32_trig_cfg trigger4_cfg = {
+	.triggers = trigger4,
+	.nb_triggers = ARRAY_SIZE(trigger4),
+	.valids = valid4,
+	.nb_valids = ARRAY_SIZE(valid4),
+};
+
+static const struct stm32_trigger trigger5[] = {
+	{
+		.name = TIM5_TRGO,
+	},
+};
+
+static const struct stm32_valid_trigger valid5[] = {
+	{
+		.name = TIM2_TRGO,
+		.ts_value = 0,
+	},
+	{
+		.name = TIM3_TRGO,
+		.ts_value = 1,
+	},
+	{
+		.name = TIM4_TRGO,
+		.ts_value = 2,
+	},
+	{
+		.name = TIM8_TRGO,
+		.ts_value = 3,
+	},
+};
+
+static const struct stm32_trig_cfg trigger5_cfg = {
+	.triggers = trigger5,
+	.nb_triggers = ARRAY_SIZE(trigger5),
+	.valids = valid5,
+	.nb_valids = ARRAY_SIZE(valid5),
+};
+
+static const struct stm32_trigger trigger6[] = {
+	{
+		.name = TIM6_TRGO,
+	},
+};
+
+static const struct stm32_trig_cfg trigger6_cfg = {
+	.triggers = trigger6,
+	.nb_triggers = ARRAY_SIZE(trigger6),
+	.nb_valids = 0,
+};
+
+static const struct stm32_trigger trigger7[] = {
+	{
+		.name = TIM7_TRGO,
+	},
+};
+
+static const struct stm32_trig_cfg trigger7_cfg = {
+	.triggers = trigger7,
+	.nb_triggers = ARRAY_SIZE(trigger7),
+	.nb_valids = 0,
+};
+
+static const struct stm32_trigger trigger8[] = {
+	{
+		.name = TIM8_TRGO,
+	},
+};
+
+static const struct stm32_valid_trigger valid8[] = {
+	{
+		.name = TIM1_TRGO,
+		.ts_value = 0,
+	},
+	{
+		.name = TIM2_TRGO,
+		.ts_value = 1,
+	},
+	{
+		.name = TIM4_TRGO,
+		.ts_value = 2,
+	},
+	{
+		.name = TIM5_TRGO,
+		.ts_value = 3,
+	},
+};
+
+static const struct stm32_trig_cfg trigger8_cfg = {
+	.triggers = trigger8,
+	.nb_triggers = ARRAY_SIZE(trigger8),
+	.valids = valid8,
+	.nb_valids = ARRAY_SIZE(valid8),
+};
+
+static const struct stm32_trigger trigger9[] = {
+	{
+		.name = TIM9_TRGO,
+	},
+};
+
+static const struct stm32_valid_trigger valid9[] = {
+	{
+		.name = TIM2_TRGO,
+		.ts_value = 0,
+	},
+	{
+		.name = TIM3_TRGO,
+		.ts_value = 1,
+	},
+};
+
+static const struct stm32_trig_cfg trigger9_cfg = {
+	.triggers = trigger9,
+	.nb_triggers = ARRAY_SIZE(trigger9),
+	.valids = valid9,
+	.nb_valids = ARRAY_SIZE(valid9),
+};
+
+static const struct stm32_trigger trigger12[] = {
+	{
+		.name = TIM12_TRGO,
+	},
+};
+
+static const struct stm32_valid_trigger valid12[] = {
+	{
+		.name = TIM4_TRGO,
+		.ts_value = 0,
+	},
+	{
+		.name = TIM5_TRGO,
+		.ts_value = 1,
+	},
+};
+
+static const struct stm32_trig_cfg trigger12_cfg = {
+	.triggers = trigger12,
+	.nb_triggers = ARRAY_SIZE(trigger12),
+	.valids = valid12,
+	.nb_valids = ARRAY_SIZE(valid12),
+};
+
+static const struct of_device_id stm32_trig_of_match[] = {
+	{
+		.compatible = "st,stm32-iio-timer1",
+		.data = &trigger1_cfg,
+	},
+	{
+		.compatible = "st,stm32-iio-timer2",
+		.data = &trigger2_cfg,
+	},
+	{
+		.compatible = "st,stm32-iio-timer3",
+		.data = &trigger3_cfg,
+	},
+	{
+		.compatible = "st,stm32-iio-timer4",
+		.data = &trigger4_cfg,
+	},
+	{
+		.compatible = "st,stm32-iio-timer5",
+		.data = &trigger5_cfg,
+	},
+	{
+		.compatible = "st,stm32-iio-timer6",
+		.data = &trigger6_cfg,
+	},
+	{
+		.compatible = "st,stm32-iio-timer7",
+		.data = &trigger7_cfg,
+	},
+	{
+		.compatible = "st,stm32-iio-timer8",
+		.data = &trigger8_cfg,
+	},
+	{
+		.compatible = "st,stm32-iio-timer9",
+		.data = &trigger9_cfg,
+	},
+	{
+		.compatible = "st,stm32-iio-timer12",
+		.data = &trigger12_cfg,
+	},
+};
+MODULE_DEVICE_TABLE(of, stm32_trig_of_match);
+
+static int stm32_timer_start(struct stm32_iio_timer_dev *stm32)
+{
+	unsigned long long prd, div;
+	int prescaler = 0;
+	u32 max_arr = 0xFFFF, cr1;
+
+	if (stm32->sampling_frequency == 0)
+		return 0;
+
+	/* Period and prescaler values depends of clock rate */
+	div = (unsigned long long)clk_get_rate(stm32->clk);
+
+	do_div(div, stm32->sampling_frequency);
+
+	prd = div;
+
+	while (div > max_arr) {
+		prescaler++;
+		div = prd;
+		do_div(div, (prescaler + 1));
+	}
+	prd = div;
+
+	if (prescaler > MAX_TIM_PSC) {
+		dev_err(stm32->dev, "prescaler exceeds the maximum value\n");
+		return -EINVAL;
+	}
+
+	/* Check that we own the timer */
+	regmap_read(stm32->regmap, TIM_CR1, &cr1);
+	if ((cr1 & TIM_CR1_CEN) && !stm32->own_timer)
+		return -EBUSY;
+
+	if (!stm32->own_timer) {
+		stm32->own_timer = true;
+		clk_enable(stm32->clk);
+	}
+
+	regmap_write(stm32->regmap, TIM_PSC, prescaler);
+	regmap_write(stm32->regmap, TIM_ARR, prd - 1);
+	regmap_update_bits(stm32->regmap, TIM_CR1, TIM_CR1_ARPE, TIM_CR1_ARPE);
+
+	/* Force master mode to update mode */
+	regmap_update_bits(stm32->regmap, TIM_CR2, TIM_CR2_MMS, 0x20);
+
+	/* Make sure that registers are updated */
+	regmap_update_bits(stm32->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG);
+
+	/* Enable interrupt */
+	regmap_write(stm32->regmap, TIM_SR, 0);
+	regmap_update_bits(stm32->regmap, TIM_DIER, TIM_DIER_UIE, TIM_DIER_UIE);
+
+	/* Enable controller */
+	regmap_update_bits(stm32->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN);
+
+	return 0;
+}
+
+static int stm32_timer_stop(struct stm32_iio_timer_dev *stm32)
+{
+	if (!stm32->own_timer)
+		return 0;
+
+	/* Stop timer */
+	regmap_update_bits(stm32->regmap, TIM_DIER, TIM_DIER_UIE, 0);
+	regmap_update_bits(stm32->regmap, TIM_CR1, TIM_CR1_CEN, 0);
+	regmap_write(stm32->regmap, TIM_PSC, 0);
+	regmap_write(stm32->regmap, TIM_ARR, 0);
+
+	clk_disable(stm32->clk);
+
+	stm32->own_timer = false;
+	stm32->active_trigger = NULL;
+
+	return 0;
+}
+
+static int stm32_set_trigger_state(struct iio_trigger *trig, bool state)
+{
+	struct stm32_iio_timer_dev *stm32 = iio_trigger_get_drvdata(trig);
+
+	stm32->active_trigger = trig;
+
+	if (state)
+		return stm32_timer_start(stm32);
+	else
+		return stm32_timer_stop(stm32);
+}
+
+static irqreturn_t stm32_timer_irq_handler(int irq, void *private)
+{
+	struct stm32_iio_timer_dev *stm32 = private;
+	u32 sr;
+
+	regmap_read(stm32->regmap, TIM_SR, &sr);
+	regmap_write(stm32->regmap, TIM_SR, 0);
+
+	if ((sr & TIM_SR_UIF) && stm32->active_trigger)
+		iio_trigger_poll(stm32->active_trigger);
+
+	return IRQ_HANDLED;
+}
+
+static const struct iio_trigger_ops timer_trigger_ops = {
+	.owner = THIS_MODULE,
+	.set_trigger_state = stm32_set_trigger_state,
+};
+
+static int stm32_setup_iio_triggers(struct stm32_iio_timer_dev *stm32)
+{
+	int i, ret;
+	const struct stm32_trigger *triggers = stm32->cfg->triggers;
+
+	for (i = 0; i < stm32->cfg->nb_triggers; i++) {
+		struct iio_trigger *trig;
+
+		trig = devm_iio_trigger_alloc(stm32->dev,
+					      "%s", triggers[i].name);
+		if  (!trig)
+			return -ENOMEM;
+
+		ret = devm_request_irq(stm32->dev, stm32->irq,
+				       stm32_timer_irq_handler, IRQF_SHARED,
+				       "timer_event", stm32);
+		if (ret)
+			return ret;
+
+		trig->dev.parent = stm32->dev->parent;
+		trig->ops = &timer_trigger_ops;
+		trig->dev.groups = stm32_trigger_attr_groups;
+		iio_trigger_set_drvdata(trig, stm32);
+
+		ret = devm_iio_trigger_register(stm32->dev, trig);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * is_stm32_iio_timer_trigger
+ * @trig: trigger to be checked
+ *
+ * return true if the trigger is a valid stm32 iio timer trigger
+ * either return false
+ */
+bool is_stm32_iio_timer_trigger(struct iio_trigger *trig)
+{
+	return (trig->ops == &timer_trigger_ops);
+}
+EXPORT_SYMBOL(is_stm32_iio_timer_trigger);
+
+static int stm32_validate_trigger(struct iio_dev *indio_dev,
+				  struct iio_trigger *trig)
+{
+	struct stm32_iio_timer_dev *dev = iio_priv(indio_dev);
+	const struct stm32_valid_trigger *valids = dev->cfg->valids;
+	int i;
+
+	if (!is_stm32_iio_timer_trigger(trig))
+		return -EINVAL;
+
+	for (i = 0; i < dev->cfg->nb_valids; i++) {
+		if (strcmp(valids[i].name, trig->name) == 0) {
+			regmap_update_bits(dev->regmap, TIM_SMCR, TIM_SMCR_TS,
+					   valids[i].ts_value << 4);
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static const struct iio_info stm32_trigger_info = {
+	.driver_module = THIS_MODULE,
+	.validate_trigger = stm32_validate_trigger,
+	.attrs = &stm32_timer_attr_group,
+};
+
+static struct stm32_iio_timer_dev *stm32_setup_iio_device(struct device *dev)
+{
+	struct iio_dev *indio_dev;
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof(struct stm32_iio_timer_dev));
+	if (!indio_dev)
+		return NULL;
+
+	indio_dev->name = dev_name(dev);
+	indio_dev->dev.parent = dev;
+	indio_dev->info = &stm32_trigger_info;
+	indio_dev->modes = INDIO_EVENT_TRIGGERED;
+	indio_dev->num_channels = 0;
+	indio_dev->dev.of_node = dev->of_node;
+
+	ret = iio_triggered_event_setup(indio_dev,
+					NULL,
+					stm32_timer_irq_handler);
+	if (ret)
+		return NULL;
+
+	ret = devm_iio_device_register(dev, indio_dev);
+	if (ret) {
+		iio_triggered_event_cleanup(indio_dev);
+		return NULL;
+	}
+
+	return iio_priv(indio_dev);
+}
+
+static int stm32_iio_timer_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct stm32_iio_timer_dev *stm32;
+	struct stm32_mfd_timer_dev *mfd = pdev->dev.platform_data;
+	int ret;
+
+	stm32 = stm32_setup_iio_device(dev);
+	if (!stm32)
+		return -ENOMEM;
+
+	stm32->dev = dev;
+	stm32->regmap = mfd->regmap;
+	stm32->clk = mfd->clk;
+	stm32->irq = mfd->irq;
+
+	if (!of_match_node(stm32_trig_of_match, np)->data)
+		return -EINVAL;
+
+	stm32->cfg =
+	(struct stm32_trig_cfg *)of_match_node(stm32_trig_of_match, np)->data;
+
+	ret = stm32_setup_iio_triggers(stm32);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, stm32);
+
+	return 0;
+}
+
+static int stm32_iio_timer_remove(struct platform_device *pdev)
+{
+	struct stm32_iio_timer_dev *stm32 = platform_get_drvdata(pdev);
+
+	iio_triggered_event_cleanup((struct iio_dev *)stm32);
+
+	return 0;
+}
+
+static struct platform_driver stm32_iio_timer_driver = {
+	.probe = stm32_iio_timer_probe,
+	.remove = stm32_iio_timer_remove,
+	.driver = {
+		.name = DRIVER_NAME,
+		.of_match_table = stm32_trig_of_match,
+	},
+};
+module_platform_driver(stm32_iio_timer_driver);
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_DESCRIPTION("STMicroelectronics STM32 iio timer driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/trigger/Kconfig b/drivers/iio/trigger/Kconfig
index 809b2e7..f2af4fe 100644
--- a/drivers/iio/trigger/Kconfig
+++ b/drivers/iio/trigger/Kconfig
@@ -46,5 +46,4 @@ config IIO_SYSFS_TRIGGER
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called iio-trig-sysfs.
-
 endmenu
diff --git a/include/linux/iio/timer/stm32-iio-timers.h b/include/linux/iio/timer/stm32-iio-timers.h
new file mode 100644
index 0000000..c91ddbd
--- /dev/null
+++ b/include/linux/iio/timer/stm32-iio-timers.h
@@ -0,0 +1,25 @@
+/*
+ * stm32-iio-timers.h
+ *
+ * Copyright (C) STMicroelectronics 2016
+ * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef _STM32_TRIGGERS_H_
+#define _STM32_TRIGGERS_H_
+
+#define TIM1_TRGO	"tim1_trgo"
+#define TIM2_TRGO	"tim2_trgo"
+#define TIM3_TRGO	"tim3_trgo"
+#define TIM4_TRGO	"tim4_trgo"
+#define TIM5_TRGO	"tim5_trgo"
+#define TIM6_TRGO	"tim6_trgo"
+#define TIM7_TRGO	"tim7_trgo"
+#define TIM8_TRGO	"tim8_trgo"
+#define TIM9_TRGO	"tim9_trgo"
+#define TIM12_TRGO	"tim12_trgo"
+
+bool is_stm32_iio_timer_trigger(struct iio_trigger *trig);
+
+#endif
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 7/7] add stm32 multi-functions timer driver in DT
  2016-11-22 16:13 ` Benjamin Gaignard
@ 2016-11-22 16:13   ` Benjamin Gaignard
  -1 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-22 16:13 UTC (permalink / raw)
  To: lee.jones, robh+dt, mark.rutland, alexandre.torgue, devicetree,
	linux-kernel, thierry.reding, linux-pwm, jic23, knaack.h, lars,
	pmeerw, linux-iio, linux-arm-kernel
  Cc: fabrice.gasnier, gerald.baeza, arnaud.pouliquen, linus.walleij,
	linaro-kernel, Benjamin Gaignard

Add timers MFD and childs into DT for stm32f4.
Define and enable pwm1 and pwm3 for stm32f469 discovery board

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
---
 arch/arm/boot/dts/stm32f429.dtsi      | 246 ++++++++++++++++++++++++++++++++++
 arch/arm/boot/dts/stm32f469-disco.dts |  29 ++++
 2 files changed, 275 insertions(+)

diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
index bca491d..28a0fe9 100644
--- a/arch/arm/boot/dts/stm32f429.dtsi
+++ b/arch/arm/boot/dts/stm32f429.dtsi
@@ -355,6 +355,21 @@
 					slew-rate = <2>;
 				};
 			};
+
+			pwm1_pins: pwm@1 {
+				pins {
+					pinmux = <STM32F429_PA8_FUNC_TIM1_CH1>,
+						 <STM32F429_PB13_FUNC_TIM1_CH1N>,
+						 <STM32F429_PB12_FUNC_TIM1_BKIN>;
+				};
+			};
+
+			pwm3_pins: pwm@3 {
+				pins {
+					pinmux = <STM32F429_PB4_FUNC_TIM3_CH1>,
+						 <STM32F429_PB5_FUNC_TIM3_CH2>;
+				};
+			};
 		};
 
 		rcc: rcc@40023810 {
@@ -426,6 +441,237 @@
 			interrupts = <80>;
 			clocks = <&rcc 0 38>;
 		};
+
+		mfd_timer1: mfdtimer1@40010000 {
+			compatible = "st,stm32-mfd-timer1";
+			reg = <0x40010000 0x400>;
+			clocks = <&rcc 0 160>;
+			clock-names = "mfd_timer_clk";
+			interrupts = <27>;
+			status = "disabled";
+
+			pwm1: pwm1@40010000 {
+				compatible = "st,stm32-pwm1";
+				status = "disabled";
+			};
+
+			iiotimer1: iiotimer1@40010000 {
+				compatible = "st,stm32-iio-timer1";
+				status = "disabled";
+			};
+		};
+
+		mfd_timer2: mfdtimer2@40000000 {
+			compatible = "st,stm32-mfd-timer2";
+			reg = <0x40000000 0x400>;
+			clocks = <&rcc 0 128>;
+			clock-names = "mfd_timer_clk";
+			interrupts = <28>;
+			status = "disabled";
+
+			pwm2: pwm2@40000000 {
+				compatible = "st,stm32-pwm2";
+				status = "disabled";
+			};
+			iiotimer2: iiotimer2@40000000 {
+				compatible = "st,stm32-iio-timer2";
+				status = "disabled";
+			};
+		};
+
+		mfd_timer3: mfdtimer3@40000400 {
+			compatible = "st,stm32-mfd-timer3";
+			reg = <0x40000400 0x400>;
+			clocks = <&rcc 0 129>;
+			clock-names = "mfd_timer_clk";
+			interrupts = <29>;
+			status = "disabled";
+
+			pwm3: pwm3@40000400 {
+				compatible = "st,stm32-pwm3";
+				status = "disabled";
+			};
+			iiotimer3: iiotimer3@40000400 {
+				compatible = "st,stm32-iio-timer3";
+				status = "disabled";
+			};
+		};
+
+		mfd_timer4: mfdtimer4@40000800 {
+			compatible = "st,stm32-mfd-timer4";
+			reg = <0x40000800 0x400>;
+			clocks = <&rcc 0 130>;
+			clock-names = "mfd_timer_clk";
+			interrupts = <30>;
+			status = "disabled";
+
+			pwm4: pwm4@40000800 {
+				compatible = "st,stm32-pwm4";
+				status = "disabled";
+			};
+			iiotimer4: iiotimer4@40000800 {
+				compatible = "st,stm32-iio-timer4";
+				status = "disabled";
+			};
+		};
+
+		mfd_timer5: mfdtimer5@40000C00 {
+			compatible = "st,stm32-mfd-timer5";
+			reg = <0x40000C00 0x400>;
+			clocks = <&rcc 0 131>;
+			clock-names = "mfd_timer_clk";
+			interrupts = <50>;
+			status = "disabled";
+
+			pwm5: pwm5@40000C00 {
+				compatible = "st,stm32-pwm5";
+				status = "disabled";
+			};
+			iiotimer5: iiotimer5@40000800 {
+				compatible = "st,stm32-iio-timer5";
+				status = "disabled";
+			};
+		};
+
+		mfd_timer6: mfdtimer6@40001000 {
+			compatible = "st,stm32-mfd-timer6";
+			reg = <0x40001000 0x400>;
+			clocks = <&rcc 0 132>;
+			clock-names = "mfd_timer_clk";
+			interrupts = <54>;
+			status = "disabled";
+
+			iiotimer6: iiotimer6@40001000 {
+				compatible = "st,stm32-iio-timer6";
+				status = "disabled";
+			};
+		};
+
+		mfd_timer7: mfdtimer7@40001400 {
+			compatible = "st,stm32-mfd-timer7";
+			reg = <0x40001400 0x400>;
+			clocks = <&rcc 0 133>;
+			clock-names = "mfd_timer_clk";
+			interrupts = <55>;
+			status = "disabled";
+
+			iiotimer7: iiotimer7@40001400 {
+				compatible = "st,stm32-iio-timer7";
+				status = "disabled";
+			};
+		};
+
+		mfd_timer8: mfdtimer8@40010400 {
+			compatible = "st,stm32-mfd-timer8";
+			reg = <0x40010400 0x400>;
+			clocks = <&rcc 0 161>;
+			clock-names = "mfd_timer_clk";
+			interrupts = <46>;
+			status = "disabled";
+
+			pwm8: pwm8@40010400 {
+				compatible = "st,stm32-pwm8";
+				status = "disabled";
+			};
+
+			iiotimer8: iiotimer7@40010400 {
+				compatible = "st,stm32-iio-timer8";
+				status = "disabled";
+			};
+		};
+
+		mfd_timer9: mfdtimer9@40014000 {
+			compatible = "st,stm32-mfd-timer9";
+			reg = <0x40014000 0x400>;
+			clocks = <&rcc 0 176>;
+			clock-names = "mfd_timer_clk";
+			interrupts = <24>;
+			status = "disabled";
+
+			pwm9: pwm9@40014000 {
+				compatible = "st,stm32-pwm9";
+				status = "disabled";
+			};
+
+			iiotimer9: iiotimer9@40014000 {
+				compatible = "st,stm32-iio-timer9";
+				status = "disabled";
+			};
+		};
+
+		mfd_timer10: mfdtimer10@40014400 {
+			compatible = "st,stm32-mfd-timer10";
+			reg = <0x40014400 0x400>;
+			clocks = <&rcc 0 177>;
+			clock-names = "mfd_timer_clk";
+			interrupts = <25>;
+			status = "disabled";
+
+			pwm10: pwm10@40014400 {
+				compatible = "st,stm32-pwm10";
+				status = "disabled";
+			};
+		};
+
+		mfd_timer11: mfdtimer11@40014800 {
+			compatible = "st,stm32-mfd-timer11";
+			reg = <0x40014800 0x400>;
+			clocks = <&rcc 0 178>;
+			clock-names = "mfd_timer_clk";
+			interrupts = <26>;
+			status = "disabled";
+
+			pwm11: pwm11@40014800 {
+				compatible = "st,stm32-pwm11";
+				status = "disabled";
+			};
+		};
+
+		mfd_timer12: mfdtimer12@40001800 {
+			compatible = "st,stm32-mfd-timer12";
+			reg = <0x40001800 0x400>;
+			clocks = <&rcc 0 134>;
+			clock-names = "mfd_timer_clk";
+			interrupts = <43>;
+			status = "disabled";
+
+			pwm12: pwm12@40001800 {
+				compatible = "st,stm32-pwm12";
+				status = "disabled";
+			};
+			iiotimer12: iiotimer12@40001800 {
+				compatible = "st,stm32-iio-timer12";
+				status = "disabled";
+			};
+		};
+
+		mfd_timer13: mfdtimer13@40001C00 {
+			compatible = "st,stm32-mfd-timer13";
+			reg = <0x40001C00 0x400>;
+			clocks = <&rcc 0 135>;
+			clock-names = "mfd_timer_clk";
+			interrupts = <44>;
+			status = "disabled";
+
+			pwm13: pwm13@40001C00 {
+				compatible = "st,stm32-pwm13";
+				status = "disabled";
+			};
+		};
+
+		mfd_timer14: mfdtimer14@40002000 {
+			compatible = "st,stm32-mfd-timer14";
+			reg = <0x40002000 0x400>;
+			clocks = <&rcc 0 136>;
+			clock-names = "mfd_timer_clk";
+			interrupts = <45>;
+			status = "disabled";
+
+			pwm14: pwm14@40002000 {
+				compatible = "st,stm32-pwm14";
+				status = "disabled";
+			};
+		};
 	};
 };
 
diff --git a/arch/arm/boot/dts/stm32f469-disco.dts b/arch/arm/boot/dts/stm32f469-disco.dts
index 8a163d7..a8f1788 100644
--- a/arch/arm/boot/dts/stm32f469-disco.dts
+++ b/arch/arm/boot/dts/stm32f469-disco.dts
@@ -81,3 +81,32 @@
 &usart3 {
 	status = "okay";
 };
+
+&mfd_timer1 {
+	status = "okay";
+};
+
+&pwm1 {
+	pinctrl-0	= <&pwm1_pins>;
+	pinctrl-names	= "default";
+	st,breakinput-polarity = <0>;
+	status = "okay";
+};
+
+&iiotimer1 {
+	status = "okay";
+};
+
+&mfd_timer3 {
+	status = "okay";
+};
+
+&pwm3 {
+	pinctrl-0	= <&pwm3_pins>;
+	pinctrl-names	= "default";
+	status = "okay";
+};
+
+&iiotimer3 {
+	status = "okay";
+};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* [PATCH 7/7] add stm32 multi-functions timer driver in DT
@ 2016-11-22 16:13   ` Benjamin Gaignard
  0 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-22 16:13 UTC (permalink / raw)
  To: linux-arm-kernel

Add timers MFD and childs into DT for stm32f4.
Define and enable pwm1 and pwm3 for stm32f469 discovery board

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
---
 arch/arm/boot/dts/stm32f429.dtsi      | 246 ++++++++++++++++++++++++++++++++++
 arch/arm/boot/dts/stm32f469-disco.dts |  29 ++++
 2 files changed, 275 insertions(+)

diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
index bca491d..28a0fe9 100644
--- a/arch/arm/boot/dts/stm32f429.dtsi
+++ b/arch/arm/boot/dts/stm32f429.dtsi
@@ -355,6 +355,21 @@
 					slew-rate = <2>;
 				};
 			};
+
+			pwm1_pins: pwm at 1 {
+				pins {
+					pinmux = <STM32F429_PA8_FUNC_TIM1_CH1>,
+						 <STM32F429_PB13_FUNC_TIM1_CH1N>,
+						 <STM32F429_PB12_FUNC_TIM1_BKIN>;
+				};
+			};
+
+			pwm3_pins: pwm at 3 {
+				pins {
+					pinmux = <STM32F429_PB4_FUNC_TIM3_CH1>,
+						 <STM32F429_PB5_FUNC_TIM3_CH2>;
+				};
+			};
 		};
 
 		rcc: rcc at 40023810 {
@@ -426,6 +441,237 @@
 			interrupts = <80>;
 			clocks = <&rcc 0 38>;
 		};
+
+		mfd_timer1: mfdtimer1 at 40010000 {
+			compatible = "st,stm32-mfd-timer1";
+			reg = <0x40010000 0x400>;
+			clocks = <&rcc 0 160>;
+			clock-names = "mfd_timer_clk";
+			interrupts = <27>;
+			status = "disabled";
+
+			pwm1: pwm1 at 40010000 {
+				compatible = "st,stm32-pwm1";
+				status = "disabled";
+			};
+
+			iiotimer1: iiotimer1 at 40010000 {
+				compatible = "st,stm32-iio-timer1";
+				status = "disabled";
+			};
+		};
+
+		mfd_timer2: mfdtimer2 at 40000000 {
+			compatible = "st,stm32-mfd-timer2";
+			reg = <0x40000000 0x400>;
+			clocks = <&rcc 0 128>;
+			clock-names = "mfd_timer_clk";
+			interrupts = <28>;
+			status = "disabled";
+
+			pwm2: pwm2 at 40000000 {
+				compatible = "st,stm32-pwm2";
+				status = "disabled";
+			};
+			iiotimer2: iiotimer2 at 40000000 {
+				compatible = "st,stm32-iio-timer2";
+				status = "disabled";
+			};
+		};
+
+		mfd_timer3: mfdtimer3 at 40000400 {
+			compatible = "st,stm32-mfd-timer3";
+			reg = <0x40000400 0x400>;
+			clocks = <&rcc 0 129>;
+			clock-names = "mfd_timer_clk";
+			interrupts = <29>;
+			status = "disabled";
+
+			pwm3: pwm3 at 40000400 {
+				compatible = "st,stm32-pwm3";
+				status = "disabled";
+			};
+			iiotimer3: iiotimer3 at 40000400 {
+				compatible = "st,stm32-iio-timer3";
+				status = "disabled";
+			};
+		};
+
+		mfd_timer4: mfdtimer4 at 40000800 {
+			compatible = "st,stm32-mfd-timer4";
+			reg = <0x40000800 0x400>;
+			clocks = <&rcc 0 130>;
+			clock-names = "mfd_timer_clk";
+			interrupts = <30>;
+			status = "disabled";
+
+			pwm4: pwm4 at 40000800 {
+				compatible = "st,stm32-pwm4";
+				status = "disabled";
+			};
+			iiotimer4: iiotimer4 at 40000800 {
+				compatible = "st,stm32-iio-timer4";
+				status = "disabled";
+			};
+		};
+
+		mfd_timer5: mfdtimer5 at 40000C00 {
+			compatible = "st,stm32-mfd-timer5";
+			reg = <0x40000C00 0x400>;
+			clocks = <&rcc 0 131>;
+			clock-names = "mfd_timer_clk";
+			interrupts = <50>;
+			status = "disabled";
+
+			pwm5: pwm5 at 40000C00 {
+				compatible = "st,stm32-pwm5";
+				status = "disabled";
+			};
+			iiotimer5: iiotimer5 at 40000800 {
+				compatible = "st,stm32-iio-timer5";
+				status = "disabled";
+			};
+		};
+
+		mfd_timer6: mfdtimer6 at 40001000 {
+			compatible = "st,stm32-mfd-timer6";
+			reg = <0x40001000 0x400>;
+			clocks = <&rcc 0 132>;
+			clock-names = "mfd_timer_clk";
+			interrupts = <54>;
+			status = "disabled";
+
+			iiotimer6: iiotimer6 at 40001000 {
+				compatible = "st,stm32-iio-timer6";
+				status = "disabled";
+			};
+		};
+
+		mfd_timer7: mfdtimer7 at 40001400 {
+			compatible = "st,stm32-mfd-timer7";
+			reg = <0x40001400 0x400>;
+			clocks = <&rcc 0 133>;
+			clock-names = "mfd_timer_clk";
+			interrupts = <55>;
+			status = "disabled";
+
+			iiotimer7: iiotimer7 at 40001400 {
+				compatible = "st,stm32-iio-timer7";
+				status = "disabled";
+			};
+		};
+
+		mfd_timer8: mfdtimer8 at 40010400 {
+			compatible = "st,stm32-mfd-timer8";
+			reg = <0x40010400 0x400>;
+			clocks = <&rcc 0 161>;
+			clock-names = "mfd_timer_clk";
+			interrupts = <46>;
+			status = "disabled";
+
+			pwm8: pwm8 at 40010400 {
+				compatible = "st,stm32-pwm8";
+				status = "disabled";
+			};
+
+			iiotimer8: iiotimer7 at 40010400 {
+				compatible = "st,stm32-iio-timer8";
+				status = "disabled";
+			};
+		};
+
+		mfd_timer9: mfdtimer9 at 40014000 {
+			compatible = "st,stm32-mfd-timer9";
+			reg = <0x40014000 0x400>;
+			clocks = <&rcc 0 176>;
+			clock-names = "mfd_timer_clk";
+			interrupts = <24>;
+			status = "disabled";
+
+			pwm9: pwm9 at 40014000 {
+				compatible = "st,stm32-pwm9";
+				status = "disabled";
+			};
+
+			iiotimer9: iiotimer9 at 40014000 {
+				compatible = "st,stm32-iio-timer9";
+				status = "disabled";
+			};
+		};
+
+		mfd_timer10: mfdtimer10 at 40014400 {
+			compatible = "st,stm32-mfd-timer10";
+			reg = <0x40014400 0x400>;
+			clocks = <&rcc 0 177>;
+			clock-names = "mfd_timer_clk";
+			interrupts = <25>;
+			status = "disabled";
+
+			pwm10: pwm10 at 40014400 {
+				compatible = "st,stm32-pwm10";
+				status = "disabled";
+			};
+		};
+
+		mfd_timer11: mfdtimer11 at 40014800 {
+			compatible = "st,stm32-mfd-timer11";
+			reg = <0x40014800 0x400>;
+			clocks = <&rcc 0 178>;
+			clock-names = "mfd_timer_clk";
+			interrupts = <26>;
+			status = "disabled";
+
+			pwm11: pwm11 at 40014800 {
+				compatible = "st,stm32-pwm11";
+				status = "disabled";
+			};
+		};
+
+		mfd_timer12: mfdtimer12 at 40001800 {
+			compatible = "st,stm32-mfd-timer12";
+			reg = <0x40001800 0x400>;
+			clocks = <&rcc 0 134>;
+			clock-names = "mfd_timer_clk";
+			interrupts = <43>;
+			status = "disabled";
+
+			pwm12: pwm12 at 40001800 {
+				compatible = "st,stm32-pwm12";
+				status = "disabled";
+			};
+			iiotimer12: iiotimer12 at 40001800 {
+				compatible = "st,stm32-iio-timer12";
+				status = "disabled";
+			};
+		};
+
+		mfd_timer13: mfdtimer13 at 40001C00 {
+			compatible = "st,stm32-mfd-timer13";
+			reg = <0x40001C00 0x400>;
+			clocks = <&rcc 0 135>;
+			clock-names = "mfd_timer_clk";
+			interrupts = <44>;
+			status = "disabled";
+
+			pwm13: pwm13 at 40001C00 {
+				compatible = "st,stm32-pwm13";
+				status = "disabled";
+			};
+		};
+
+		mfd_timer14: mfdtimer14 at 40002000 {
+			compatible = "st,stm32-mfd-timer14";
+			reg = <0x40002000 0x400>;
+			clocks = <&rcc 0 136>;
+			clock-names = "mfd_timer_clk";
+			interrupts = <45>;
+			status = "disabled";
+
+			pwm14: pwm14 at 40002000 {
+				compatible = "st,stm32-pwm14";
+				status = "disabled";
+			};
+		};
 	};
 };
 
diff --git a/arch/arm/boot/dts/stm32f469-disco.dts b/arch/arm/boot/dts/stm32f469-disco.dts
index 8a163d7..a8f1788 100644
--- a/arch/arm/boot/dts/stm32f469-disco.dts
+++ b/arch/arm/boot/dts/stm32f469-disco.dts
@@ -81,3 +81,32 @@
 &usart3 {
 	status = "okay";
 };
+
+&mfd_timer1 {
+	status = "okay";
+};
+
+&pwm1 {
+	pinctrl-0	= <&pwm1_pins>;
+	pinctrl-names	= "default";
+	st,breakinput-polarity = <0>;
+	status = "okay";
+};
+
+&iiotimer1 {
+	status = "okay";
+};
+
+&mfd_timer3 {
+	status = "okay";
+};
+
+&pwm3 {
+	pinctrl-0	= <&pwm3_pins>;
+	pinctrl-names	= "default";
+	status = "okay";
+};
+
+&iiotimer3 {
+	status = "okay";
+};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 64+ messages in thread

* Re: [PATCH 2/7] add MFD for stm32 timer IP
  2016-11-22 16:13   ` Benjamin Gaignard
@ 2016-11-22 16:30     ` Lee Jones
  -1 siblings, 0 replies; 64+ messages in thread
From: Lee Jones @ 2016-11-22 16:30 UTC (permalink / raw)
  To: Benjamin Gaignard
  Cc: robh+dt, mark.rutland, alexandre.torgue, devicetree,
	linux-kernel, thierry.reding, linux-pwm, jic23, knaack.h, lars,
	pmeerw, linux-iio, linux-arm-kernel, fabrice.gasnier,
	gerald.baeza, arnaud.pouliquen, linus.walleij, linaro-kernel,
	Benjamin Gaignard

On Tue, 22 Nov 2016, Benjamin Gaignard wrote:

> This hardware block could at used at same time for PWM generation
> and IIO timer for other IPs like DAC, ADC or other timers.
> PWM and IIO timer configuration are mixed in the same registers
> so we need a MFD to be able to share those registers.
> 
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
> ---
>  drivers/mfd/Kconfig                 |  10 ++
>  drivers/mfd/Makefile                |   2 +
>  drivers/mfd/stm32-mfd-timer.c       | 236 ++++++++++++++++++++++++++++++++++++
>  include/linux/mfd/stm32-mfd-timer.h |  78 ++++++++++++
>  4 files changed, 326 insertions(+)
>  create mode 100644 drivers/mfd/stm32-mfd-timer.c
>  create mode 100644 include/linux/mfd/stm32-mfd-timer.h

This driver is going to need a re-write.

However, it's difficult to provide suggestions, since I've been left
off of the Cc: list for all the other patches.

Please re-send the set with all of the Maintainers Cc'ed on all of
the patches.

> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index c6df644..63aee36 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -1607,6 +1607,15 @@ config MFD_STW481X
>  	  in various ST Microelectronics and ST-Ericsson embedded
>  	  Nomadik series.
>  
> +config MFD_STM32_TIMER
> +	tristate "Support for STM32 multifunctions timer"
> +	select MFD_CORE
> +	select REGMAP
> +	depends on ARCH_STM32
> +	depends on OF
> +	help
> +	  Select multifunction driver (pwm, IIO trigger) for stm32 timers
> +
>  menu "Multimedia Capabilities Port drivers"
>  	depends on ARCH_SA1100
>  
> @@ -1644,4 +1653,5 @@ config MFD_VEXPRESS_SYSREG
>  	  on the ARM Ltd. Versatile Express board.
>  
>  endmenu
> +
>  endif
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index 9834e66..b348c3e 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -211,3 +211,5 @@ obj-$(CONFIG_INTEL_SOC_PMIC)	+= intel-soc-pmic.o
>  obj-$(CONFIG_MFD_MT6397)	+= mt6397-core.o
>  
>  obj-$(CONFIG_MFD_ALTERA_A10SR)	+= altera-a10sr.o
> +
> +obj-$(CONFIG_MFD_STM32_TIMER) 	+= stm32-mfd-timer.o
> diff --git a/drivers/mfd/stm32-mfd-timer.c b/drivers/mfd/stm32-mfd-timer.c
> new file mode 100644
> index 0000000..67e7db3
> --- /dev/null
> +++ b/drivers/mfd/stm32-mfd-timer.c
> @@ -0,0 +1,236 @@
> +/*
> + * stm32-timer.c
> + *
> + * Copyright (C) STMicroelectronics 2016
> + * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
> + * License terms:  GNU General Public License (GPL), version 2
> + */
> +
> +#include <linux/device.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +
> +#include <linux/mfd/stm32-mfd-timer.h>
> +
> +static const struct stm32_mfd_timer_cfg mfd_cells_cfg[] = {
> +	{
> +		.pwm_name = "pwm1",
> +		.pwm_compatible = "st,stm32-pwm1",
> +		.trigger_name = "iiotimer1",
> +		.trigger_compatible = "st,stm32-iio-timer1",
> +	},
> +	{
> +		.pwm_name = "pwm2",
> +		.pwm_compatible = "st,stm32-pwm2",
> +		.trigger_name = "iiotimer2",
> +		.trigger_compatible = "st,stm32-iio-timer2",
> +	},
> +	{
> +		.pwm_name = "pwm3",
> +		.pwm_compatible = "st,stm32-pwm3",
> +		.trigger_name = "iiotimer3",
> +		.trigger_compatible = "st,stm32-iio-timer3",
> +	},
> +	{
> +		.pwm_name = "pwm4",
> +		.pwm_compatible = "st,stm32-pwm4",
> +		.trigger_name = "iiotimer4",
> +		.trigger_compatible = "st,stm32-iio-timer4",
> +	},
> +	{
> +		.pwm_name = "pwm5",
> +		.pwm_compatible = "st,stm32-pwm5",
> +		.trigger_name = "iiotimer5",
> +		.trigger_compatible = "st,stm32-iio-timer5",
> +	},
> +	{
> +		.trigger_name = "iiotimer6",
> +		.trigger_compatible = "st,stm32-iio-timer6",
> +	},
> +	{
> +		.trigger_name = "iiotimer7",
> +		.trigger_compatible = "st,stm32-iio-timer7",
> +	},
> +	{
> +		.pwm_name = "pwm8",
> +		.pwm_compatible = "st,stm32-pwm8",
> +		.trigger_name = "iiotimer8",
> +		.trigger_compatible = "st,stm32-iio-timer8",
> +	},
> +	{
> +		.pwm_name = "pwm9",
> +		.pwm_compatible = "st,stm32-pwm9",
> +		.trigger_name = "iiotimer9",
> +		.trigger_compatible = "st,stm32-iio-timer9",
> +	},
> +	{
> +		.pwm_name = "pwm10",
> +		.pwm_compatible = "st,stm32-pwm10",
> +	},
> +	{
> +		.pwm_name = "pwm11",
> +		.pwm_compatible = "st,stm32-pwm11",
> +	},
> +	{
> +		.pwm_name = "pwm12",
> +		.pwm_compatible = "st,stm32-pwm12",
> +		.trigger_name = "iiotimer12",
> +		.trigger_compatible = "st,stm32-iio-timer12",
> +	},
> +	{
> +		.pwm_name = "pwm13",
> +		.pwm_compatible = "st,stm32-pwm13",
> +	},
> +	{
> +		.pwm_name = "pwm14",
> +		.pwm_compatible = "st,stm32-pwm14",
> +	},
> +};
> +
> +static const struct of_device_id stm32_timer_of_match[] = {
> +	{
> +		.compatible = "st,stm32-mfd-timer1",
> +		.data = &mfd_cells_cfg[0],
> +	},
> +	{
> +		.compatible = "st,stm32-mfd-timer2",
> +		.data = &mfd_cells_cfg[1],
> +	},
> +	{
> +		.compatible = "st,stm32-mfd-timer3",
> +		.data = &mfd_cells_cfg[2],
> +	},
> +	{
> +		.compatible = "st,stm32-mfd-timer4",
> +		.data = &mfd_cells_cfg[3],
> +	},
> +	{
> +		.compatible = "st,stm32-mfd-timer5",
> +		.data = &mfd_cells_cfg[4],
> +	},
> +	{
> +		.compatible = "st,stm32-mfd-timer6",
> +		.data = &mfd_cells_cfg[5],
> +	},
> +	{
> +		.compatible = "st,stm32-mfd-timer7",
> +		.data = &mfd_cells_cfg[6],
> +	},
> +	{
> +		.compatible = "st,stm32-mfd-timer8",
> +		.data = &mfd_cells_cfg[7],
> +	},
> +	{
> +		.compatible = "st,stm32-mfd-timer9",
> +		.data = &mfd_cells_cfg[8],
> +	},
> +	{
> +		.compatible = "st,stm32-mfd-timer10",
> +		.data = &mfd_cells_cfg[9],
> +	},
> +	{
> +		.compatible = "st,stm32-mfd-timer11",
> +		.data = &mfd_cells_cfg[10],
> +	},
> +	{
> +		.compatible = "st,stm32-mfd-timer12",
> +		.data = &mfd_cells_cfg[11],
> +	},
> +	{
> +		.compatible = "st,stm32-mfd-timer13",
> +		.data = &mfd_cells_cfg[12],
> +	},
> +	{
> +		.compatible = "st,stm32-mfd-timer14",
> +		.data = &mfd_cells_cfg[13],
> +	},
> +};
> +
> +static const struct regmap_config stm32_timer_regmap_cfg = {
> +	.reg_bits = 32,
> +	.val_bits = 32,
> +	.reg_stride = sizeof(u32),
> +	.max_register = 0x400,
> +	.fast_io = true,
> +};
> +
> +static int stm32_mfd_timer_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct device_node *np = dev->of_node;
> +	struct stm32_mfd_timer_dev *mfd;
> +	struct resource *res;
> +	int ret, nb_cells = 0;
> +	struct mfd_cell *cell = NULL;
> +	void __iomem *mmio;
> +
> +	mfd = devm_kzalloc(dev, sizeof(*mfd), GFP_KERNEL);
> +	if (!mfd)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res)
> +		return -ENOMEM;
> +
> +	mmio = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(mmio))
> +		return PTR_ERR(mmio);
> +
> +	mfd->regmap = devm_regmap_init_mmio_clk(dev, "mfd_timer_clk", mmio,
> +						&stm32_timer_regmap_cfg);
> +	if (IS_ERR(mfd->regmap))
> +		return PTR_ERR(mfd->regmap);
> +
> +	mfd->clk = devm_clk_get(dev, NULL);
> +	if (IS_ERR(mfd->clk))
> +		return PTR_ERR(mfd->clk);
> +
> +	mfd->irq = platform_get_irq(pdev, 0);
> +	if (mfd->irq < 0)
> +		return -EINVAL;
> +
> +	/* populate data structure depending on compatibility */
> +	if (!of_match_node(stm32_timer_of_match, np)->data)
> +		return -EINVAL;
> +
> +	mfd->cfg =
> +	(struct stm32_mfd_timer_cfg *)of_match_node(stm32_timer_of_match, np)->data;
> +
> +	if (mfd->cfg->pwm_name && mfd->cfg->pwm_compatible) {
> +		cell = &mfd->cells[nb_cells++];
> +		cell->name = mfd->cfg->pwm_name;
> +		cell->of_compatible = mfd->cfg->pwm_compatible;
> +		cell->platform_data = mfd;
> +		cell->pdata_size = sizeof(*mfd);
> +	}
> +
> +	if (mfd->cfg->trigger_name && mfd->cfg->trigger_compatible) {
> +		cell = &mfd->cells[nb_cells++];
> +		cell->name = mfd->cfg->trigger_name;
> +		cell->of_compatible = mfd->cfg->trigger_compatible;
> +		cell->platform_data = mfd;
> +		cell->pdata_size = sizeof(*mfd);
> +	}
> +
> +	ret = devm_mfd_add_devices(&pdev->dev, pdev->id, mfd->cells,
> +				   nb_cells, NULL, 0, NULL);
> +	if (ret)
> +		return ret;
> +
> +	platform_set_drvdata(pdev, mfd);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver stm32_mfd_timer_driver = {
> +	.probe		= stm32_mfd_timer_probe,
> +	.driver	= {
> +		.name	= "stm32-mfd-timer",
> +		.of_match_table = stm32_timer_of_match,
> +	},
> +};
> +module_platform_driver(stm32_mfd_timer_driver);
> +
> +MODULE_DESCRIPTION("STMicroelectronics STM32 Timer MFD");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/mfd/stm32-mfd-timer.h b/include/linux/mfd/stm32-mfd-timer.h
> new file mode 100644
> index 0000000..4a79c22
> --- /dev/null
> +++ b/include/linux/mfd/stm32-mfd-timer.h
> @@ -0,0 +1,78 @@
> +/*
> + * stm32-mfd-timer.h
> + *
> + * Copyright (C) STMicroelectronics 2016
> + * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
> + * License terms:  GNU General Public License (GPL), version 2
> + */
> +
> +#ifndef _LINUX_MFD_STM32_TIMER_H_
> +#define _LINUX_MFD_STM32_TIMER_H_
> +
> +#include <linux/clk.h>
> +#include <linux/mfd/core.h>
> +#include <linux/regmap.h>
> +#include <linux/reset.h>
> +
> +#define TIM_CR1		0x00	/* Control Register 1      */
> +#define TIM_CR2		0x04	/* Control Register 2      */
> +#define TIM_SMCR	0x08	/* Slave mode control reg  */
> +#define TIM_DIER	0x0C	/* DMA/interrupt register  */
> +#define TIM_SR		0x10	/* Status register	   */
> +#define TIM_EGR		0x14	/* Event Generation Reg    */
> +#define TIM_CCMR1	0x18	/* Capt/Comp 1 Mode Reg    */
> +#define TIM_CCMR2	0x1C	/* Capt/Comp 2 Mode Reg    */
> +#define TIM_CCER	0x20	/* Capt/Comp Enable Reg    */
> +#define TIM_PSC		0x28	/* Prescaler               */
> +#define TIM_ARR		0x2c	/* Auto-Reload Register    */
> +#define TIM_CCR1	0x34	/* Capt/Comp Register 1    */
> +#define TIM_CCR2	0x38	/* Capt/Comp Register 2    */
> +#define TIM_CCR3	0x3C	/* Capt/Comp Register 3    */
> +#define TIM_CCR4	0x40	/* Capt/Comp Register 4    */
> +#define TIM_BDTR	0x44	/* Break and Dead-Time Reg */
> +
> +#define TIM_CR1_CEN	BIT(0)	/* Counter Enable	   */
> +#define TIM_CR1_ARPE	BIT(7)	/* Auto-reload Preload Ena */
> +#define TIM_CR2_MMS	(BIT(4) | BIT(5) | BIT(6)) /* Master mode selection */
> +#define TIM_SMCR_SMS	(BIT(0) | BIT(1) | BIT(2)) /* Slave mode selection */
> +#define TIM_SMCR_TS	(BIT(4) | BIT(5) | BIT(6)) /* Trigger selection */
> +#define TIM_DIER_UIE	BIT(0)	/* Update interrupt	   */
> +#define TIM_SR_UIF	BIT(0)	/* Update interrupt flag   */
> +#define TIM_EGR_UG	BIT(0)	/* Update Generation       */
> +#define TIM_CCMR_PE	BIT(3)	/* Channel Preload Enable  */
> +#define TIM_CCMR_M1	(BIT(6) | BIT(5))  /* Channel PWM Mode 1 */
> +#define TIM_CCER_CC1E	BIT(0)	/* Capt/Comp 1  out Ena    */
> +#define TIM_CCER_CC1P	BIT(1)	/* Capt/Comp 1  Polarity   */
> +#define TIM_CCER_CC1NE	BIT(2)	/* Capt/Comp 1N out Ena    */
> +#define TIM_CCER_CC1NP	BIT(3)	/* Capt/Comp 1N Polarity   */
> +#define TIM_CCER_CCXE	(BIT(0) | BIT(4) | BIT(8) | BIT(12))
> +#define TIM_BDTR_BKE	BIT(12) /* Break input enable	   */
> +#define TIM_BDTR_BKP	BIT(13) /* Break input polarity	   */
> +#define TIM_BDTR_AOE	BIT(14)	/* Automatic Output Enable */
> +#define TIM_BDTR_MOE	BIT(15)	/* Main Output Enable      */
> +
> +#define STM32_TIMER_CELLS	2
> +#define MAX_TIM_PSC		0xFFFF
> +
> +struct stm32_mfd_timer_cfg {
> +	const char *pwm_name;
> +	const char *pwm_compatible;
> +	const char *trigger_name;
> +	const char *trigger_compatible;
> +};
> +
> +struct stm32_mfd_timer_dev {
> +	/* Device data */
> +	struct device *dev;
> +	struct clk *clk;
> +	int irq;
> +
> +	/* Registers mapping */
> +	struct regmap *regmap;
> +
> +	/* Private data */
> +	struct mfd_cell cells[STM32_TIMER_CELLS];
> +	struct stm32_mfd_timer_cfg *cfg;
> +};
> +
> +#endif

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 64+ messages in thread

* [PATCH 2/7] add MFD for stm32 timer IP
@ 2016-11-22 16:30     ` Lee Jones
  0 siblings, 0 replies; 64+ messages in thread
From: Lee Jones @ 2016-11-22 16:30 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 22 Nov 2016, Benjamin Gaignard wrote:

> This hardware block could at used at same time for PWM generation
> and IIO timer for other IPs like DAC, ADC or other timers.
> PWM and IIO timer configuration are mixed in the same registers
> so we need a MFD to be able to share those registers.
> 
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
> ---
>  drivers/mfd/Kconfig                 |  10 ++
>  drivers/mfd/Makefile                |   2 +
>  drivers/mfd/stm32-mfd-timer.c       | 236 ++++++++++++++++++++++++++++++++++++
>  include/linux/mfd/stm32-mfd-timer.h |  78 ++++++++++++
>  4 files changed, 326 insertions(+)
>  create mode 100644 drivers/mfd/stm32-mfd-timer.c
>  create mode 100644 include/linux/mfd/stm32-mfd-timer.h

This driver is going to need a re-write.

However, it's difficult to provide suggestions, since I've been left
off of the Cc: list for all the other patches.

Please re-send the set with all of the Maintainers Cc'ed on all of
the patches.

> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index c6df644..63aee36 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -1607,6 +1607,15 @@ config MFD_STW481X
>  	  in various ST Microelectronics and ST-Ericsson embedded
>  	  Nomadik series.
>  
> +config MFD_STM32_TIMER
> +	tristate "Support for STM32 multifunctions timer"
> +	select MFD_CORE
> +	select REGMAP
> +	depends on ARCH_STM32
> +	depends on OF
> +	help
> +	  Select multifunction driver (pwm, IIO trigger) for stm32 timers
> +
>  menu "Multimedia Capabilities Port drivers"
>  	depends on ARCH_SA1100
>  
> @@ -1644,4 +1653,5 @@ config MFD_VEXPRESS_SYSREG
>  	  on the ARM Ltd. Versatile Express board.
>  
>  endmenu
> +
>  endif
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index 9834e66..b348c3e 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -211,3 +211,5 @@ obj-$(CONFIG_INTEL_SOC_PMIC)	+= intel-soc-pmic.o
>  obj-$(CONFIG_MFD_MT6397)	+= mt6397-core.o
>  
>  obj-$(CONFIG_MFD_ALTERA_A10SR)	+= altera-a10sr.o
> +
> +obj-$(CONFIG_MFD_STM32_TIMER) 	+= stm32-mfd-timer.o
> diff --git a/drivers/mfd/stm32-mfd-timer.c b/drivers/mfd/stm32-mfd-timer.c
> new file mode 100644
> index 0000000..67e7db3
> --- /dev/null
> +++ b/drivers/mfd/stm32-mfd-timer.c
> @@ -0,0 +1,236 @@
> +/*
> + * stm32-timer.c
> + *
> + * Copyright (C) STMicroelectronics 2016
> + * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
> + * License terms:  GNU General Public License (GPL), version 2
> + */
> +
> +#include <linux/device.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +
> +#include <linux/mfd/stm32-mfd-timer.h>
> +
> +static const struct stm32_mfd_timer_cfg mfd_cells_cfg[] = {
> +	{
> +		.pwm_name = "pwm1",
> +		.pwm_compatible = "st,stm32-pwm1",
> +		.trigger_name = "iiotimer1",
> +		.trigger_compatible = "st,stm32-iio-timer1",
> +	},
> +	{
> +		.pwm_name = "pwm2",
> +		.pwm_compatible = "st,stm32-pwm2",
> +		.trigger_name = "iiotimer2",
> +		.trigger_compatible = "st,stm32-iio-timer2",
> +	},
> +	{
> +		.pwm_name = "pwm3",
> +		.pwm_compatible = "st,stm32-pwm3",
> +		.trigger_name = "iiotimer3",
> +		.trigger_compatible = "st,stm32-iio-timer3",
> +	},
> +	{
> +		.pwm_name = "pwm4",
> +		.pwm_compatible = "st,stm32-pwm4",
> +		.trigger_name = "iiotimer4",
> +		.trigger_compatible = "st,stm32-iio-timer4",
> +	},
> +	{
> +		.pwm_name = "pwm5",
> +		.pwm_compatible = "st,stm32-pwm5",
> +		.trigger_name = "iiotimer5",
> +		.trigger_compatible = "st,stm32-iio-timer5",
> +	},
> +	{
> +		.trigger_name = "iiotimer6",
> +		.trigger_compatible = "st,stm32-iio-timer6",
> +	},
> +	{
> +		.trigger_name = "iiotimer7",
> +		.trigger_compatible = "st,stm32-iio-timer7",
> +	},
> +	{
> +		.pwm_name = "pwm8",
> +		.pwm_compatible = "st,stm32-pwm8",
> +		.trigger_name = "iiotimer8",
> +		.trigger_compatible = "st,stm32-iio-timer8",
> +	},
> +	{
> +		.pwm_name = "pwm9",
> +		.pwm_compatible = "st,stm32-pwm9",
> +		.trigger_name = "iiotimer9",
> +		.trigger_compatible = "st,stm32-iio-timer9",
> +	},
> +	{
> +		.pwm_name = "pwm10",
> +		.pwm_compatible = "st,stm32-pwm10",
> +	},
> +	{
> +		.pwm_name = "pwm11",
> +		.pwm_compatible = "st,stm32-pwm11",
> +	},
> +	{
> +		.pwm_name = "pwm12",
> +		.pwm_compatible = "st,stm32-pwm12",
> +		.trigger_name = "iiotimer12",
> +		.trigger_compatible = "st,stm32-iio-timer12",
> +	},
> +	{
> +		.pwm_name = "pwm13",
> +		.pwm_compatible = "st,stm32-pwm13",
> +	},
> +	{
> +		.pwm_name = "pwm14",
> +		.pwm_compatible = "st,stm32-pwm14",
> +	},
> +};
> +
> +static const struct of_device_id stm32_timer_of_match[] = {
> +	{
> +		.compatible = "st,stm32-mfd-timer1",
> +		.data = &mfd_cells_cfg[0],
> +	},
> +	{
> +		.compatible = "st,stm32-mfd-timer2",
> +		.data = &mfd_cells_cfg[1],
> +	},
> +	{
> +		.compatible = "st,stm32-mfd-timer3",
> +		.data = &mfd_cells_cfg[2],
> +	},
> +	{
> +		.compatible = "st,stm32-mfd-timer4",
> +		.data = &mfd_cells_cfg[3],
> +	},
> +	{
> +		.compatible = "st,stm32-mfd-timer5",
> +		.data = &mfd_cells_cfg[4],
> +	},
> +	{
> +		.compatible = "st,stm32-mfd-timer6",
> +		.data = &mfd_cells_cfg[5],
> +	},
> +	{
> +		.compatible = "st,stm32-mfd-timer7",
> +		.data = &mfd_cells_cfg[6],
> +	},
> +	{
> +		.compatible = "st,stm32-mfd-timer8",
> +		.data = &mfd_cells_cfg[7],
> +	},
> +	{
> +		.compatible = "st,stm32-mfd-timer9",
> +		.data = &mfd_cells_cfg[8],
> +	},
> +	{
> +		.compatible = "st,stm32-mfd-timer10",
> +		.data = &mfd_cells_cfg[9],
> +	},
> +	{
> +		.compatible = "st,stm32-mfd-timer11",
> +		.data = &mfd_cells_cfg[10],
> +	},
> +	{
> +		.compatible = "st,stm32-mfd-timer12",
> +		.data = &mfd_cells_cfg[11],
> +	},
> +	{
> +		.compatible = "st,stm32-mfd-timer13",
> +		.data = &mfd_cells_cfg[12],
> +	},
> +	{
> +		.compatible = "st,stm32-mfd-timer14",
> +		.data = &mfd_cells_cfg[13],
> +	},
> +};
> +
> +static const struct regmap_config stm32_timer_regmap_cfg = {
> +	.reg_bits = 32,
> +	.val_bits = 32,
> +	.reg_stride = sizeof(u32),
> +	.max_register = 0x400,
> +	.fast_io = true,
> +};
> +
> +static int stm32_mfd_timer_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct device_node *np = dev->of_node;
> +	struct stm32_mfd_timer_dev *mfd;
> +	struct resource *res;
> +	int ret, nb_cells = 0;
> +	struct mfd_cell *cell = NULL;
> +	void __iomem *mmio;
> +
> +	mfd = devm_kzalloc(dev, sizeof(*mfd), GFP_KERNEL);
> +	if (!mfd)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res)
> +		return -ENOMEM;
> +
> +	mmio = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(mmio))
> +		return PTR_ERR(mmio);
> +
> +	mfd->regmap = devm_regmap_init_mmio_clk(dev, "mfd_timer_clk", mmio,
> +						&stm32_timer_regmap_cfg);
> +	if (IS_ERR(mfd->regmap))
> +		return PTR_ERR(mfd->regmap);
> +
> +	mfd->clk = devm_clk_get(dev, NULL);
> +	if (IS_ERR(mfd->clk))
> +		return PTR_ERR(mfd->clk);
> +
> +	mfd->irq = platform_get_irq(pdev, 0);
> +	if (mfd->irq < 0)
> +		return -EINVAL;
> +
> +	/* populate data structure depending on compatibility */
> +	if (!of_match_node(stm32_timer_of_match, np)->data)
> +		return -EINVAL;
> +
> +	mfd->cfg =
> +	(struct stm32_mfd_timer_cfg *)of_match_node(stm32_timer_of_match, np)->data;
> +
> +	if (mfd->cfg->pwm_name && mfd->cfg->pwm_compatible) {
> +		cell = &mfd->cells[nb_cells++];
> +		cell->name = mfd->cfg->pwm_name;
> +		cell->of_compatible = mfd->cfg->pwm_compatible;
> +		cell->platform_data = mfd;
> +		cell->pdata_size = sizeof(*mfd);
> +	}
> +
> +	if (mfd->cfg->trigger_name && mfd->cfg->trigger_compatible) {
> +		cell = &mfd->cells[nb_cells++];
> +		cell->name = mfd->cfg->trigger_name;
> +		cell->of_compatible = mfd->cfg->trigger_compatible;
> +		cell->platform_data = mfd;
> +		cell->pdata_size = sizeof(*mfd);
> +	}
> +
> +	ret = devm_mfd_add_devices(&pdev->dev, pdev->id, mfd->cells,
> +				   nb_cells, NULL, 0, NULL);
> +	if (ret)
> +		return ret;
> +
> +	platform_set_drvdata(pdev, mfd);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver stm32_mfd_timer_driver = {
> +	.probe		= stm32_mfd_timer_probe,
> +	.driver	= {
> +		.name	= "stm32-mfd-timer",
> +		.of_match_table = stm32_timer_of_match,
> +	},
> +};
> +module_platform_driver(stm32_mfd_timer_driver);
> +
> +MODULE_DESCRIPTION("STMicroelectronics STM32 Timer MFD");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/mfd/stm32-mfd-timer.h b/include/linux/mfd/stm32-mfd-timer.h
> new file mode 100644
> index 0000000..4a79c22
> --- /dev/null
> +++ b/include/linux/mfd/stm32-mfd-timer.h
> @@ -0,0 +1,78 @@
> +/*
> + * stm32-mfd-timer.h
> + *
> + * Copyright (C) STMicroelectronics 2016
> + * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
> + * License terms:  GNU General Public License (GPL), version 2
> + */
> +
> +#ifndef _LINUX_MFD_STM32_TIMER_H_
> +#define _LINUX_MFD_STM32_TIMER_H_
> +
> +#include <linux/clk.h>
> +#include <linux/mfd/core.h>
> +#include <linux/regmap.h>
> +#include <linux/reset.h>
> +
> +#define TIM_CR1		0x00	/* Control Register 1      */
> +#define TIM_CR2		0x04	/* Control Register 2      */
> +#define TIM_SMCR	0x08	/* Slave mode control reg  */
> +#define TIM_DIER	0x0C	/* DMA/interrupt register  */
> +#define TIM_SR		0x10	/* Status register	   */
> +#define TIM_EGR		0x14	/* Event Generation Reg    */
> +#define TIM_CCMR1	0x18	/* Capt/Comp 1 Mode Reg    */
> +#define TIM_CCMR2	0x1C	/* Capt/Comp 2 Mode Reg    */
> +#define TIM_CCER	0x20	/* Capt/Comp Enable Reg    */
> +#define TIM_PSC		0x28	/* Prescaler               */
> +#define TIM_ARR		0x2c	/* Auto-Reload Register    */
> +#define TIM_CCR1	0x34	/* Capt/Comp Register 1    */
> +#define TIM_CCR2	0x38	/* Capt/Comp Register 2    */
> +#define TIM_CCR3	0x3C	/* Capt/Comp Register 3    */
> +#define TIM_CCR4	0x40	/* Capt/Comp Register 4    */
> +#define TIM_BDTR	0x44	/* Break and Dead-Time Reg */
> +
> +#define TIM_CR1_CEN	BIT(0)	/* Counter Enable	   */
> +#define TIM_CR1_ARPE	BIT(7)	/* Auto-reload Preload Ena */
> +#define TIM_CR2_MMS	(BIT(4) | BIT(5) | BIT(6)) /* Master mode selection */
> +#define TIM_SMCR_SMS	(BIT(0) | BIT(1) | BIT(2)) /* Slave mode selection */
> +#define TIM_SMCR_TS	(BIT(4) | BIT(5) | BIT(6)) /* Trigger selection */
> +#define TIM_DIER_UIE	BIT(0)	/* Update interrupt	   */
> +#define TIM_SR_UIF	BIT(0)	/* Update interrupt flag   */
> +#define TIM_EGR_UG	BIT(0)	/* Update Generation       */
> +#define TIM_CCMR_PE	BIT(3)	/* Channel Preload Enable  */
> +#define TIM_CCMR_M1	(BIT(6) | BIT(5))  /* Channel PWM Mode 1 */
> +#define TIM_CCER_CC1E	BIT(0)	/* Capt/Comp 1  out Ena    */
> +#define TIM_CCER_CC1P	BIT(1)	/* Capt/Comp 1  Polarity   */
> +#define TIM_CCER_CC1NE	BIT(2)	/* Capt/Comp 1N out Ena    */
> +#define TIM_CCER_CC1NP	BIT(3)	/* Capt/Comp 1N Polarity   */
> +#define TIM_CCER_CCXE	(BIT(0) | BIT(4) | BIT(8) | BIT(12))
> +#define TIM_BDTR_BKE	BIT(12) /* Break input enable	   */
> +#define TIM_BDTR_BKP	BIT(13) /* Break input polarity	   */
> +#define TIM_BDTR_AOE	BIT(14)	/* Automatic Output Enable */
> +#define TIM_BDTR_MOE	BIT(15)	/* Main Output Enable      */
> +
> +#define STM32_TIMER_CELLS	2
> +#define MAX_TIM_PSC		0xFFFF
> +
> +struct stm32_mfd_timer_cfg {
> +	const char *pwm_name;
> +	const char *pwm_compatible;
> +	const char *trigger_name;
> +	const char *trigger_compatible;
> +};
> +
> +struct stm32_mfd_timer_dev {
> +	/* Device data */
> +	struct device *dev;
> +	struct clk *clk;
> +	int irq;
> +
> +	/* Registers mapping */
> +	struct regmap *regmap;
> +
> +	/* Private data */
> +	struct mfd_cell cells[STM32_TIMER_CELLS];
> +	struct stm32_mfd_timer_cfg *cfg;
> +};
> +
> +#endif

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 2/7] add MFD for stm32 timer IP
  2016-11-22 16:41       ` Lee Jones
  (?)
@ 2016-11-22 16:40         ` Benjamin Gaignard
  -1 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-22 16:40 UTC (permalink / raw)
  To: Lee Jones
  Cc: robh+dt, Mark Rutland, alexandre.torgue, devicetree,
	Linux Kernel Mailing List, Thierry Reding, linux-pwm, jic23,
	knaack.h, Lars-Peter Clausen, Peter Meerwald-Stadler, linux-iio,
	linux-arm-kernel, Fabrice Gasnier, Gerald Baeza,
	Arnaud Pouliquen, Linus Walleij, Linaro Kernel Mailman List,
	Benjamin Gaignard

Your comments are welcome on all of them ;-)

2016-11-22 17:41 GMT+01:00 Lee Jones <lee.jones@linaro.org>:
> On Tue, 22 Nov 2016, Lee Jones wrote:
>
>> On Tue, 22 Nov 2016, Benjamin Gaignard wrote:
>>
>> > This hardware block could at used at same time for PWM generation
>> > and IIO timer for other IPs like DAC, ADC or other timers.
>> > PWM and IIO timer configuration are mixed in the same registers
>> > so we need a MFD to be able to share those registers.
>> >
>> > Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
>> > ---
>> >  drivers/mfd/Kconfig                 |  10 ++
>> >  drivers/mfd/Makefile                |   2 +
>> >  drivers/mfd/stm32-mfd-timer.c       | 236 ++++++++++++++++++++++++++++++++++++
>> >  include/linux/mfd/stm32-mfd-timer.h |  78 ++++++++++++
>> >  4 files changed, 326 insertions(+)
>> >  create mode 100644 drivers/mfd/stm32-mfd-timer.c
>> >  create mode 100644 include/linux/mfd/stm32-mfd-timer.h
>>
>> This driver is going to need a re-write.
>>
>> However, it's difficult to provide suggestions, since I've been left
>> off of the Cc: list for all the other patches.
>>
>> Please re-send the set with all of the Maintainers Cc'ed on all of
>> the patches.
>
> Scrap that -- they all just came trickling through!
>
>> > diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
>> > index c6df644..63aee36 100644
>> > --- a/drivers/mfd/Kconfig
>> > +++ b/drivers/mfd/Kconfig
>> > @@ -1607,6 +1607,15 @@ config MFD_STW481X
>> >       in various ST Microelectronics and ST-Ericsson embedded
>> >       Nomadik series.
>> >
>> > +config MFD_STM32_TIMER
>> > +   tristate "Support for STM32 multifunctions timer"
>> > +   select MFD_CORE
>> > +   select REGMAP
>> > +   depends on ARCH_STM32
>> > +   depends on OF
>> > +   help
>> > +     Select multifunction driver (pwm, IIO trigger) for stm32 timers
>> > +
>> >  menu "Multimedia Capabilities Port drivers"
>> >     depends on ARCH_SA1100
>> >
>> > @@ -1644,4 +1653,5 @@ config MFD_VEXPRESS_SYSREG
>> >       on the ARM Ltd. Versatile Express board.
>> >
>> >  endmenu
>> > +
>> >  endif
>> > diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
>> > index 9834e66..b348c3e 100644
>> > --- a/drivers/mfd/Makefile
>> > +++ b/drivers/mfd/Makefile
>> > @@ -211,3 +211,5 @@ obj-$(CONFIG_INTEL_SOC_PMIC)    += intel-soc-pmic.o
>> >  obj-$(CONFIG_MFD_MT6397)   += mt6397-core.o
>> >
>> >  obj-$(CONFIG_MFD_ALTERA_A10SR)     += altera-a10sr.o
>> > +
>> > +obj-$(CONFIG_MFD_STM32_TIMER)      += stm32-mfd-timer.o
>> > diff --git a/drivers/mfd/stm32-mfd-timer.c b/drivers/mfd/stm32-mfd-timer.c
>> > new file mode 100644
>> > index 0000000..67e7db3
>> > --- /dev/null
>> > +++ b/drivers/mfd/stm32-mfd-timer.c
>> > @@ -0,0 +1,236 @@
>> > +/*
>> > + * stm32-timer.c
>> > + *
>> > + * Copyright (C) STMicroelectronics 2016
>> > + * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
>> > + * License terms:  GNU General Public License (GPL), version 2
>> > + */
>> > +
>> > +#include <linux/device.h>
>> > +#include <linux/init.h>
>> > +#include <linux/module.h>
>> > +#include <linux/of.h>
>> > +
>> > +#include <linux/mfd/stm32-mfd-timer.h>
>> > +
>> > +static const struct stm32_mfd_timer_cfg mfd_cells_cfg[] = {
>> > +   {
>> > +           .pwm_name = "pwm1",
>> > +           .pwm_compatible = "st,stm32-pwm1",
>> > +           .trigger_name = "iiotimer1",
>> > +           .trigger_compatible = "st,stm32-iio-timer1",
>> > +   },
>> > +   {
>> > +           .pwm_name = "pwm2",
>> > +           .pwm_compatible = "st,stm32-pwm2",
>> > +           .trigger_name = "iiotimer2",
>> > +           .trigger_compatible = "st,stm32-iio-timer2",
>> > +   },
>> > +   {
>> > +           .pwm_name = "pwm3",
>> > +           .pwm_compatible = "st,stm32-pwm3",
>> > +           .trigger_name = "iiotimer3",
>> > +           .trigger_compatible = "st,stm32-iio-timer3",
>> > +   },
>> > +   {
>> > +           .pwm_name = "pwm4",
>> > +           .pwm_compatible = "st,stm32-pwm4",
>> > +           .trigger_name = "iiotimer4",
>> > +           .trigger_compatible = "st,stm32-iio-timer4",
>> > +   },
>> > +   {
>> > +           .pwm_name = "pwm5",
>> > +           .pwm_compatible = "st,stm32-pwm5",
>> > +           .trigger_name = "iiotimer5",
>> > +           .trigger_compatible = "st,stm32-iio-timer5",
>> > +   },
>> > +   {
>> > +           .trigger_name = "iiotimer6",
>> > +           .trigger_compatible = "st,stm32-iio-timer6",
>> > +   },
>> > +   {
>> > +           .trigger_name = "iiotimer7",
>> > +           .trigger_compatible = "st,stm32-iio-timer7",
>> > +   },
>> > +   {
>> > +           .pwm_name = "pwm8",
>> > +           .pwm_compatible = "st,stm32-pwm8",
>> > +           .trigger_name = "iiotimer8",
>> > +           .trigger_compatible = "st,stm32-iio-timer8",
>> > +   },
>> > +   {
>> > +           .pwm_name = "pwm9",
>> > +           .pwm_compatible = "st,stm32-pwm9",
>> > +           .trigger_name = "iiotimer9",
>> > +           .trigger_compatible = "st,stm32-iio-timer9",
>> > +   },
>> > +   {
>> > +           .pwm_name = "pwm10",
>> > +           .pwm_compatible = "st,stm32-pwm10",
>> > +   },
>> > +   {
>> > +           .pwm_name = "pwm11",
>> > +           .pwm_compatible = "st,stm32-pwm11",
>> > +   },
>> > +   {
>> > +           .pwm_name = "pwm12",
>> > +           .pwm_compatible = "st,stm32-pwm12",
>> > +           .trigger_name = "iiotimer12",
>> > +           .trigger_compatible = "st,stm32-iio-timer12",
>> > +   },
>> > +   {
>> > +           .pwm_name = "pwm13",
>> > +           .pwm_compatible = "st,stm32-pwm13",
>> > +   },
>> > +   {
>> > +           .pwm_name = "pwm14",
>> > +           .pwm_compatible = "st,stm32-pwm14",
>> > +   },
>> > +};
>> > +
>> > +static const struct of_device_id stm32_timer_of_match[] = {
>> > +   {
>> > +           .compatible = "st,stm32-mfd-timer1",
>> > +           .data = &mfd_cells_cfg[0],
>> > +   },
>> > +   {
>> > +           .compatible = "st,stm32-mfd-timer2",
>> > +           .data = &mfd_cells_cfg[1],
>> > +   },
>> > +   {
>> > +           .compatible = "st,stm32-mfd-timer3",
>> > +           .data = &mfd_cells_cfg[2],
>> > +   },
>> > +   {
>> > +           .compatible = "st,stm32-mfd-timer4",
>> > +           .data = &mfd_cells_cfg[3],
>> > +   },
>> > +   {
>> > +           .compatible = "st,stm32-mfd-timer5",
>> > +           .data = &mfd_cells_cfg[4],
>> > +   },
>> > +   {
>> > +           .compatible = "st,stm32-mfd-timer6",
>> > +           .data = &mfd_cells_cfg[5],
>> > +   },
>> > +   {
>> > +           .compatible = "st,stm32-mfd-timer7",
>> > +           .data = &mfd_cells_cfg[6],
>> > +   },
>> > +   {
>> > +           .compatible = "st,stm32-mfd-timer8",
>> > +           .data = &mfd_cells_cfg[7],
>> > +   },
>> > +   {
>> > +           .compatible = "st,stm32-mfd-timer9",
>> > +           .data = &mfd_cells_cfg[8],
>> > +   },
>> > +   {
>> > +           .compatible = "st,stm32-mfd-timer10",
>> > +           .data = &mfd_cells_cfg[9],
>> > +   },
>> > +   {
>> > +           .compatible = "st,stm32-mfd-timer11",
>> > +           .data = &mfd_cells_cfg[10],
>> > +   },
>> > +   {
>> > +           .compatible = "st,stm32-mfd-timer12",
>> > +           .data = &mfd_cells_cfg[11],
>> > +   },
>> > +   {
>> > +           .compatible = "st,stm32-mfd-timer13",
>> > +           .data = &mfd_cells_cfg[12],
>> > +   },
>> > +   {
>> > +           .compatible = "st,stm32-mfd-timer14",
>> > +           .data = &mfd_cells_cfg[13],
>> > +   },
>> > +};
>> > +
>> > +static const struct regmap_config stm32_timer_regmap_cfg = {
>> > +   .reg_bits = 32,
>> > +   .val_bits = 32,
>> > +   .reg_stride = sizeof(u32),
>> > +   .max_register = 0x400,
>> > +   .fast_io = true,
>> > +};
>> > +
>> > +static int stm32_mfd_timer_probe(struct platform_device *pdev)
>> > +{
>> > +   struct device *dev = &pdev->dev;
>> > +   struct device_node *np = dev->of_node;
>> > +   struct stm32_mfd_timer_dev *mfd;
>> > +   struct resource *res;
>> > +   int ret, nb_cells = 0;
>> > +   struct mfd_cell *cell = NULL;
>> > +   void __iomem *mmio;
>> > +
>> > +   mfd = devm_kzalloc(dev, sizeof(*mfd), GFP_KERNEL);
>> > +   if (!mfd)
>> > +           return -ENOMEM;
>> > +
>> > +   res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> > +   if (!res)
>> > +           return -ENOMEM;
>> > +
>> > +   mmio = devm_ioremap_resource(dev, res);
>> > +   if (IS_ERR(mmio))
>> > +           return PTR_ERR(mmio);
>> > +
>> > +   mfd->regmap = devm_regmap_init_mmio_clk(dev, "mfd_timer_clk", mmio,
>> > +                                           &stm32_timer_regmap_cfg);
>> > +   if (IS_ERR(mfd->regmap))
>> > +           return PTR_ERR(mfd->regmap);
>> > +
>> > +   mfd->clk = devm_clk_get(dev, NULL);
>> > +   if (IS_ERR(mfd->clk))
>> > +           return PTR_ERR(mfd->clk);
>> > +
>> > +   mfd->irq = platform_get_irq(pdev, 0);
>> > +   if (mfd->irq < 0)
>> > +           return -EINVAL;
>> > +
>> > +   /* populate data structure depending on compatibility */
>> > +   if (!of_match_node(stm32_timer_of_match, np)->data)
>> > +           return -EINVAL;
>> > +
>> > +   mfd->cfg =
>> > +   (struct stm32_mfd_timer_cfg *)of_match_node(stm32_timer_of_match, np)->data;
>> > +
>> > +   if (mfd->cfg->pwm_name && mfd->cfg->pwm_compatible) {
>> > +           cell = &mfd->cells[nb_cells++];
>> > +           cell->name = mfd->cfg->pwm_name;
>> > +           cell->of_compatible = mfd->cfg->pwm_compatible;
>> > +           cell->platform_data = mfd;
>> > +           cell->pdata_size = sizeof(*mfd);
>> > +   }
>> > +
>> > +   if (mfd->cfg->trigger_name && mfd->cfg->trigger_compatible) {
>> > +           cell = &mfd->cells[nb_cells++];
>> > +           cell->name = mfd->cfg->trigger_name;
>> > +           cell->of_compatible = mfd->cfg->trigger_compatible;
>> > +           cell->platform_data = mfd;
>> > +           cell->pdata_size = sizeof(*mfd);
>> > +   }
>> > +
>> > +   ret = devm_mfd_add_devices(&pdev->dev, pdev->id, mfd->cells,
>> > +                              nb_cells, NULL, 0, NULL);
>> > +   if (ret)
>> > +           return ret;
>> > +
>> > +   platform_set_drvdata(pdev, mfd);
>> > +
>> > +   return 0;
>> > +}
>> > +
>> > +static struct platform_driver stm32_mfd_timer_driver = {
>> > +   .probe          = stm32_mfd_timer_probe,
>> > +   .driver = {
>> > +           .name   = "stm32-mfd-timer",
>> > +           .of_match_table = stm32_timer_of_match,
>> > +   },
>> > +};
>> > +module_platform_driver(stm32_mfd_timer_driver);
>> > +
>> > +MODULE_DESCRIPTION("STMicroelectronics STM32 Timer MFD");
>> > +MODULE_LICENSE("GPL");
>> > diff --git a/include/linux/mfd/stm32-mfd-timer.h b/include/linux/mfd/stm32-mfd-timer.h
>> > new file mode 100644
>> > index 0000000..4a79c22
>> > --- /dev/null
>> > +++ b/include/linux/mfd/stm32-mfd-timer.h
>> > @@ -0,0 +1,78 @@
>> > +/*
>> > + * stm32-mfd-timer.h
>> > + *
>> > + * Copyright (C) STMicroelectronics 2016
>> > + * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
>> > + * License terms:  GNU General Public License (GPL), version 2
>> > + */
>> > +
>> > +#ifndef _LINUX_MFD_STM32_TIMER_H_
>> > +#define _LINUX_MFD_STM32_TIMER_H_
>> > +
>> > +#include <linux/clk.h>
>> > +#include <linux/mfd/core.h>
>> > +#include <linux/regmap.h>
>> > +#include <linux/reset.h>
>> > +
>> > +#define TIM_CR1            0x00    /* Control Register 1      */
>> > +#define TIM_CR2            0x04    /* Control Register 2      */
>> > +#define TIM_SMCR   0x08    /* Slave mode control reg  */
>> > +#define TIM_DIER   0x0C    /* DMA/interrupt register  */
>> > +#define TIM_SR             0x10    /* Status register         */
>> > +#define TIM_EGR            0x14    /* Event Generation Reg    */
>> > +#define TIM_CCMR1  0x18    /* Capt/Comp 1 Mode Reg    */
>> > +#define TIM_CCMR2  0x1C    /* Capt/Comp 2 Mode Reg    */
>> > +#define TIM_CCER   0x20    /* Capt/Comp Enable Reg    */
>> > +#define TIM_PSC            0x28    /* Prescaler               */
>> > +#define TIM_ARR            0x2c    /* Auto-Reload Register    */
>> > +#define TIM_CCR1   0x34    /* Capt/Comp Register 1    */
>> > +#define TIM_CCR2   0x38    /* Capt/Comp Register 2    */
>> > +#define TIM_CCR3   0x3C    /* Capt/Comp Register 3    */
>> > +#define TIM_CCR4   0x40    /* Capt/Comp Register 4    */
>> > +#define TIM_BDTR   0x44    /* Break and Dead-Time Reg */
>> > +
>> > +#define TIM_CR1_CEN        BIT(0)  /* Counter Enable          */
>> > +#define TIM_CR1_ARPE       BIT(7)  /* Auto-reload Preload Ena */
>> > +#define TIM_CR2_MMS        (BIT(4) | BIT(5) | BIT(6)) /* Master mode selection */
>> > +#define TIM_SMCR_SMS       (BIT(0) | BIT(1) | BIT(2)) /* Slave mode selection */
>> > +#define TIM_SMCR_TS        (BIT(4) | BIT(5) | BIT(6)) /* Trigger selection */
>> > +#define TIM_DIER_UIE       BIT(0)  /* Update interrupt        */
>> > +#define TIM_SR_UIF BIT(0)  /* Update interrupt flag   */
>> > +#define TIM_EGR_UG BIT(0)  /* Update Generation       */
>> > +#define TIM_CCMR_PE        BIT(3)  /* Channel Preload Enable  */
>> > +#define TIM_CCMR_M1        (BIT(6) | BIT(5))  /* Channel PWM Mode 1 */
>> > +#define TIM_CCER_CC1E      BIT(0)  /* Capt/Comp 1  out Ena    */
>> > +#define TIM_CCER_CC1P      BIT(1)  /* Capt/Comp 1  Polarity   */
>> > +#define TIM_CCER_CC1NE     BIT(2)  /* Capt/Comp 1N out Ena    */
>> > +#define TIM_CCER_CC1NP     BIT(3)  /* Capt/Comp 1N Polarity   */
>> > +#define TIM_CCER_CCXE      (BIT(0) | BIT(4) | BIT(8) | BIT(12))
>> > +#define TIM_BDTR_BKE       BIT(12) /* Break input enable      */
>> > +#define TIM_BDTR_BKP       BIT(13) /* Break input polarity    */
>> > +#define TIM_BDTR_AOE       BIT(14) /* Automatic Output Enable */
>> > +#define TIM_BDTR_MOE       BIT(15) /* Main Output Enable      */
>> > +
>> > +#define STM32_TIMER_CELLS  2
>> > +#define MAX_TIM_PSC                0xFFFF
>> > +
>> > +struct stm32_mfd_timer_cfg {
>> > +   const char *pwm_name;
>> > +   const char *pwm_compatible;
>> > +   const char *trigger_name;
>> > +   const char *trigger_compatible;
>> > +};
>> > +
>> > +struct stm32_mfd_timer_dev {
>> > +   /* Device data */
>> > +   struct device *dev;
>> > +   struct clk *clk;
>> > +   int irq;
>> > +
>> > +   /* Registers mapping */
>> > +   struct regmap *regmap;
>> > +
>> > +   /* Private data */
>> > +   struct mfd_cell cells[STM32_TIMER_CELLS];
>> > +   struct stm32_mfd_timer_cfg *cfg;
>> > +};
>> > +
>> > +#endif
>>
>
> --
> Lee Jones
> Linaro STMicroelectronics Landing Team Lead
> Linaro.org │ Open source software for ARM SoCs
> Follow Linaro: Facebook | Twitter | Blog



-- 
Benjamin Gaignard

Graphic Study Group

Linaro.org │ Open source software for ARM SoCs

Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 2/7] add MFD for stm32 timer IP
@ 2016-11-22 16:40         ` Benjamin Gaignard
  0 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-22 16:40 UTC (permalink / raw)
  To: Lee Jones
  Cc: robh+dt, Mark Rutland, alexandre.torgue, devicetree,
	Linux Kernel Mailing List, Thierry Reding, linux-pwm, jic23,
	knaack.h, Lars-Peter Clausen, Peter Meerwald-Stadler, linux-iio,
	linux-arm-kernel, Fabrice Gasnier, Gerald Baeza,
	Arnaud Pouliquen, Linus Walleij, Linaro Kernel Mailman List,
	Benjamin Gaignard

Your comments are welcome on all of them ;-)

2016-11-22 17:41 GMT+01:00 Lee Jones <lee.jones@linaro.org>:
> On Tue, 22 Nov 2016, Lee Jones wrote:
>
>> On Tue, 22 Nov 2016, Benjamin Gaignard wrote:
>>
>> > This hardware block could at used at same time for PWM generation
>> > and IIO timer for other IPs like DAC, ADC or other timers.
>> > PWM and IIO timer configuration are mixed in the same registers
>> > so we need a MFD to be able to share those registers.
>> >
>> > Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
>> > ---
>> >  drivers/mfd/Kconfig                 |  10 ++
>> >  drivers/mfd/Makefile                |   2 +
>> >  drivers/mfd/stm32-mfd-timer.c       | 236 +++++++++++++++++++++++++++=
+++++++++
>> >  include/linux/mfd/stm32-mfd-timer.h |  78 ++++++++++++
>> >  4 files changed, 326 insertions(+)
>> >  create mode 100644 drivers/mfd/stm32-mfd-timer.c
>> >  create mode 100644 include/linux/mfd/stm32-mfd-timer.h
>>
>> This driver is going to need a re-write.
>>
>> However, it's difficult to provide suggestions, since I've been left
>> off of the Cc: list for all the other patches.
>>
>> Please re-send the set with all of the Maintainers Cc'ed on all of
>> the patches.
>
> Scrap that -- they all just came trickling through!
>
>> > diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
>> > index c6df644..63aee36 100644
>> > --- a/drivers/mfd/Kconfig
>> > +++ b/drivers/mfd/Kconfig
>> > @@ -1607,6 +1607,15 @@ config MFD_STW481X
>> >       in various ST Microelectronics and ST-Ericsson embedded
>> >       Nomadik series.
>> >
>> > +config MFD_STM32_TIMER
>> > +   tristate "Support for STM32 multifunctions timer"
>> > +   select MFD_CORE
>> > +   select REGMAP
>> > +   depends on ARCH_STM32
>> > +   depends on OF
>> > +   help
>> > +     Select multifunction driver (pwm, IIO trigger) for stm32 timers
>> > +
>> >  menu "Multimedia Capabilities Port drivers"
>> >     depends on ARCH_SA1100
>> >
>> > @@ -1644,4 +1653,5 @@ config MFD_VEXPRESS_SYSREG
>> >       on the ARM Ltd. Versatile Express board.
>> >
>> >  endmenu
>> > +
>> >  endif
>> > diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
>> > index 9834e66..b348c3e 100644
>> > --- a/drivers/mfd/Makefile
>> > +++ b/drivers/mfd/Makefile
>> > @@ -211,3 +211,5 @@ obj-$(CONFIG_INTEL_SOC_PMIC)    +=3D intel-soc-pmi=
c.o
>> >  obj-$(CONFIG_MFD_MT6397)   +=3D mt6397-core.o
>> >
>> >  obj-$(CONFIG_MFD_ALTERA_A10SR)     +=3D altera-a10sr.o
>> > +
>> > +obj-$(CONFIG_MFD_STM32_TIMER)      +=3D stm32-mfd-timer.o
>> > diff --git a/drivers/mfd/stm32-mfd-timer.c b/drivers/mfd/stm32-mfd-tim=
er.c
>> > new file mode 100644
>> > index 0000000..67e7db3
>> > --- /dev/null
>> > +++ b/drivers/mfd/stm32-mfd-timer.c
>> > @@ -0,0 +1,236 @@
>> > +/*
>> > + * stm32-timer.c
>> > + *
>> > + * Copyright (C) STMicroelectronics 2016
>> > + * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroel=
ectronics.
>> > + * License terms:  GNU General Public License (GPL), version 2
>> > + */
>> > +
>> > +#include <linux/device.h>
>> > +#include <linux/init.h>
>> > +#include <linux/module.h>
>> > +#include <linux/of.h>
>> > +
>> > +#include <linux/mfd/stm32-mfd-timer.h>
>> > +
>> > +static const struct stm32_mfd_timer_cfg mfd_cells_cfg[] =3D {
>> > +   {
>> > +           .pwm_name =3D "pwm1",
>> > +           .pwm_compatible =3D "st,stm32-pwm1",
>> > +           .trigger_name =3D "iiotimer1",
>> > +           .trigger_compatible =3D "st,stm32-iio-timer1",
>> > +   },
>> > +   {
>> > +           .pwm_name =3D "pwm2",
>> > +           .pwm_compatible =3D "st,stm32-pwm2",
>> > +           .trigger_name =3D "iiotimer2",
>> > +           .trigger_compatible =3D "st,stm32-iio-timer2",
>> > +   },
>> > +   {
>> > +           .pwm_name =3D "pwm3",
>> > +           .pwm_compatible =3D "st,stm32-pwm3",
>> > +           .trigger_name =3D "iiotimer3",
>> > +           .trigger_compatible =3D "st,stm32-iio-timer3",
>> > +   },
>> > +   {
>> > +           .pwm_name =3D "pwm4",
>> > +           .pwm_compatible =3D "st,stm32-pwm4",
>> > +           .trigger_name =3D "iiotimer4",
>> > +           .trigger_compatible =3D "st,stm32-iio-timer4",
>> > +   },
>> > +   {
>> > +           .pwm_name =3D "pwm5",
>> > +           .pwm_compatible =3D "st,stm32-pwm5",
>> > +           .trigger_name =3D "iiotimer5",
>> > +           .trigger_compatible =3D "st,stm32-iio-timer5",
>> > +   },
>> > +   {
>> > +           .trigger_name =3D "iiotimer6",
>> > +           .trigger_compatible =3D "st,stm32-iio-timer6",
>> > +   },
>> > +   {
>> > +           .trigger_name =3D "iiotimer7",
>> > +           .trigger_compatible =3D "st,stm32-iio-timer7",
>> > +   },
>> > +   {
>> > +           .pwm_name =3D "pwm8",
>> > +           .pwm_compatible =3D "st,stm32-pwm8",
>> > +           .trigger_name =3D "iiotimer8",
>> > +           .trigger_compatible =3D "st,stm32-iio-timer8",
>> > +   },
>> > +   {
>> > +           .pwm_name =3D "pwm9",
>> > +           .pwm_compatible =3D "st,stm32-pwm9",
>> > +           .trigger_name =3D "iiotimer9",
>> > +           .trigger_compatible =3D "st,stm32-iio-timer9",
>> > +   },
>> > +   {
>> > +           .pwm_name =3D "pwm10",
>> > +           .pwm_compatible =3D "st,stm32-pwm10",
>> > +   },
>> > +   {
>> > +           .pwm_name =3D "pwm11",
>> > +           .pwm_compatible =3D "st,stm32-pwm11",
>> > +   },
>> > +   {
>> > +           .pwm_name =3D "pwm12",
>> > +           .pwm_compatible =3D "st,stm32-pwm12",
>> > +           .trigger_name =3D "iiotimer12",
>> > +           .trigger_compatible =3D "st,stm32-iio-timer12",
>> > +   },
>> > +   {
>> > +           .pwm_name =3D "pwm13",
>> > +           .pwm_compatible =3D "st,stm32-pwm13",
>> > +   },
>> > +   {
>> > +           .pwm_name =3D "pwm14",
>> > +           .pwm_compatible =3D "st,stm32-pwm14",
>> > +   },
>> > +};
>> > +
>> > +static const struct of_device_id stm32_timer_of_match[] =3D {
>> > +   {
>> > +           .compatible =3D "st,stm32-mfd-timer1",
>> > +           .data =3D &mfd_cells_cfg[0],
>> > +   },
>> > +   {
>> > +           .compatible =3D "st,stm32-mfd-timer2",
>> > +           .data =3D &mfd_cells_cfg[1],
>> > +   },
>> > +   {
>> > +           .compatible =3D "st,stm32-mfd-timer3",
>> > +           .data =3D &mfd_cells_cfg[2],
>> > +   },
>> > +   {
>> > +           .compatible =3D "st,stm32-mfd-timer4",
>> > +           .data =3D &mfd_cells_cfg[3],
>> > +   },
>> > +   {
>> > +           .compatible =3D "st,stm32-mfd-timer5",
>> > +           .data =3D &mfd_cells_cfg[4],
>> > +   },
>> > +   {
>> > +           .compatible =3D "st,stm32-mfd-timer6",
>> > +           .data =3D &mfd_cells_cfg[5],
>> > +   },
>> > +   {
>> > +           .compatible =3D "st,stm32-mfd-timer7",
>> > +           .data =3D &mfd_cells_cfg[6],
>> > +   },
>> > +   {
>> > +           .compatible =3D "st,stm32-mfd-timer8",
>> > +           .data =3D &mfd_cells_cfg[7],
>> > +   },
>> > +   {
>> > +           .compatible =3D "st,stm32-mfd-timer9",
>> > +           .data =3D &mfd_cells_cfg[8],
>> > +   },
>> > +   {
>> > +           .compatible =3D "st,stm32-mfd-timer10",
>> > +           .data =3D &mfd_cells_cfg[9],
>> > +   },
>> > +   {
>> > +           .compatible =3D "st,stm32-mfd-timer11",
>> > +           .data =3D &mfd_cells_cfg[10],
>> > +   },
>> > +   {
>> > +           .compatible =3D "st,stm32-mfd-timer12",
>> > +           .data =3D &mfd_cells_cfg[11],
>> > +   },
>> > +   {
>> > +           .compatible =3D "st,stm32-mfd-timer13",
>> > +           .data =3D &mfd_cells_cfg[12],
>> > +   },
>> > +   {
>> > +           .compatible =3D "st,stm32-mfd-timer14",
>> > +           .data =3D &mfd_cells_cfg[13],
>> > +   },
>> > +};
>> > +
>> > +static const struct regmap_config stm32_timer_regmap_cfg =3D {
>> > +   .reg_bits =3D 32,
>> > +   .val_bits =3D 32,
>> > +   .reg_stride =3D sizeof(u32),
>> > +   .max_register =3D 0x400,
>> > +   .fast_io =3D true,
>> > +};
>> > +
>> > +static int stm32_mfd_timer_probe(struct platform_device *pdev)
>> > +{
>> > +   struct device *dev =3D &pdev->dev;
>> > +   struct device_node *np =3D dev->of_node;
>> > +   struct stm32_mfd_timer_dev *mfd;
>> > +   struct resource *res;
>> > +   int ret, nb_cells =3D 0;
>> > +   struct mfd_cell *cell =3D NULL;
>> > +   void __iomem *mmio;
>> > +
>> > +   mfd =3D devm_kzalloc(dev, sizeof(*mfd), GFP_KERNEL);
>> > +   if (!mfd)
>> > +           return -ENOMEM;
>> > +
>> > +   res =3D platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> > +   if (!res)
>> > +           return -ENOMEM;
>> > +
>> > +   mmio =3D devm_ioremap_resource(dev, res);
>> > +   if (IS_ERR(mmio))
>> > +           return PTR_ERR(mmio);
>> > +
>> > +   mfd->regmap =3D devm_regmap_init_mmio_clk(dev, "mfd_timer_clk", mm=
io,
>> > +                                           &stm32_timer_regmap_cfg);
>> > +   if (IS_ERR(mfd->regmap))
>> > +           return PTR_ERR(mfd->regmap);
>> > +
>> > +   mfd->clk =3D devm_clk_get(dev, NULL);
>> > +   if (IS_ERR(mfd->clk))
>> > +           return PTR_ERR(mfd->clk);
>> > +
>> > +   mfd->irq =3D platform_get_irq(pdev, 0);
>> > +   if (mfd->irq < 0)
>> > +           return -EINVAL;
>> > +
>> > +   /* populate data structure depending on compatibility */
>> > +   if (!of_match_node(stm32_timer_of_match, np)->data)
>> > +           return -EINVAL;
>> > +
>> > +   mfd->cfg =3D
>> > +   (struct stm32_mfd_timer_cfg *)of_match_node(stm32_timer_of_match, =
np)->data;
>> > +
>> > +   if (mfd->cfg->pwm_name && mfd->cfg->pwm_compatible) {
>> > +           cell =3D &mfd->cells[nb_cells++];
>> > +           cell->name =3D mfd->cfg->pwm_name;
>> > +           cell->of_compatible =3D mfd->cfg->pwm_compatible;
>> > +           cell->platform_data =3D mfd;
>> > +           cell->pdata_size =3D sizeof(*mfd);
>> > +   }
>> > +
>> > +   if (mfd->cfg->trigger_name && mfd->cfg->trigger_compatible) {
>> > +           cell =3D &mfd->cells[nb_cells++];
>> > +           cell->name =3D mfd->cfg->trigger_name;
>> > +           cell->of_compatible =3D mfd->cfg->trigger_compatible;
>> > +           cell->platform_data =3D mfd;
>> > +           cell->pdata_size =3D sizeof(*mfd);
>> > +   }
>> > +
>> > +   ret =3D devm_mfd_add_devices(&pdev->dev, pdev->id, mfd->cells,
>> > +                              nb_cells, NULL, 0, NULL);
>> > +   if (ret)
>> > +           return ret;
>> > +
>> > +   platform_set_drvdata(pdev, mfd);
>> > +
>> > +   return 0;
>> > +}
>> > +
>> > +static struct platform_driver stm32_mfd_timer_driver =3D {
>> > +   .probe          =3D stm32_mfd_timer_probe,
>> > +   .driver =3D {
>> > +           .name   =3D "stm32-mfd-timer",
>> > +           .of_match_table =3D stm32_timer_of_match,
>> > +   },
>> > +};
>> > +module_platform_driver(stm32_mfd_timer_driver);
>> > +
>> > +MODULE_DESCRIPTION("STMicroelectronics STM32 Timer MFD");
>> > +MODULE_LICENSE("GPL");
>> > diff --git a/include/linux/mfd/stm32-mfd-timer.h b/include/linux/mfd/s=
tm32-mfd-timer.h
>> > new file mode 100644
>> > index 0000000..4a79c22
>> > --- /dev/null
>> > +++ b/include/linux/mfd/stm32-mfd-timer.h
>> > @@ -0,0 +1,78 @@
>> > +/*
>> > + * stm32-mfd-timer.h
>> > + *
>> > + * Copyright (C) STMicroelectronics 2016
>> > + * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroel=
ectronics.
>> > + * License terms:  GNU General Public License (GPL), version 2
>> > + */
>> > +
>> > +#ifndef _LINUX_MFD_STM32_TIMER_H_
>> > +#define _LINUX_MFD_STM32_TIMER_H_
>> > +
>> > +#include <linux/clk.h>
>> > +#include <linux/mfd/core.h>
>> > +#include <linux/regmap.h>
>> > +#include <linux/reset.h>
>> > +
>> > +#define TIM_CR1            0x00    /* Control Register 1      */
>> > +#define TIM_CR2            0x04    /* Control Register 2      */
>> > +#define TIM_SMCR   0x08    /* Slave mode control reg  */
>> > +#define TIM_DIER   0x0C    /* DMA/interrupt register  */
>> > +#define TIM_SR             0x10    /* Status register         */
>> > +#define TIM_EGR            0x14    /* Event Generation Reg    */
>> > +#define TIM_CCMR1  0x18    /* Capt/Comp 1 Mode Reg    */
>> > +#define TIM_CCMR2  0x1C    /* Capt/Comp 2 Mode Reg    */
>> > +#define TIM_CCER   0x20    /* Capt/Comp Enable Reg    */
>> > +#define TIM_PSC            0x28    /* Prescaler               */
>> > +#define TIM_ARR            0x2c    /* Auto-Reload Register    */
>> > +#define TIM_CCR1   0x34    /* Capt/Comp Register 1    */
>> > +#define TIM_CCR2   0x38    /* Capt/Comp Register 2    */
>> > +#define TIM_CCR3   0x3C    /* Capt/Comp Register 3    */
>> > +#define TIM_CCR4   0x40    /* Capt/Comp Register 4    */
>> > +#define TIM_BDTR   0x44    /* Break and Dead-Time Reg */
>> > +
>> > +#define TIM_CR1_CEN        BIT(0)  /* Counter Enable          */
>> > +#define TIM_CR1_ARPE       BIT(7)  /* Auto-reload Preload Ena */
>> > +#define TIM_CR2_MMS        (BIT(4) | BIT(5) | BIT(6)) /* Master mode =
selection */
>> > +#define TIM_SMCR_SMS       (BIT(0) | BIT(1) | BIT(2)) /* Slave mode s=
election */
>> > +#define TIM_SMCR_TS        (BIT(4) | BIT(5) | BIT(6)) /* Trigger sele=
ction */
>> > +#define TIM_DIER_UIE       BIT(0)  /* Update interrupt        */
>> > +#define TIM_SR_UIF BIT(0)  /* Update interrupt flag   */
>> > +#define TIM_EGR_UG BIT(0)  /* Update Generation       */
>> > +#define TIM_CCMR_PE        BIT(3)  /* Channel Preload Enable  */
>> > +#define TIM_CCMR_M1        (BIT(6) | BIT(5))  /* Channel PWM Mode 1 *=
/
>> > +#define TIM_CCER_CC1E      BIT(0)  /* Capt/Comp 1  out Ena    */
>> > +#define TIM_CCER_CC1P      BIT(1)  /* Capt/Comp 1  Polarity   */
>> > +#define TIM_CCER_CC1NE     BIT(2)  /* Capt/Comp 1N out Ena    */
>> > +#define TIM_CCER_CC1NP     BIT(3)  /* Capt/Comp 1N Polarity   */
>> > +#define TIM_CCER_CCXE      (BIT(0) | BIT(4) | BIT(8) | BIT(12))
>> > +#define TIM_BDTR_BKE       BIT(12) /* Break input enable      */
>> > +#define TIM_BDTR_BKP       BIT(13) /* Break input polarity    */
>> > +#define TIM_BDTR_AOE       BIT(14) /* Automatic Output Enable */
>> > +#define TIM_BDTR_MOE       BIT(15) /* Main Output Enable      */
>> > +
>> > +#define STM32_TIMER_CELLS  2
>> > +#define MAX_TIM_PSC                0xFFFF
>> > +
>> > +struct stm32_mfd_timer_cfg {
>> > +   const char *pwm_name;
>> > +   const char *pwm_compatible;
>> > +   const char *trigger_name;
>> > +   const char *trigger_compatible;
>> > +};
>> > +
>> > +struct stm32_mfd_timer_dev {
>> > +   /* Device data */
>> > +   struct device *dev;
>> > +   struct clk *clk;
>> > +   int irq;
>> > +
>> > +   /* Registers mapping */
>> > +   struct regmap *regmap;
>> > +
>> > +   /* Private data */
>> > +   struct mfd_cell cells[STM32_TIMER_CELLS];
>> > +   struct stm32_mfd_timer_cfg *cfg;
>> > +};
>> > +
>> > +#endif
>>
>
> --
> Lee Jones
> Linaro STMicroelectronics Landing Team Lead
> Linaro.org =E2=94=82 Open source software for ARM SoCs
> Follow Linaro: Facebook | Twitter | Blog



--=20
Benjamin Gaignard

Graphic Study Group

Linaro.org =E2=94=82 Open source software for ARM SoCs

Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 64+ messages in thread

* [PATCH 2/7] add MFD for stm32 timer IP
@ 2016-11-22 16:40         ` Benjamin Gaignard
  0 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-22 16:40 UTC (permalink / raw)
  To: linux-arm-kernel

Your comments are welcome on all of them ;-)

2016-11-22 17:41 GMT+01:00 Lee Jones <lee.jones@linaro.org>:
> On Tue, 22 Nov 2016, Lee Jones wrote:
>
>> On Tue, 22 Nov 2016, Benjamin Gaignard wrote:
>>
>> > This hardware block could at used at same time for PWM generation
>> > and IIO timer for other IPs like DAC, ADC or other timers.
>> > PWM and IIO timer configuration are mixed in the same registers
>> > so we need a MFD to be able to share those registers.
>> >
>> > Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
>> > ---
>> >  drivers/mfd/Kconfig                 |  10 ++
>> >  drivers/mfd/Makefile                |   2 +
>> >  drivers/mfd/stm32-mfd-timer.c       | 236 ++++++++++++++++++++++++++++++++++++
>> >  include/linux/mfd/stm32-mfd-timer.h |  78 ++++++++++++
>> >  4 files changed, 326 insertions(+)
>> >  create mode 100644 drivers/mfd/stm32-mfd-timer.c
>> >  create mode 100644 include/linux/mfd/stm32-mfd-timer.h
>>
>> This driver is going to need a re-write.
>>
>> However, it's difficult to provide suggestions, since I've been left
>> off of the Cc: list for all the other patches.
>>
>> Please re-send the set with all of the Maintainers Cc'ed on all of
>> the patches.
>
> Scrap that -- they all just came trickling through!
>
>> > diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
>> > index c6df644..63aee36 100644
>> > --- a/drivers/mfd/Kconfig
>> > +++ b/drivers/mfd/Kconfig
>> > @@ -1607,6 +1607,15 @@ config MFD_STW481X
>> >       in various ST Microelectronics and ST-Ericsson embedded
>> >       Nomadik series.
>> >
>> > +config MFD_STM32_TIMER
>> > +   tristate "Support for STM32 multifunctions timer"
>> > +   select MFD_CORE
>> > +   select REGMAP
>> > +   depends on ARCH_STM32
>> > +   depends on OF
>> > +   help
>> > +     Select multifunction driver (pwm, IIO trigger) for stm32 timers
>> > +
>> >  menu "Multimedia Capabilities Port drivers"
>> >     depends on ARCH_SA1100
>> >
>> > @@ -1644,4 +1653,5 @@ config MFD_VEXPRESS_SYSREG
>> >       on the ARM Ltd. Versatile Express board.
>> >
>> >  endmenu
>> > +
>> >  endif
>> > diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
>> > index 9834e66..b348c3e 100644
>> > --- a/drivers/mfd/Makefile
>> > +++ b/drivers/mfd/Makefile
>> > @@ -211,3 +211,5 @@ obj-$(CONFIG_INTEL_SOC_PMIC)    += intel-soc-pmic.o
>> >  obj-$(CONFIG_MFD_MT6397)   += mt6397-core.o
>> >
>> >  obj-$(CONFIG_MFD_ALTERA_A10SR)     += altera-a10sr.o
>> > +
>> > +obj-$(CONFIG_MFD_STM32_TIMER)      += stm32-mfd-timer.o
>> > diff --git a/drivers/mfd/stm32-mfd-timer.c b/drivers/mfd/stm32-mfd-timer.c
>> > new file mode 100644
>> > index 0000000..67e7db3
>> > --- /dev/null
>> > +++ b/drivers/mfd/stm32-mfd-timer.c
>> > @@ -0,0 +1,236 @@
>> > +/*
>> > + * stm32-timer.c
>> > + *
>> > + * Copyright (C) STMicroelectronics 2016
>> > + * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
>> > + * License terms:  GNU General Public License (GPL), version 2
>> > + */
>> > +
>> > +#include <linux/device.h>
>> > +#include <linux/init.h>
>> > +#include <linux/module.h>
>> > +#include <linux/of.h>
>> > +
>> > +#include <linux/mfd/stm32-mfd-timer.h>
>> > +
>> > +static const struct stm32_mfd_timer_cfg mfd_cells_cfg[] = {
>> > +   {
>> > +           .pwm_name = "pwm1",
>> > +           .pwm_compatible = "st,stm32-pwm1",
>> > +           .trigger_name = "iiotimer1",
>> > +           .trigger_compatible = "st,stm32-iio-timer1",
>> > +   },
>> > +   {
>> > +           .pwm_name = "pwm2",
>> > +           .pwm_compatible = "st,stm32-pwm2",
>> > +           .trigger_name = "iiotimer2",
>> > +           .trigger_compatible = "st,stm32-iio-timer2",
>> > +   },
>> > +   {
>> > +           .pwm_name = "pwm3",
>> > +           .pwm_compatible = "st,stm32-pwm3",
>> > +           .trigger_name = "iiotimer3",
>> > +           .trigger_compatible = "st,stm32-iio-timer3",
>> > +   },
>> > +   {
>> > +           .pwm_name = "pwm4",
>> > +           .pwm_compatible = "st,stm32-pwm4",
>> > +           .trigger_name = "iiotimer4",
>> > +           .trigger_compatible = "st,stm32-iio-timer4",
>> > +   },
>> > +   {
>> > +           .pwm_name = "pwm5",
>> > +           .pwm_compatible = "st,stm32-pwm5",
>> > +           .trigger_name = "iiotimer5",
>> > +           .trigger_compatible = "st,stm32-iio-timer5",
>> > +   },
>> > +   {
>> > +           .trigger_name = "iiotimer6",
>> > +           .trigger_compatible = "st,stm32-iio-timer6",
>> > +   },
>> > +   {
>> > +           .trigger_name = "iiotimer7",
>> > +           .trigger_compatible = "st,stm32-iio-timer7",
>> > +   },
>> > +   {
>> > +           .pwm_name = "pwm8",
>> > +           .pwm_compatible = "st,stm32-pwm8",
>> > +           .trigger_name = "iiotimer8",
>> > +           .trigger_compatible = "st,stm32-iio-timer8",
>> > +   },
>> > +   {
>> > +           .pwm_name = "pwm9",
>> > +           .pwm_compatible = "st,stm32-pwm9",
>> > +           .trigger_name = "iiotimer9",
>> > +           .trigger_compatible = "st,stm32-iio-timer9",
>> > +   },
>> > +   {
>> > +           .pwm_name = "pwm10",
>> > +           .pwm_compatible = "st,stm32-pwm10",
>> > +   },
>> > +   {
>> > +           .pwm_name = "pwm11",
>> > +           .pwm_compatible = "st,stm32-pwm11",
>> > +   },
>> > +   {
>> > +           .pwm_name = "pwm12",
>> > +           .pwm_compatible = "st,stm32-pwm12",
>> > +           .trigger_name = "iiotimer12",
>> > +           .trigger_compatible = "st,stm32-iio-timer12",
>> > +   },
>> > +   {
>> > +           .pwm_name = "pwm13",
>> > +           .pwm_compatible = "st,stm32-pwm13",
>> > +   },
>> > +   {
>> > +           .pwm_name = "pwm14",
>> > +           .pwm_compatible = "st,stm32-pwm14",
>> > +   },
>> > +};
>> > +
>> > +static const struct of_device_id stm32_timer_of_match[] = {
>> > +   {
>> > +           .compatible = "st,stm32-mfd-timer1",
>> > +           .data = &mfd_cells_cfg[0],
>> > +   },
>> > +   {
>> > +           .compatible = "st,stm32-mfd-timer2",
>> > +           .data = &mfd_cells_cfg[1],
>> > +   },
>> > +   {
>> > +           .compatible = "st,stm32-mfd-timer3",
>> > +           .data = &mfd_cells_cfg[2],
>> > +   },
>> > +   {
>> > +           .compatible = "st,stm32-mfd-timer4",
>> > +           .data = &mfd_cells_cfg[3],
>> > +   },
>> > +   {
>> > +           .compatible = "st,stm32-mfd-timer5",
>> > +           .data = &mfd_cells_cfg[4],
>> > +   },
>> > +   {
>> > +           .compatible = "st,stm32-mfd-timer6",
>> > +           .data = &mfd_cells_cfg[5],
>> > +   },
>> > +   {
>> > +           .compatible = "st,stm32-mfd-timer7",
>> > +           .data = &mfd_cells_cfg[6],
>> > +   },
>> > +   {
>> > +           .compatible = "st,stm32-mfd-timer8",
>> > +           .data = &mfd_cells_cfg[7],
>> > +   },
>> > +   {
>> > +           .compatible = "st,stm32-mfd-timer9",
>> > +           .data = &mfd_cells_cfg[8],
>> > +   },
>> > +   {
>> > +           .compatible = "st,stm32-mfd-timer10",
>> > +           .data = &mfd_cells_cfg[9],
>> > +   },
>> > +   {
>> > +           .compatible = "st,stm32-mfd-timer11",
>> > +           .data = &mfd_cells_cfg[10],
>> > +   },
>> > +   {
>> > +           .compatible = "st,stm32-mfd-timer12",
>> > +           .data = &mfd_cells_cfg[11],
>> > +   },
>> > +   {
>> > +           .compatible = "st,stm32-mfd-timer13",
>> > +           .data = &mfd_cells_cfg[12],
>> > +   },
>> > +   {
>> > +           .compatible = "st,stm32-mfd-timer14",
>> > +           .data = &mfd_cells_cfg[13],
>> > +   },
>> > +};
>> > +
>> > +static const struct regmap_config stm32_timer_regmap_cfg = {
>> > +   .reg_bits = 32,
>> > +   .val_bits = 32,
>> > +   .reg_stride = sizeof(u32),
>> > +   .max_register = 0x400,
>> > +   .fast_io = true,
>> > +};
>> > +
>> > +static int stm32_mfd_timer_probe(struct platform_device *pdev)
>> > +{
>> > +   struct device *dev = &pdev->dev;
>> > +   struct device_node *np = dev->of_node;
>> > +   struct stm32_mfd_timer_dev *mfd;
>> > +   struct resource *res;
>> > +   int ret, nb_cells = 0;
>> > +   struct mfd_cell *cell = NULL;
>> > +   void __iomem *mmio;
>> > +
>> > +   mfd = devm_kzalloc(dev, sizeof(*mfd), GFP_KERNEL);
>> > +   if (!mfd)
>> > +           return -ENOMEM;
>> > +
>> > +   res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> > +   if (!res)
>> > +           return -ENOMEM;
>> > +
>> > +   mmio = devm_ioremap_resource(dev, res);
>> > +   if (IS_ERR(mmio))
>> > +           return PTR_ERR(mmio);
>> > +
>> > +   mfd->regmap = devm_regmap_init_mmio_clk(dev, "mfd_timer_clk", mmio,
>> > +                                           &stm32_timer_regmap_cfg);
>> > +   if (IS_ERR(mfd->regmap))
>> > +           return PTR_ERR(mfd->regmap);
>> > +
>> > +   mfd->clk = devm_clk_get(dev, NULL);
>> > +   if (IS_ERR(mfd->clk))
>> > +           return PTR_ERR(mfd->clk);
>> > +
>> > +   mfd->irq = platform_get_irq(pdev, 0);
>> > +   if (mfd->irq < 0)
>> > +           return -EINVAL;
>> > +
>> > +   /* populate data structure depending on compatibility */
>> > +   if (!of_match_node(stm32_timer_of_match, np)->data)
>> > +           return -EINVAL;
>> > +
>> > +   mfd->cfg =
>> > +   (struct stm32_mfd_timer_cfg *)of_match_node(stm32_timer_of_match, np)->data;
>> > +
>> > +   if (mfd->cfg->pwm_name && mfd->cfg->pwm_compatible) {
>> > +           cell = &mfd->cells[nb_cells++];
>> > +           cell->name = mfd->cfg->pwm_name;
>> > +           cell->of_compatible = mfd->cfg->pwm_compatible;
>> > +           cell->platform_data = mfd;
>> > +           cell->pdata_size = sizeof(*mfd);
>> > +   }
>> > +
>> > +   if (mfd->cfg->trigger_name && mfd->cfg->trigger_compatible) {
>> > +           cell = &mfd->cells[nb_cells++];
>> > +           cell->name = mfd->cfg->trigger_name;
>> > +           cell->of_compatible = mfd->cfg->trigger_compatible;
>> > +           cell->platform_data = mfd;
>> > +           cell->pdata_size = sizeof(*mfd);
>> > +   }
>> > +
>> > +   ret = devm_mfd_add_devices(&pdev->dev, pdev->id, mfd->cells,
>> > +                              nb_cells, NULL, 0, NULL);
>> > +   if (ret)
>> > +           return ret;
>> > +
>> > +   platform_set_drvdata(pdev, mfd);
>> > +
>> > +   return 0;
>> > +}
>> > +
>> > +static struct platform_driver stm32_mfd_timer_driver = {
>> > +   .probe          = stm32_mfd_timer_probe,
>> > +   .driver = {
>> > +           .name   = "stm32-mfd-timer",
>> > +           .of_match_table = stm32_timer_of_match,
>> > +   },
>> > +};
>> > +module_platform_driver(stm32_mfd_timer_driver);
>> > +
>> > +MODULE_DESCRIPTION("STMicroelectronics STM32 Timer MFD");
>> > +MODULE_LICENSE("GPL");
>> > diff --git a/include/linux/mfd/stm32-mfd-timer.h b/include/linux/mfd/stm32-mfd-timer.h
>> > new file mode 100644
>> > index 0000000..4a79c22
>> > --- /dev/null
>> > +++ b/include/linux/mfd/stm32-mfd-timer.h
>> > @@ -0,0 +1,78 @@
>> > +/*
>> > + * stm32-mfd-timer.h
>> > + *
>> > + * Copyright (C) STMicroelectronics 2016
>> > + * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
>> > + * License terms:  GNU General Public License (GPL), version 2
>> > + */
>> > +
>> > +#ifndef _LINUX_MFD_STM32_TIMER_H_
>> > +#define _LINUX_MFD_STM32_TIMER_H_
>> > +
>> > +#include <linux/clk.h>
>> > +#include <linux/mfd/core.h>
>> > +#include <linux/regmap.h>
>> > +#include <linux/reset.h>
>> > +
>> > +#define TIM_CR1            0x00    /* Control Register 1      */
>> > +#define TIM_CR2            0x04    /* Control Register 2      */
>> > +#define TIM_SMCR   0x08    /* Slave mode control reg  */
>> > +#define TIM_DIER   0x0C    /* DMA/interrupt register  */
>> > +#define TIM_SR             0x10    /* Status register         */
>> > +#define TIM_EGR            0x14    /* Event Generation Reg    */
>> > +#define TIM_CCMR1  0x18    /* Capt/Comp 1 Mode Reg    */
>> > +#define TIM_CCMR2  0x1C    /* Capt/Comp 2 Mode Reg    */
>> > +#define TIM_CCER   0x20    /* Capt/Comp Enable Reg    */
>> > +#define TIM_PSC            0x28    /* Prescaler               */
>> > +#define TIM_ARR            0x2c    /* Auto-Reload Register    */
>> > +#define TIM_CCR1   0x34    /* Capt/Comp Register 1    */
>> > +#define TIM_CCR2   0x38    /* Capt/Comp Register 2    */
>> > +#define TIM_CCR3   0x3C    /* Capt/Comp Register 3    */
>> > +#define TIM_CCR4   0x40    /* Capt/Comp Register 4    */
>> > +#define TIM_BDTR   0x44    /* Break and Dead-Time Reg */
>> > +
>> > +#define TIM_CR1_CEN        BIT(0)  /* Counter Enable          */
>> > +#define TIM_CR1_ARPE       BIT(7)  /* Auto-reload Preload Ena */
>> > +#define TIM_CR2_MMS        (BIT(4) | BIT(5) | BIT(6)) /* Master mode selection */
>> > +#define TIM_SMCR_SMS       (BIT(0) | BIT(1) | BIT(2)) /* Slave mode selection */
>> > +#define TIM_SMCR_TS        (BIT(4) | BIT(5) | BIT(6)) /* Trigger selection */
>> > +#define TIM_DIER_UIE       BIT(0)  /* Update interrupt        */
>> > +#define TIM_SR_UIF BIT(0)  /* Update interrupt flag   */
>> > +#define TIM_EGR_UG BIT(0)  /* Update Generation       */
>> > +#define TIM_CCMR_PE        BIT(3)  /* Channel Preload Enable  */
>> > +#define TIM_CCMR_M1        (BIT(6) | BIT(5))  /* Channel PWM Mode 1 */
>> > +#define TIM_CCER_CC1E      BIT(0)  /* Capt/Comp 1  out Ena    */
>> > +#define TIM_CCER_CC1P      BIT(1)  /* Capt/Comp 1  Polarity   */
>> > +#define TIM_CCER_CC1NE     BIT(2)  /* Capt/Comp 1N out Ena    */
>> > +#define TIM_CCER_CC1NP     BIT(3)  /* Capt/Comp 1N Polarity   */
>> > +#define TIM_CCER_CCXE      (BIT(0) | BIT(4) | BIT(8) | BIT(12))
>> > +#define TIM_BDTR_BKE       BIT(12) /* Break input enable      */
>> > +#define TIM_BDTR_BKP       BIT(13) /* Break input polarity    */
>> > +#define TIM_BDTR_AOE       BIT(14) /* Automatic Output Enable */
>> > +#define TIM_BDTR_MOE       BIT(15) /* Main Output Enable      */
>> > +
>> > +#define STM32_TIMER_CELLS  2
>> > +#define MAX_TIM_PSC                0xFFFF
>> > +
>> > +struct stm32_mfd_timer_cfg {
>> > +   const char *pwm_name;
>> > +   const char *pwm_compatible;
>> > +   const char *trigger_name;
>> > +   const char *trigger_compatible;
>> > +};
>> > +
>> > +struct stm32_mfd_timer_dev {
>> > +   /* Device data */
>> > +   struct device *dev;
>> > +   struct clk *clk;
>> > +   int irq;
>> > +
>> > +   /* Registers mapping */
>> > +   struct regmap *regmap;
>> > +
>> > +   /* Private data */
>> > +   struct mfd_cell cells[STM32_TIMER_CELLS];
>> > +   struct stm32_mfd_timer_cfg *cfg;
>> > +};
>> > +
>> > +#endif
>>
>
> --
> Lee Jones
> Linaro STMicroelectronics Landing Team Lead
> Linaro.org ? Open source software for ARM SoCs
> Follow Linaro: Facebook | Twitter | Blog



-- 
Benjamin Gaignard

Graphic Study Group

Linaro.org ? Open source software for ARM SoCs

Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 2/7] add MFD for stm32 timer IP
@ 2016-11-22 16:41       ` Lee Jones
  0 siblings, 0 replies; 64+ messages in thread
From: Lee Jones @ 2016-11-22 16:41 UTC (permalink / raw)
  To: Benjamin Gaignard
  Cc: robh+dt, mark.rutland, alexandre.torgue, devicetree,
	linux-kernel, thierry.reding, linux-pwm, jic23, knaack.h, lars,
	pmeerw, linux-iio, linux-arm-kernel, fabrice.gasnier,
	gerald.baeza, arnaud.pouliquen, linus.walleij, linaro-kernel,
	Benjamin Gaignard

On Tue, 22 Nov 2016, Lee Jones wrote:

> On Tue, 22 Nov 2016, Benjamin Gaignard wrote:
> 
> > This hardware block could at used at same time for PWM generation
> > and IIO timer for other IPs like DAC, ADC or other timers.
> > PWM and IIO timer configuration are mixed in the same registers
> > so we need a MFD to be able to share those registers.
> > 
> > Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
> > ---
> >  drivers/mfd/Kconfig                 |  10 ++
> >  drivers/mfd/Makefile                |   2 +
> >  drivers/mfd/stm32-mfd-timer.c       | 236 ++++++++++++++++++++++++++++++++++++
> >  include/linux/mfd/stm32-mfd-timer.h |  78 ++++++++++++
> >  4 files changed, 326 insertions(+)
> >  create mode 100644 drivers/mfd/stm32-mfd-timer.c
> >  create mode 100644 include/linux/mfd/stm32-mfd-timer.h
> 
> This driver is going to need a re-write.
> 
> However, it's difficult to provide suggestions, since I've been left
> off of the Cc: list for all the other patches.
> 
> Please re-send the set with all of the Maintainers Cc'ed on all of
> the patches.

Scrap that -- they all just came trickling through!

> > diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> > index c6df644..63aee36 100644
> > --- a/drivers/mfd/Kconfig
> > +++ b/drivers/mfd/Kconfig
> > @@ -1607,6 +1607,15 @@ config MFD_STW481X
> >  	  in various ST Microelectronics and ST-Ericsson embedded
> >  	  Nomadik series.
> >  
> > +config MFD_STM32_TIMER
> > +	tristate "Support for STM32 multifunctions timer"
> > +	select MFD_CORE
> > +	select REGMAP
> > +	depends on ARCH_STM32
> > +	depends on OF
> > +	help
> > +	  Select multifunction driver (pwm, IIO trigger) for stm32 timers
> > +
> >  menu "Multimedia Capabilities Port drivers"
> >  	depends on ARCH_SA1100
> >  
> > @@ -1644,4 +1653,5 @@ config MFD_VEXPRESS_SYSREG
> >  	  on the ARM Ltd. Versatile Express board.
> >  
> >  endmenu
> > +
> >  endif
> > diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> > index 9834e66..b348c3e 100644
> > --- a/drivers/mfd/Makefile
> > +++ b/drivers/mfd/Makefile
> > @@ -211,3 +211,5 @@ obj-$(CONFIG_INTEL_SOC_PMIC)	+= intel-soc-pmic.o
> >  obj-$(CONFIG_MFD_MT6397)	+= mt6397-core.o
> >  
> >  obj-$(CONFIG_MFD_ALTERA_A10SR)	+= altera-a10sr.o
> > +
> > +obj-$(CONFIG_MFD_STM32_TIMER) 	+= stm32-mfd-timer.o
> > diff --git a/drivers/mfd/stm32-mfd-timer.c b/drivers/mfd/stm32-mfd-timer.c
> > new file mode 100644
> > index 0000000..67e7db3
> > --- /dev/null
> > +++ b/drivers/mfd/stm32-mfd-timer.c
> > @@ -0,0 +1,236 @@
> > +/*
> > + * stm32-timer.c
> > + *
> > + * Copyright (C) STMicroelectronics 2016
> > + * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
> > + * License terms:  GNU General Public License (GPL), version 2
> > + */
> > +
> > +#include <linux/device.h>
> > +#include <linux/init.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +
> > +#include <linux/mfd/stm32-mfd-timer.h>
> > +
> > +static const struct stm32_mfd_timer_cfg mfd_cells_cfg[] = {
> > +	{
> > +		.pwm_name = "pwm1",
> > +		.pwm_compatible = "st,stm32-pwm1",
> > +		.trigger_name = "iiotimer1",
> > +		.trigger_compatible = "st,stm32-iio-timer1",
> > +	},
> > +	{
> > +		.pwm_name = "pwm2",
> > +		.pwm_compatible = "st,stm32-pwm2",
> > +		.trigger_name = "iiotimer2",
> > +		.trigger_compatible = "st,stm32-iio-timer2",
> > +	},
> > +	{
> > +		.pwm_name = "pwm3",
> > +		.pwm_compatible = "st,stm32-pwm3",
> > +		.trigger_name = "iiotimer3",
> > +		.trigger_compatible = "st,stm32-iio-timer3",
> > +	},
> > +	{
> > +		.pwm_name = "pwm4",
> > +		.pwm_compatible = "st,stm32-pwm4",
> > +		.trigger_name = "iiotimer4",
> > +		.trigger_compatible = "st,stm32-iio-timer4",
> > +	},
> > +	{
> > +		.pwm_name = "pwm5",
> > +		.pwm_compatible = "st,stm32-pwm5",
> > +		.trigger_name = "iiotimer5",
> > +		.trigger_compatible = "st,stm32-iio-timer5",
> > +	},
> > +	{
> > +		.trigger_name = "iiotimer6",
> > +		.trigger_compatible = "st,stm32-iio-timer6",
> > +	},
> > +	{
> > +		.trigger_name = "iiotimer7",
> > +		.trigger_compatible = "st,stm32-iio-timer7",
> > +	},
> > +	{
> > +		.pwm_name = "pwm8",
> > +		.pwm_compatible = "st,stm32-pwm8",
> > +		.trigger_name = "iiotimer8",
> > +		.trigger_compatible = "st,stm32-iio-timer8",
> > +	},
> > +	{
> > +		.pwm_name = "pwm9",
> > +		.pwm_compatible = "st,stm32-pwm9",
> > +		.trigger_name = "iiotimer9",
> > +		.trigger_compatible = "st,stm32-iio-timer9",
> > +	},
> > +	{
> > +		.pwm_name = "pwm10",
> > +		.pwm_compatible = "st,stm32-pwm10",
> > +	},
> > +	{
> > +		.pwm_name = "pwm11",
> > +		.pwm_compatible = "st,stm32-pwm11",
> > +	},
> > +	{
> > +		.pwm_name = "pwm12",
> > +		.pwm_compatible = "st,stm32-pwm12",
> > +		.trigger_name = "iiotimer12",
> > +		.trigger_compatible = "st,stm32-iio-timer12",
> > +	},
> > +	{
> > +		.pwm_name = "pwm13",
> > +		.pwm_compatible = "st,stm32-pwm13",
> > +	},
> > +	{
> > +		.pwm_name = "pwm14",
> > +		.pwm_compatible = "st,stm32-pwm14",
> > +	},
> > +};
> > +
> > +static const struct of_device_id stm32_timer_of_match[] = {
> > +	{
> > +		.compatible = "st,stm32-mfd-timer1",
> > +		.data = &mfd_cells_cfg[0],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer2",
> > +		.data = &mfd_cells_cfg[1],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer3",
> > +		.data = &mfd_cells_cfg[2],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer4",
> > +		.data = &mfd_cells_cfg[3],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer5",
> > +		.data = &mfd_cells_cfg[4],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer6",
> > +		.data = &mfd_cells_cfg[5],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer7",
> > +		.data = &mfd_cells_cfg[6],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer8",
> > +		.data = &mfd_cells_cfg[7],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer9",
> > +		.data = &mfd_cells_cfg[8],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer10",
> > +		.data = &mfd_cells_cfg[9],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer11",
> > +		.data = &mfd_cells_cfg[10],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer12",
> > +		.data = &mfd_cells_cfg[11],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer13",
> > +		.data = &mfd_cells_cfg[12],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer14",
> > +		.data = &mfd_cells_cfg[13],
> > +	},
> > +};
> > +
> > +static const struct regmap_config stm32_timer_regmap_cfg = {
> > +	.reg_bits = 32,
> > +	.val_bits = 32,
> > +	.reg_stride = sizeof(u32),
> > +	.max_register = 0x400,
> > +	.fast_io = true,
> > +};
> > +
> > +static int stm32_mfd_timer_probe(struct platform_device *pdev)
> > +{
> > +	struct device *dev = &pdev->dev;
> > +	struct device_node *np = dev->of_node;
> > +	struct stm32_mfd_timer_dev *mfd;
> > +	struct resource *res;
> > +	int ret, nb_cells = 0;
> > +	struct mfd_cell *cell = NULL;
> > +	void __iomem *mmio;
> > +
> > +	mfd = devm_kzalloc(dev, sizeof(*mfd), GFP_KERNEL);
> > +	if (!mfd)
> > +		return -ENOMEM;
> > +
> > +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > +	if (!res)
> > +		return -ENOMEM;
> > +
> > +	mmio = devm_ioremap_resource(dev, res);
> > +	if (IS_ERR(mmio))
> > +		return PTR_ERR(mmio);
> > +
> > +	mfd->regmap = devm_regmap_init_mmio_clk(dev, "mfd_timer_clk", mmio,
> > +						&stm32_timer_regmap_cfg);
> > +	if (IS_ERR(mfd->regmap))
> > +		return PTR_ERR(mfd->regmap);
> > +
> > +	mfd->clk = devm_clk_get(dev, NULL);
> > +	if (IS_ERR(mfd->clk))
> > +		return PTR_ERR(mfd->clk);
> > +
> > +	mfd->irq = platform_get_irq(pdev, 0);
> > +	if (mfd->irq < 0)
> > +		return -EINVAL;
> > +
> > +	/* populate data structure depending on compatibility */
> > +	if (!of_match_node(stm32_timer_of_match, np)->data)
> > +		return -EINVAL;
> > +
> > +	mfd->cfg =
> > +	(struct stm32_mfd_timer_cfg *)of_match_node(stm32_timer_of_match, np)->data;
> > +
> > +	if (mfd->cfg->pwm_name && mfd->cfg->pwm_compatible) {
> > +		cell = &mfd->cells[nb_cells++];
> > +		cell->name = mfd->cfg->pwm_name;
> > +		cell->of_compatible = mfd->cfg->pwm_compatible;
> > +		cell->platform_data = mfd;
> > +		cell->pdata_size = sizeof(*mfd);
> > +	}
> > +
> > +	if (mfd->cfg->trigger_name && mfd->cfg->trigger_compatible) {
> > +		cell = &mfd->cells[nb_cells++];
> > +		cell->name = mfd->cfg->trigger_name;
> > +		cell->of_compatible = mfd->cfg->trigger_compatible;
> > +		cell->platform_data = mfd;
> > +		cell->pdata_size = sizeof(*mfd);
> > +	}
> > +
> > +	ret = devm_mfd_add_devices(&pdev->dev, pdev->id, mfd->cells,
> > +				   nb_cells, NULL, 0, NULL);
> > +	if (ret)
> > +		return ret;
> > +
> > +	platform_set_drvdata(pdev, mfd);
> > +
> > +	return 0;
> > +}
> > +
> > +static struct platform_driver stm32_mfd_timer_driver = {
> > +	.probe		= stm32_mfd_timer_probe,
> > +	.driver	= {
> > +		.name	= "stm32-mfd-timer",
> > +		.of_match_table = stm32_timer_of_match,
> > +	},
> > +};
> > +module_platform_driver(stm32_mfd_timer_driver);
> > +
> > +MODULE_DESCRIPTION("STMicroelectronics STM32 Timer MFD");
> > +MODULE_LICENSE("GPL");
> > diff --git a/include/linux/mfd/stm32-mfd-timer.h b/include/linux/mfd/stm32-mfd-timer.h
> > new file mode 100644
> > index 0000000..4a79c22
> > --- /dev/null
> > +++ b/include/linux/mfd/stm32-mfd-timer.h
> > @@ -0,0 +1,78 @@
> > +/*
> > + * stm32-mfd-timer.h
> > + *
> > + * Copyright (C) STMicroelectronics 2016
> > + * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
> > + * License terms:  GNU General Public License (GPL), version 2
> > + */
> > +
> > +#ifndef _LINUX_MFD_STM32_TIMER_H_
> > +#define _LINUX_MFD_STM32_TIMER_H_
> > +
> > +#include <linux/clk.h>
> > +#include <linux/mfd/core.h>
> > +#include <linux/regmap.h>
> > +#include <linux/reset.h>
> > +
> > +#define TIM_CR1		0x00	/* Control Register 1      */
> > +#define TIM_CR2		0x04	/* Control Register 2      */
> > +#define TIM_SMCR	0x08	/* Slave mode control reg  */
> > +#define TIM_DIER	0x0C	/* DMA/interrupt register  */
> > +#define TIM_SR		0x10	/* Status register	   */
> > +#define TIM_EGR		0x14	/* Event Generation Reg    */
> > +#define TIM_CCMR1	0x18	/* Capt/Comp 1 Mode Reg    */
> > +#define TIM_CCMR2	0x1C	/* Capt/Comp 2 Mode Reg    */
> > +#define TIM_CCER	0x20	/* Capt/Comp Enable Reg    */
> > +#define TIM_PSC		0x28	/* Prescaler               */
> > +#define TIM_ARR		0x2c	/* Auto-Reload Register    */
> > +#define TIM_CCR1	0x34	/* Capt/Comp Register 1    */
> > +#define TIM_CCR2	0x38	/* Capt/Comp Register 2    */
> > +#define TIM_CCR3	0x3C	/* Capt/Comp Register 3    */
> > +#define TIM_CCR4	0x40	/* Capt/Comp Register 4    */
> > +#define TIM_BDTR	0x44	/* Break and Dead-Time Reg */
> > +
> > +#define TIM_CR1_CEN	BIT(0)	/* Counter Enable	   */
> > +#define TIM_CR1_ARPE	BIT(7)	/* Auto-reload Preload Ena */
> > +#define TIM_CR2_MMS	(BIT(4) | BIT(5) | BIT(6)) /* Master mode selection */
> > +#define TIM_SMCR_SMS	(BIT(0) | BIT(1) | BIT(2)) /* Slave mode selection */
> > +#define TIM_SMCR_TS	(BIT(4) | BIT(5) | BIT(6)) /* Trigger selection */
> > +#define TIM_DIER_UIE	BIT(0)	/* Update interrupt	   */
> > +#define TIM_SR_UIF	BIT(0)	/* Update interrupt flag   */
> > +#define TIM_EGR_UG	BIT(0)	/* Update Generation       */
> > +#define TIM_CCMR_PE	BIT(3)	/* Channel Preload Enable  */
> > +#define TIM_CCMR_M1	(BIT(6) | BIT(5))  /* Channel PWM Mode 1 */
> > +#define TIM_CCER_CC1E	BIT(0)	/* Capt/Comp 1  out Ena    */
> > +#define TIM_CCER_CC1P	BIT(1)	/* Capt/Comp 1  Polarity   */
> > +#define TIM_CCER_CC1NE	BIT(2)	/* Capt/Comp 1N out Ena    */
> > +#define TIM_CCER_CC1NP	BIT(3)	/* Capt/Comp 1N Polarity   */
> > +#define TIM_CCER_CCXE	(BIT(0) | BIT(4) | BIT(8) | BIT(12))
> > +#define TIM_BDTR_BKE	BIT(12) /* Break input enable	   */
> > +#define TIM_BDTR_BKP	BIT(13) /* Break input polarity	   */
> > +#define TIM_BDTR_AOE	BIT(14)	/* Automatic Output Enable */
> > +#define TIM_BDTR_MOE	BIT(15)	/* Main Output Enable      */
> > +
> > +#define STM32_TIMER_CELLS	2
> > +#define MAX_TIM_PSC		0xFFFF
> > +
> > +struct stm32_mfd_timer_cfg {
> > +	const char *pwm_name;
> > +	const char *pwm_compatible;
> > +	const char *trigger_name;
> > +	const char *trigger_compatible;
> > +};
> > +
> > +struct stm32_mfd_timer_dev {
> > +	/* Device data */
> > +	struct device *dev;
> > +	struct clk *clk;
> > +	int irq;
> > +
> > +	/* Registers mapping */
> > +	struct regmap *regmap;
> > +
> > +	/* Private data */
> > +	struct mfd_cell cells[STM32_TIMER_CELLS];
> > +	struct stm32_mfd_timer_cfg *cfg;
> > +};
> > +
> > +#endif
> 

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 2/7] add MFD for stm32 timer IP
@ 2016-11-22 16:41       ` Lee Jones
  0 siblings, 0 replies; 64+ messages in thread
From: Lee Jones @ 2016-11-22 16:41 UTC (permalink / raw)
  To: Benjamin Gaignard
  Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	alexandre.torgue-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	linux-pwm-u79uwXL29TY76Z2rM5mHXA, jic23-DgEjT+Ai2ygdnm+yROfE0A,
	knaack.h-Mmb7MZpHnFY, lars-Qo5EllUWu/uELgA04lAiVw,
	pmeerw-jW+XmwGofnusTnJN9+BGXg, linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	fabrice.gasnier-qxv4g6HH51o, gerald.baeza-qxv4g6HH51o,
	arnaud.pouliquen-qxv4g6HH51o,
	linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
	linaro-kernel-cunTk1MwBs8s++Sfvej+rw, Benjamin Gaignard

On Tue, 22 Nov 2016, Lee Jones wrote:

> On Tue, 22 Nov 2016, Benjamin Gaignard wrote:
> 
> > This hardware block could at used at same time for PWM generation
> > and IIO timer for other IPs like DAC, ADC or other timers.
> > PWM and IIO timer configuration are mixed in the same registers
> > so we need a MFD to be able to share those registers.
> > 
> > Signed-off-by: Benjamin Gaignard <benjamin.gaignard-qxv4g6HH51o@public.gmane.org>
> > ---
> >  drivers/mfd/Kconfig                 |  10 ++
> >  drivers/mfd/Makefile                |   2 +
> >  drivers/mfd/stm32-mfd-timer.c       | 236 ++++++++++++++++++++++++++++++++++++
> >  include/linux/mfd/stm32-mfd-timer.h |  78 ++++++++++++
> >  4 files changed, 326 insertions(+)
> >  create mode 100644 drivers/mfd/stm32-mfd-timer.c
> >  create mode 100644 include/linux/mfd/stm32-mfd-timer.h
> 
> This driver is going to need a re-write.
> 
> However, it's difficult to provide suggestions, since I've been left
> off of the Cc: list for all the other patches.
> 
> Please re-send the set with all of the Maintainers Cc'ed on all of
> the patches.

Scrap that -- they all just came trickling through!

> > diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> > index c6df644..63aee36 100644
> > --- a/drivers/mfd/Kconfig
> > +++ b/drivers/mfd/Kconfig
> > @@ -1607,6 +1607,15 @@ config MFD_STW481X
> >  	  in various ST Microelectronics and ST-Ericsson embedded
> >  	  Nomadik series.
> >  
> > +config MFD_STM32_TIMER
> > +	tristate "Support for STM32 multifunctions timer"
> > +	select MFD_CORE
> > +	select REGMAP
> > +	depends on ARCH_STM32
> > +	depends on OF
> > +	help
> > +	  Select multifunction driver (pwm, IIO trigger) for stm32 timers
> > +
> >  menu "Multimedia Capabilities Port drivers"
> >  	depends on ARCH_SA1100
> >  
> > @@ -1644,4 +1653,5 @@ config MFD_VEXPRESS_SYSREG
> >  	  on the ARM Ltd. Versatile Express board.
> >  
> >  endmenu
> > +
> >  endif
> > diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> > index 9834e66..b348c3e 100644
> > --- a/drivers/mfd/Makefile
> > +++ b/drivers/mfd/Makefile
> > @@ -211,3 +211,5 @@ obj-$(CONFIG_INTEL_SOC_PMIC)	+= intel-soc-pmic.o
> >  obj-$(CONFIG_MFD_MT6397)	+= mt6397-core.o
> >  
> >  obj-$(CONFIG_MFD_ALTERA_A10SR)	+= altera-a10sr.o
> > +
> > +obj-$(CONFIG_MFD_STM32_TIMER) 	+= stm32-mfd-timer.o
> > diff --git a/drivers/mfd/stm32-mfd-timer.c b/drivers/mfd/stm32-mfd-timer.c
> > new file mode 100644
> > index 0000000..67e7db3
> > --- /dev/null
> > +++ b/drivers/mfd/stm32-mfd-timer.c
> > @@ -0,0 +1,236 @@
> > +/*
> > + * stm32-timer.c
> > + *
> > + * Copyright (C) STMicroelectronics 2016
> > + * Author: Benjamin Gaignard <benjamin.gaignard-qxv4g6HH51o@public.gmane.org> for STMicroelectronics.
> > + * License terms:  GNU General Public License (GPL), version 2
> > + */
> > +
> > +#include <linux/device.h>
> > +#include <linux/init.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +
> > +#include <linux/mfd/stm32-mfd-timer.h>
> > +
> > +static const struct stm32_mfd_timer_cfg mfd_cells_cfg[] = {
> > +	{
> > +		.pwm_name = "pwm1",
> > +		.pwm_compatible = "st,stm32-pwm1",
> > +		.trigger_name = "iiotimer1",
> > +		.trigger_compatible = "st,stm32-iio-timer1",
> > +	},
> > +	{
> > +		.pwm_name = "pwm2",
> > +		.pwm_compatible = "st,stm32-pwm2",
> > +		.trigger_name = "iiotimer2",
> > +		.trigger_compatible = "st,stm32-iio-timer2",
> > +	},
> > +	{
> > +		.pwm_name = "pwm3",
> > +		.pwm_compatible = "st,stm32-pwm3",
> > +		.trigger_name = "iiotimer3",
> > +		.trigger_compatible = "st,stm32-iio-timer3",
> > +	},
> > +	{
> > +		.pwm_name = "pwm4",
> > +		.pwm_compatible = "st,stm32-pwm4",
> > +		.trigger_name = "iiotimer4",
> > +		.trigger_compatible = "st,stm32-iio-timer4",
> > +	},
> > +	{
> > +		.pwm_name = "pwm5",
> > +		.pwm_compatible = "st,stm32-pwm5",
> > +		.trigger_name = "iiotimer5",
> > +		.trigger_compatible = "st,stm32-iio-timer5",
> > +	},
> > +	{
> > +		.trigger_name = "iiotimer6",
> > +		.trigger_compatible = "st,stm32-iio-timer6",
> > +	},
> > +	{
> > +		.trigger_name = "iiotimer7",
> > +		.trigger_compatible = "st,stm32-iio-timer7",
> > +	},
> > +	{
> > +		.pwm_name = "pwm8",
> > +		.pwm_compatible = "st,stm32-pwm8",
> > +		.trigger_name = "iiotimer8",
> > +		.trigger_compatible = "st,stm32-iio-timer8",
> > +	},
> > +	{
> > +		.pwm_name = "pwm9",
> > +		.pwm_compatible = "st,stm32-pwm9",
> > +		.trigger_name = "iiotimer9",
> > +		.trigger_compatible = "st,stm32-iio-timer9",
> > +	},
> > +	{
> > +		.pwm_name = "pwm10",
> > +		.pwm_compatible = "st,stm32-pwm10",
> > +	},
> > +	{
> > +		.pwm_name = "pwm11",
> > +		.pwm_compatible = "st,stm32-pwm11",
> > +	},
> > +	{
> > +		.pwm_name = "pwm12",
> > +		.pwm_compatible = "st,stm32-pwm12",
> > +		.trigger_name = "iiotimer12",
> > +		.trigger_compatible = "st,stm32-iio-timer12",
> > +	},
> > +	{
> > +		.pwm_name = "pwm13",
> > +		.pwm_compatible = "st,stm32-pwm13",
> > +	},
> > +	{
> > +		.pwm_name = "pwm14",
> > +		.pwm_compatible = "st,stm32-pwm14",
> > +	},
> > +};
> > +
> > +static const struct of_device_id stm32_timer_of_match[] = {
> > +	{
> > +		.compatible = "st,stm32-mfd-timer1",
> > +		.data = &mfd_cells_cfg[0],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer2",
> > +		.data = &mfd_cells_cfg[1],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer3",
> > +		.data = &mfd_cells_cfg[2],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer4",
> > +		.data = &mfd_cells_cfg[3],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer5",
> > +		.data = &mfd_cells_cfg[4],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer6",
> > +		.data = &mfd_cells_cfg[5],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer7",
> > +		.data = &mfd_cells_cfg[6],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer8",
> > +		.data = &mfd_cells_cfg[7],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer9",
> > +		.data = &mfd_cells_cfg[8],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer10",
> > +		.data = &mfd_cells_cfg[9],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer11",
> > +		.data = &mfd_cells_cfg[10],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer12",
> > +		.data = &mfd_cells_cfg[11],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer13",
> > +		.data = &mfd_cells_cfg[12],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer14",
> > +		.data = &mfd_cells_cfg[13],
> > +	},
> > +};
> > +
> > +static const struct regmap_config stm32_timer_regmap_cfg = {
> > +	.reg_bits = 32,
> > +	.val_bits = 32,
> > +	.reg_stride = sizeof(u32),
> > +	.max_register = 0x400,
> > +	.fast_io = true,
> > +};
> > +
> > +static int stm32_mfd_timer_probe(struct platform_device *pdev)
> > +{
> > +	struct device *dev = &pdev->dev;
> > +	struct device_node *np = dev->of_node;
> > +	struct stm32_mfd_timer_dev *mfd;
> > +	struct resource *res;
> > +	int ret, nb_cells = 0;
> > +	struct mfd_cell *cell = NULL;
> > +	void __iomem *mmio;
> > +
> > +	mfd = devm_kzalloc(dev, sizeof(*mfd), GFP_KERNEL);
> > +	if (!mfd)
> > +		return -ENOMEM;
> > +
> > +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > +	if (!res)
> > +		return -ENOMEM;
> > +
> > +	mmio = devm_ioremap_resource(dev, res);
> > +	if (IS_ERR(mmio))
> > +		return PTR_ERR(mmio);
> > +
> > +	mfd->regmap = devm_regmap_init_mmio_clk(dev, "mfd_timer_clk", mmio,
> > +						&stm32_timer_regmap_cfg);
> > +	if (IS_ERR(mfd->regmap))
> > +		return PTR_ERR(mfd->regmap);
> > +
> > +	mfd->clk = devm_clk_get(dev, NULL);
> > +	if (IS_ERR(mfd->clk))
> > +		return PTR_ERR(mfd->clk);
> > +
> > +	mfd->irq = platform_get_irq(pdev, 0);
> > +	if (mfd->irq < 0)
> > +		return -EINVAL;
> > +
> > +	/* populate data structure depending on compatibility */
> > +	if (!of_match_node(stm32_timer_of_match, np)->data)
> > +		return -EINVAL;
> > +
> > +	mfd->cfg =
> > +	(struct stm32_mfd_timer_cfg *)of_match_node(stm32_timer_of_match, np)->data;
> > +
> > +	if (mfd->cfg->pwm_name && mfd->cfg->pwm_compatible) {
> > +		cell = &mfd->cells[nb_cells++];
> > +		cell->name = mfd->cfg->pwm_name;
> > +		cell->of_compatible = mfd->cfg->pwm_compatible;
> > +		cell->platform_data = mfd;
> > +		cell->pdata_size = sizeof(*mfd);
> > +	}
> > +
> > +	if (mfd->cfg->trigger_name && mfd->cfg->trigger_compatible) {
> > +		cell = &mfd->cells[nb_cells++];
> > +		cell->name = mfd->cfg->trigger_name;
> > +		cell->of_compatible = mfd->cfg->trigger_compatible;
> > +		cell->platform_data = mfd;
> > +		cell->pdata_size = sizeof(*mfd);
> > +	}
> > +
> > +	ret = devm_mfd_add_devices(&pdev->dev, pdev->id, mfd->cells,
> > +				   nb_cells, NULL, 0, NULL);
> > +	if (ret)
> > +		return ret;
> > +
> > +	platform_set_drvdata(pdev, mfd);
> > +
> > +	return 0;
> > +}
> > +
> > +static struct platform_driver stm32_mfd_timer_driver = {
> > +	.probe		= stm32_mfd_timer_probe,
> > +	.driver	= {
> > +		.name	= "stm32-mfd-timer",
> > +		.of_match_table = stm32_timer_of_match,
> > +	},
> > +};
> > +module_platform_driver(stm32_mfd_timer_driver);
> > +
> > +MODULE_DESCRIPTION("STMicroelectronics STM32 Timer MFD");
> > +MODULE_LICENSE("GPL");
> > diff --git a/include/linux/mfd/stm32-mfd-timer.h b/include/linux/mfd/stm32-mfd-timer.h
> > new file mode 100644
> > index 0000000..4a79c22
> > --- /dev/null
> > +++ b/include/linux/mfd/stm32-mfd-timer.h
> > @@ -0,0 +1,78 @@
> > +/*
> > + * stm32-mfd-timer.h
> > + *
> > + * Copyright (C) STMicroelectronics 2016
> > + * Author: Benjamin Gaignard <benjamin.gaignard-qxv4g6HH51o@public.gmane.org> for STMicroelectronics.
> > + * License terms:  GNU General Public License (GPL), version 2
> > + */
> > +
> > +#ifndef _LINUX_MFD_STM32_TIMER_H_
> > +#define _LINUX_MFD_STM32_TIMER_H_
> > +
> > +#include <linux/clk.h>
> > +#include <linux/mfd/core.h>
> > +#include <linux/regmap.h>
> > +#include <linux/reset.h>
> > +
> > +#define TIM_CR1		0x00	/* Control Register 1      */
> > +#define TIM_CR2		0x04	/* Control Register 2      */
> > +#define TIM_SMCR	0x08	/* Slave mode control reg  */
> > +#define TIM_DIER	0x0C	/* DMA/interrupt register  */
> > +#define TIM_SR		0x10	/* Status register	   */
> > +#define TIM_EGR		0x14	/* Event Generation Reg    */
> > +#define TIM_CCMR1	0x18	/* Capt/Comp 1 Mode Reg    */
> > +#define TIM_CCMR2	0x1C	/* Capt/Comp 2 Mode Reg    */
> > +#define TIM_CCER	0x20	/* Capt/Comp Enable Reg    */
> > +#define TIM_PSC		0x28	/* Prescaler               */
> > +#define TIM_ARR		0x2c	/* Auto-Reload Register    */
> > +#define TIM_CCR1	0x34	/* Capt/Comp Register 1    */
> > +#define TIM_CCR2	0x38	/* Capt/Comp Register 2    */
> > +#define TIM_CCR3	0x3C	/* Capt/Comp Register 3    */
> > +#define TIM_CCR4	0x40	/* Capt/Comp Register 4    */
> > +#define TIM_BDTR	0x44	/* Break and Dead-Time Reg */
> > +
> > +#define TIM_CR1_CEN	BIT(0)	/* Counter Enable	   */
> > +#define TIM_CR1_ARPE	BIT(7)	/* Auto-reload Preload Ena */
> > +#define TIM_CR2_MMS	(BIT(4) | BIT(5) | BIT(6)) /* Master mode selection */
> > +#define TIM_SMCR_SMS	(BIT(0) | BIT(1) | BIT(2)) /* Slave mode selection */
> > +#define TIM_SMCR_TS	(BIT(4) | BIT(5) | BIT(6)) /* Trigger selection */
> > +#define TIM_DIER_UIE	BIT(0)	/* Update interrupt	   */
> > +#define TIM_SR_UIF	BIT(0)	/* Update interrupt flag   */
> > +#define TIM_EGR_UG	BIT(0)	/* Update Generation       */
> > +#define TIM_CCMR_PE	BIT(3)	/* Channel Preload Enable  */
> > +#define TIM_CCMR_M1	(BIT(6) | BIT(5))  /* Channel PWM Mode 1 */
> > +#define TIM_CCER_CC1E	BIT(0)	/* Capt/Comp 1  out Ena    */
> > +#define TIM_CCER_CC1P	BIT(1)	/* Capt/Comp 1  Polarity   */
> > +#define TIM_CCER_CC1NE	BIT(2)	/* Capt/Comp 1N out Ena    */
> > +#define TIM_CCER_CC1NP	BIT(3)	/* Capt/Comp 1N Polarity   */
> > +#define TIM_CCER_CCXE	(BIT(0) | BIT(4) | BIT(8) | BIT(12))
> > +#define TIM_BDTR_BKE	BIT(12) /* Break input enable	   */
> > +#define TIM_BDTR_BKP	BIT(13) /* Break input polarity	   */
> > +#define TIM_BDTR_AOE	BIT(14)	/* Automatic Output Enable */
> > +#define TIM_BDTR_MOE	BIT(15)	/* Main Output Enable      */
> > +
> > +#define STM32_TIMER_CELLS	2
> > +#define MAX_TIM_PSC		0xFFFF
> > +
> > +struct stm32_mfd_timer_cfg {
> > +	const char *pwm_name;
> > +	const char *pwm_compatible;
> > +	const char *trigger_name;
> > +	const char *trigger_compatible;
> > +};
> > +
> > +struct stm32_mfd_timer_dev {
> > +	/* Device data */
> > +	struct device *dev;
> > +	struct clk *clk;
> > +	int irq;
> > +
> > +	/* Registers mapping */
> > +	struct regmap *regmap;
> > +
> > +	/* Private data */
> > +	struct mfd_cell cells[STM32_TIMER_CELLS];
> > +	struct stm32_mfd_timer_cfg *cfg;
> > +};
> > +
> > +#endif
> 

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 64+ messages in thread

* [PATCH 2/7] add MFD for stm32 timer IP
@ 2016-11-22 16:41       ` Lee Jones
  0 siblings, 0 replies; 64+ messages in thread
From: Lee Jones @ 2016-11-22 16:41 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 22 Nov 2016, Lee Jones wrote:

> On Tue, 22 Nov 2016, Benjamin Gaignard wrote:
> 
> > This hardware block could at used at same time for PWM generation
> > and IIO timer for other IPs like DAC, ADC or other timers.
> > PWM and IIO timer configuration are mixed in the same registers
> > so we need a MFD to be able to share those registers.
> > 
> > Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
> > ---
> >  drivers/mfd/Kconfig                 |  10 ++
> >  drivers/mfd/Makefile                |   2 +
> >  drivers/mfd/stm32-mfd-timer.c       | 236 ++++++++++++++++++++++++++++++++++++
> >  include/linux/mfd/stm32-mfd-timer.h |  78 ++++++++++++
> >  4 files changed, 326 insertions(+)
> >  create mode 100644 drivers/mfd/stm32-mfd-timer.c
> >  create mode 100644 include/linux/mfd/stm32-mfd-timer.h
> 
> This driver is going to need a re-write.
> 
> However, it's difficult to provide suggestions, since I've been left
> off of the Cc: list for all the other patches.
> 
> Please re-send the set with all of the Maintainers Cc'ed on all of
> the patches.

Scrap that -- they all just came trickling through!

> > diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> > index c6df644..63aee36 100644
> > --- a/drivers/mfd/Kconfig
> > +++ b/drivers/mfd/Kconfig
> > @@ -1607,6 +1607,15 @@ config MFD_STW481X
> >  	  in various ST Microelectronics and ST-Ericsson embedded
> >  	  Nomadik series.
> >  
> > +config MFD_STM32_TIMER
> > +	tristate "Support for STM32 multifunctions timer"
> > +	select MFD_CORE
> > +	select REGMAP
> > +	depends on ARCH_STM32
> > +	depends on OF
> > +	help
> > +	  Select multifunction driver (pwm, IIO trigger) for stm32 timers
> > +
> >  menu "Multimedia Capabilities Port drivers"
> >  	depends on ARCH_SA1100
> >  
> > @@ -1644,4 +1653,5 @@ config MFD_VEXPRESS_SYSREG
> >  	  on the ARM Ltd. Versatile Express board.
> >  
> >  endmenu
> > +
> >  endif
> > diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> > index 9834e66..b348c3e 100644
> > --- a/drivers/mfd/Makefile
> > +++ b/drivers/mfd/Makefile
> > @@ -211,3 +211,5 @@ obj-$(CONFIG_INTEL_SOC_PMIC)	+= intel-soc-pmic.o
> >  obj-$(CONFIG_MFD_MT6397)	+= mt6397-core.o
> >  
> >  obj-$(CONFIG_MFD_ALTERA_A10SR)	+= altera-a10sr.o
> > +
> > +obj-$(CONFIG_MFD_STM32_TIMER) 	+= stm32-mfd-timer.o
> > diff --git a/drivers/mfd/stm32-mfd-timer.c b/drivers/mfd/stm32-mfd-timer.c
> > new file mode 100644
> > index 0000000..67e7db3
> > --- /dev/null
> > +++ b/drivers/mfd/stm32-mfd-timer.c
> > @@ -0,0 +1,236 @@
> > +/*
> > + * stm32-timer.c
> > + *
> > + * Copyright (C) STMicroelectronics 2016
> > + * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
> > + * License terms:  GNU General Public License (GPL), version 2
> > + */
> > +
> > +#include <linux/device.h>
> > +#include <linux/init.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +
> > +#include <linux/mfd/stm32-mfd-timer.h>
> > +
> > +static const struct stm32_mfd_timer_cfg mfd_cells_cfg[] = {
> > +	{
> > +		.pwm_name = "pwm1",
> > +		.pwm_compatible = "st,stm32-pwm1",
> > +		.trigger_name = "iiotimer1",
> > +		.trigger_compatible = "st,stm32-iio-timer1",
> > +	},
> > +	{
> > +		.pwm_name = "pwm2",
> > +		.pwm_compatible = "st,stm32-pwm2",
> > +		.trigger_name = "iiotimer2",
> > +		.trigger_compatible = "st,stm32-iio-timer2",
> > +	},
> > +	{
> > +		.pwm_name = "pwm3",
> > +		.pwm_compatible = "st,stm32-pwm3",
> > +		.trigger_name = "iiotimer3",
> > +		.trigger_compatible = "st,stm32-iio-timer3",
> > +	},
> > +	{
> > +		.pwm_name = "pwm4",
> > +		.pwm_compatible = "st,stm32-pwm4",
> > +		.trigger_name = "iiotimer4",
> > +		.trigger_compatible = "st,stm32-iio-timer4",
> > +	},
> > +	{
> > +		.pwm_name = "pwm5",
> > +		.pwm_compatible = "st,stm32-pwm5",
> > +		.trigger_name = "iiotimer5",
> > +		.trigger_compatible = "st,stm32-iio-timer5",
> > +	},
> > +	{
> > +		.trigger_name = "iiotimer6",
> > +		.trigger_compatible = "st,stm32-iio-timer6",
> > +	},
> > +	{
> > +		.trigger_name = "iiotimer7",
> > +		.trigger_compatible = "st,stm32-iio-timer7",
> > +	},
> > +	{
> > +		.pwm_name = "pwm8",
> > +		.pwm_compatible = "st,stm32-pwm8",
> > +		.trigger_name = "iiotimer8",
> > +		.trigger_compatible = "st,stm32-iio-timer8",
> > +	},
> > +	{
> > +		.pwm_name = "pwm9",
> > +		.pwm_compatible = "st,stm32-pwm9",
> > +		.trigger_name = "iiotimer9",
> > +		.trigger_compatible = "st,stm32-iio-timer9",
> > +	},
> > +	{
> > +		.pwm_name = "pwm10",
> > +		.pwm_compatible = "st,stm32-pwm10",
> > +	},
> > +	{
> > +		.pwm_name = "pwm11",
> > +		.pwm_compatible = "st,stm32-pwm11",
> > +	},
> > +	{
> > +		.pwm_name = "pwm12",
> > +		.pwm_compatible = "st,stm32-pwm12",
> > +		.trigger_name = "iiotimer12",
> > +		.trigger_compatible = "st,stm32-iio-timer12",
> > +	},
> > +	{
> > +		.pwm_name = "pwm13",
> > +		.pwm_compatible = "st,stm32-pwm13",
> > +	},
> > +	{
> > +		.pwm_name = "pwm14",
> > +		.pwm_compatible = "st,stm32-pwm14",
> > +	},
> > +};
> > +
> > +static const struct of_device_id stm32_timer_of_match[] = {
> > +	{
> > +		.compatible = "st,stm32-mfd-timer1",
> > +		.data = &mfd_cells_cfg[0],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer2",
> > +		.data = &mfd_cells_cfg[1],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer3",
> > +		.data = &mfd_cells_cfg[2],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer4",
> > +		.data = &mfd_cells_cfg[3],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer5",
> > +		.data = &mfd_cells_cfg[4],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer6",
> > +		.data = &mfd_cells_cfg[5],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer7",
> > +		.data = &mfd_cells_cfg[6],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer8",
> > +		.data = &mfd_cells_cfg[7],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer9",
> > +		.data = &mfd_cells_cfg[8],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer10",
> > +		.data = &mfd_cells_cfg[9],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer11",
> > +		.data = &mfd_cells_cfg[10],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer12",
> > +		.data = &mfd_cells_cfg[11],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer13",
> > +		.data = &mfd_cells_cfg[12],
> > +	},
> > +	{
> > +		.compatible = "st,stm32-mfd-timer14",
> > +		.data = &mfd_cells_cfg[13],
> > +	},
> > +};
> > +
> > +static const struct regmap_config stm32_timer_regmap_cfg = {
> > +	.reg_bits = 32,
> > +	.val_bits = 32,
> > +	.reg_stride = sizeof(u32),
> > +	.max_register = 0x400,
> > +	.fast_io = true,
> > +};
> > +
> > +static int stm32_mfd_timer_probe(struct platform_device *pdev)
> > +{
> > +	struct device *dev = &pdev->dev;
> > +	struct device_node *np = dev->of_node;
> > +	struct stm32_mfd_timer_dev *mfd;
> > +	struct resource *res;
> > +	int ret, nb_cells = 0;
> > +	struct mfd_cell *cell = NULL;
> > +	void __iomem *mmio;
> > +
> > +	mfd = devm_kzalloc(dev, sizeof(*mfd), GFP_KERNEL);
> > +	if (!mfd)
> > +		return -ENOMEM;
> > +
> > +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > +	if (!res)
> > +		return -ENOMEM;
> > +
> > +	mmio = devm_ioremap_resource(dev, res);
> > +	if (IS_ERR(mmio))
> > +		return PTR_ERR(mmio);
> > +
> > +	mfd->regmap = devm_regmap_init_mmio_clk(dev, "mfd_timer_clk", mmio,
> > +						&stm32_timer_regmap_cfg);
> > +	if (IS_ERR(mfd->regmap))
> > +		return PTR_ERR(mfd->regmap);
> > +
> > +	mfd->clk = devm_clk_get(dev, NULL);
> > +	if (IS_ERR(mfd->clk))
> > +		return PTR_ERR(mfd->clk);
> > +
> > +	mfd->irq = platform_get_irq(pdev, 0);
> > +	if (mfd->irq < 0)
> > +		return -EINVAL;
> > +
> > +	/* populate data structure depending on compatibility */
> > +	if (!of_match_node(stm32_timer_of_match, np)->data)
> > +		return -EINVAL;
> > +
> > +	mfd->cfg =
> > +	(struct stm32_mfd_timer_cfg *)of_match_node(stm32_timer_of_match, np)->data;
> > +
> > +	if (mfd->cfg->pwm_name && mfd->cfg->pwm_compatible) {
> > +		cell = &mfd->cells[nb_cells++];
> > +		cell->name = mfd->cfg->pwm_name;
> > +		cell->of_compatible = mfd->cfg->pwm_compatible;
> > +		cell->platform_data = mfd;
> > +		cell->pdata_size = sizeof(*mfd);
> > +	}
> > +
> > +	if (mfd->cfg->trigger_name && mfd->cfg->trigger_compatible) {
> > +		cell = &mfd->cells[nb_cells++];
> > +		cell->name = mfd->cfg->trigger_name;
> > +		cell->of_compatible = mfd->cfg->trigger_compatible;
> > +		cell->platform_data = mfd;
> > +		cell->pdata_size = sizeof(*mfd);
> > +	}
> > +
> > +	ret = devm_mfd_add_devices(&pdev->dev, pdev->id, mfd->cells,
> > +				   nb_cells, NULL, 0, NULL);
> > +	if (ret)
> > +		return ret;
> > +
> > +	platform_set_drvdata(pdev, mfd);
> > +
> > +	return 0;
> > +}
> > +
> > +static struct platform_driver stm32_mfd_timer_driver = {
> > +	.probe		= stm32_mfd_timer_probe,
> > +	.driver	= {
> > +		.name	= "stm32-mfd-timer",
> > +		.of_match_table = stm32_timer_of_match,
> > +	},
> > +};
> > +module_platform_driver(stm32_mfd_timer_driver);
> > +
> > +MODULE_DESCRIPTION("STMicroelectronics STM32 Timer MFD");
> > +MODULE_LICENSE("GPL");
> > diff --git a/include/linux/mfd/stm32-mfd-timer.h b/include/linux/mfd/stm32-mfd-timer.h
> > new file mode 100644
> > index 0000000..4a79c22
> > --- /dev/null
> > +++ b/include/linux/mfd/stm32-mfd-timer.h
> > @@ -0,0 +1,78 @@
> > +/*
> > + * stm32-mfd-timer.h
> > + *
> > + * Copyright (C) STMicroelectronics 2016
> > + * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
> > + * License terms:  GNU General Public License (GPL), version 2
> > + */
> > +
> > +#ifndef _LINUX_MFD_STM32_TIMER_H_
> > +#define _LINUX_MFD_STM32_TIMER_H_
> > +
> > +#include <linux/clk.h>
> > +#include <linux/mfd/core.h>
> > +#include <linux/regmap.h>
> > +#include <linux/reset.h>
> > +
> > +#define TIM_CR1		0x00	/* Control Register 1      */
> > +#define TIM_CR2		0x04	/* Control Register 2      */
> > +#define TIM_SMCR	0x08	/* Slave mode control reg  */
> > +#define TIM_DIER	0x0C	/* DMA/interrupt register  */
> > +#define TIM_SR		0x10	/* Status register	   */
> > +#define TIM_EGR		0x14	/* Event Generation Reg    */
> > +#define TIM_CCMR1	0x18	/* Capt/Comp 1 Mode Reg    */
> > +#define TIM_CCMR2	0x1C	/* Capt/Comp 2 Mode Reg    */
> > +#define TIM_CCER	0x20	/* Capt/Comp Enable Reg    */
> > +#define TIM_PSC		0x28	/* Prescaler               */
> > +#define TIM_ARR		0x2c	/* Auto-Reload Register    */
> > +#define TIM_CCR1	0x34	/* Capt/Comp Register 1    */
> > +#define TIM_CCR2	0x38	/* Capt/Comp Register 2    */
> > +#define TIM_CCR3	0x3C	/* Capt/Comp Register 3    */
> > +#define TIM_CCR4	0x40	/* Capt/Comp Register 4    */
> > +#define TIM_BDTR	0x44	/* Break and Dead-Time Reg */
> > +
> > +#define TIM_CR1_CEN	BIT(0)	/* Counter Enable	   */
> > +#define TIM_CR1_ARPE	BIT(7)	/* Auto-reload Preload Ena */
> > +#define TIM_CR2_MMS	(BIT(4) | BIT(5) | BIT(6)) /* Master mode selection */
> > +#define TIM_SMCR_SMS	(BIT(0) | BIT(1) | BIT(2)) /* Slave mode selection */
> > +#define TIM_SMCR_TS	(BIT(4) | BIT(5) | BIT(6)) /* Trigger selection */
> > +#define TIM_DIER_UIE	BIT(0)	/* Update interrupt	   */
> > +#define TIM_SR_UIF	BIT(0)	/* Update interrupt flag   */
> > +#define TIM_EGR_UG	BIT(0)	/* Update Generation       */
> > +#define TIM_CCMR_PE	BIT(3)	/* Channel Preload Enable  */
> > +#define TIM_CCMR_M1	(BIT(6) | BIT(5))  /* Channel PWM Mode 1 */
> > +#define TIM_CCER_CC1E	BIT(0)	/* Capt/Comp 1  out Ena    */
> > +#define TIM_CCER_CC1P	BIT(1)	/* Capt/Comp 1  Polarity   */
> > +#define TIM_CCER_CC1NE	BIT(2)	/* Capt/Comp 1N out Ena    */
> > +#define TIM_CCER_CC1NP	BIT(3)	/* Capt/Comp 1N Polarity   */
> > +#define TIM_CCER_CCXE	(BIT(0) | BIT(4) | BIT(8) | BIT(12))
> > +#define TIM_BDTR_BKE	BIT(12) /* Break input enable	   */
> > +#define TIM_BDTR_BKP	BIT(13) /* Break input polarity	   */
> > +#define TIM_BDTR_AOE	BIT(14)	/* Automatic Output Enable */
> > +#define TIM_BDTR_MOE	BIT(15)	/* Main Output Enable      */
> > +
> > +#define STM32_TIMER_CELLS	2
> > +#define MAX_TIM_PSC		0xFFFF
> > +
> > +struct stm32_mfd_timer_cfg {
> > +	const char *pwm_name;
> > +	const char *pwm_compatible;
> > +	const char *trigger_name;
> > +	const char *trigger_compatible;
> > +};
> > +
> > +struct stm32_mfd_timer_dev {
> > +	/* Device data */
> > +	struct device *dev;
> > +	struct clk *clk;
> > +	int irq;
> > +
> > +	/* Registers mapping */
> > +	struct regmap *regmap;
> > +
> > +	/* Private data */
> > +	struct mfd_cell cells[STM32_TIMER_CELLS];
> > +	struct stm32_mfd_timer_cfg *cfg;
> > +};
> > +
> > +#endif
> 

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 1/7] add binding for stm32 multifunctions timer driver
  2016-11-22 16:13   ` Benjamin Gaignard
@ 2016-11-22 16:52     ` Lee Jones
  -1 siblings, 0 replies; 64+ messages in thread
From: Lee Jones @ 2016-11-22 16:52 UTC (permalink / raw)
  To: Benjamin Gaignard
  Cc: robh+dt, mark.rutland, alexandre.torgue, devicetree,
	linux-kernel, thierry.reding, linux-pwm, jic23, knaack.h, lars,
	pmeerw, linux-iio, linux-arm-kernel, fabrice.gasnier,
	gerald.baeza, arnaud.pouliquen, linus.walleij, linaro-kernel,
	Benjamin Gaignard

On Tue, 22 Nov 2016, Benjamin Gaignard wrote:

> Add bindings information for stm32 timer MFD
> 
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
> ---
>  .../devicetree/bindings/mfd/stm32-timer.txt        | 53 ++++++++++++++++++++++
>  1 file changed, 53 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mfd/stm32-timer.txt
> 
> diff --git a/Documentation/devicetree/bindings/mfd/stm32-timer.txt b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
> new file mode 100644
> index 0000000..3cefce1
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
> @@ -0,0 +1,53 @@
> +STM32 multifunctions timer driver

"STM32 Multi-Function Timer/PWM device bindings"

Doesn't this shared device have a better name?

> +stm32 timer MFD allow to handle at the same time pwm and IIO timer devices

No need for this sentence.

> +Required parameters:
> +- compatible: must be one of the follow value:
> +	"st,stm32-mfd-timer1"
> +	"st,stm32-mfd-timer2"
> +	"st,stm32-mfd-timer3"
> +	"st,stm32-mfd-timer4"
> +	"st,stm32-mfd-timer5"
> +	"st,stm32-mfd-timer6"
> +	"st,stm32-mfd-timer7"
> +	"st,stm32-mfd-timer8"
> +	"st,stm32-mfd-timer9"
> +	"st,stm32-mfd-timer10"
> +	"st,stm32-mfd-timer11"
> +	"st,stm32-mfd-timer12"
> +	"st,stm32-mfd-timer13"
> +	"st,stm32-mfd-timer14"

We don't normally number devices.

What's stopping you from simply doing:

	pwm1: pwm1@40010000 {
		compatible = "st,stm32-pwm";
	};
	pwm2: pwm1@40020000 {
		compatible = "st,stm32-pwm";
	};
	pwm3: pwm1@40030000 {
		compatible = "st,stm32-pwm";
	};

> +- reg :			Physical base address and length of the controller's
> +			registers.
> +- clock-names: 		Set to "mfd_timer_clk".

How many clocks are there?

If only 1, you don't need this property.

"mfd_timer_clk" is not the correct name.

What is it called in the datasheet?

> +- clocks: 		Phandle of the clock used by the timer module.

"Phandle to the clock ..."

> +			For Clk properties, please refer to [1].
> +- interrupts :		Reference to the timer interrupt

Reference to?

See how other binding documents describe this property.

> +Optional parameters:
> +- resets :		Reference to a reset controller asserting the timer

As above.

> +Optional subnodes:

Either use ":" or " :" or "<tab>:", but keep it consistent.

> +- pwm:			See Documentation/devicetree/bindings/pwm/pwm-stm32.txt
> +- iiotimer:		See Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt
> +
> +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt

Use the relative paths "../clock/", "../pwm/", "../iio/".

> +Example:
> +	mfd_timer1: mfdtimer1@40010000 {

This is not an "MFD timer".  MFD is a Linuxisum.

> +		compatible = "st,stm32-mfd-timer1";

Better description required.

> +		reg = <0x40010000 0x400>;
> +		clocks = <&rcc 0 160>;
> +		clock-names = "mfd_timer_clk";
> +		interrupts = <27>;
> +
> +		pwm1: pwm1@40010000 {
> +			compatible = "st,stm32-pwm1";
> +		};
> +
> +		iiotimer1: iiotimer1@40010000 {
> +			compatible = "st,stm32-iio-timer1";
> +		};
> +	};

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 64+ messages in thread

* [PATCH 1/7] add binding for stm32 multifunctions timer driver
@ 2016-11-22 16:52     ` Lee Jones
  0 siblings, 0 replies; 64+ messages in thread
From: Lee Jones @ 2016-11-22 16:52 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 22 Nov 2016, Benjamin Gaignard wrote:

> Add bindings information for stm32 timer MFD
> 
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
> ---
>  .../devicetree/bindings/mfd/stm32-timer.txt        | 53 ++++++++++++++++++++++
>  1 file changed, 53 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mfd/stm32-timer.txt
> 
> diff --git a/Documentation/devicetree/bindings/mfd/stm32-timer.txt b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
> new file mode 100644
> index 0000000..3cefce1
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
> @@ -0,0 +1,53 @@
> +STM32 multifunctions timer driver

"STM32 Multi-Function Timer/PWM device bindings"

Doesn't this shared device have a better name?

> +stm32 timer MFD allow to handle at the same time pwm and IIO timer devices

No need for this sentence.

> +Required parameters:
> +- compatible: must be one of the follow value:
> +	"st,stm32-mfd-timer1"
> +	"st,stm32-mfd-timer2"
> +	"st,stm32-mfd-timer3"
> +	"st,stm32-mfd-timer4"
> +	"st,stm32-mfd-timer5"
> +	"st,stm32-mfd-timer6"
> +	"st,stm32-mfd-timer7"
> +	"st,stm32-mfd-timer8"
> +	"st,stm32-mfd-timer9"
> +	"st,stm32-mfd-timer10"
> +	"st,stm32-mfd-timer11"
> +	"st,stm32-mfd-timer12"
> +	"st,stm32-mfd-timer13"
> +	"st,stm32-mfd-timer14"

We don't normally number devices.

What's stopping you from simply doing:

	pwm1: pwm1 at 40010000 {
		compatible = "st,stm32-pwm";
	};
	pwm2: pwm1 at 40020000 {
		compatible = "st,stm32-pwm";
	};
	pwm3: pwm1 at 40030000 {
		compatible = "st,stm32-pwm";
	};

> +- reg :			Physical base address and length of the controller's
> +			registers.
> +- clock-names: 		Set to "mfd_timer_clk".

How many clocks are there?

If only 1, you don't need this property.

"mfd_timer_clk" is not the correct name.

What is it called in the datasheet?

> +- clocks: 		Phandle of the clock used by the timer module.

"Phandle to the clock ..."

> +			For Clk properties, please refer to [1].
> +- interrupts :		Reference to the timer interrupt

Reference to?

See how other binding documents describe this property.

> +Optional parameters:
> +- resets :		Reference to a reset controller asserting the timer

As above.

> +Optional subnodes:

Either use ":" or " :" or "<tab>:", but keep it consistent.

> +- pwm:			See Documentation/devicetree/bindings/pwm/pwm-stm32.txt
> +- iiotimer:		See Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt
> +
> +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt

Use the relative paths "../clock/", "../pwm/", "../iio/".

> +Example:
> +	mfd_timer1: mfdtimer1 at 40010000 {

This is not an "MFD timer".  MFD is a Linuxisum.

> +		compatible = "st,stm32-mfd-timer1";

Better description required.

> +		reg = <0x40010000 0x400>;
> +		clocks = <&rcc 0 160>;
> +		clock-names = "mfd_timer_clk";
> +		interrupts = <27>;
> +
> +		pwm1: pwm1 at 40010000 {
> +			compatible = "st,stm32-pwm1";
> +		};
> +
> +		iiotimer1: iiotimer1 at 40010000 {
> +			compatible = "st,stm32-iio-timer1";
> +		};
> +	};

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 5/7] add bindings for stm32 IIO timer drivers
@ 2016-11-22 16:53     ` Lars-Peter Clausen
  0 siblings, 0 replies; 64+ messages in thread
From: Lars-Peter Clausen @ 2016-11-22 16:53 UTC (permalink / raw)
  To: Benjamin Gaignard, lee.jones, robh+dt, mark.rutland,
	alexandre.torgue, devicetree, linux-kernel, thierry.reding,
	linux-pwm, jic23, knaack.h, pmeerw, linux-iio, linux-arm-kernel
  Cc: fabrice.gasnier, gerald.baeza, arnaud.pouliquen, linus.walleij,
	linaro-kernel, Benjamin Gaignard

On 11/22/2016 05:13 PM, Benjamin Gaignard wrote:
> Define bindings for stm32 IIO timer
> 
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
> ---
>  .../bindings/iio/timer/stm32-iio-timer.txt         | 33 ++++++++++++++++++++++
>  1 file changed, 33 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt
> 
> diff --git a/Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt b/Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt
> new file mode 100644
> index 0000000..b80025e
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt
> @@ -0,0 +1,33 @@
> +timer IIO trigger bindings for STM32
> +
> +Must be a child of STM32 multifunctions timer driver
> +
> +Required parameters:
> +- compatible: must be one of the follow value:
> +	"st,stm32-iio-timer1"
> +	"st,stm32-iio-timer2"
> +	"st,stm32-iio-timer3"
> +	"st,stm32-iio-timer4"
> +	"st,stm32-iio-timer5"
> +	"st,stm32-iio-timer6"
> +	"st,stm32-iio-timer7"
> +	"st,stm32-iio-timer8"
> +	"st,stm32-iio-timer9"
> +	"st,stm32-iio-timer10"
> +	"st,stm32-iio-timer11"
> +	"st,stm32-iio-timer12"
> +	"st,stm32-iio-timer13"
> +	"st,stm32-iio-timer14"

We can't do this. This is a binding for a driver, not for the hardware.

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 5/7] add bindings for stm32 IIO timer drivers
@ 2016-11-22 16:53     ` Lars-Peter Clausen
  0 siblings, 0 replies; 64+ messages in thread
From: Lars-Peter Clausen @ 2016-11-22 16:53 UTC (permalink / raw)
  To: Benjamin Gaignard, lee.jones-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	alexandre.torgue-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
	linux-pwm-u79uwXL29TY76Z2rM5mHXA, jic23-DgEjT+Ai2ygdnm+yROfE0A,
	knaack.h-Mmb7MZpHnFY, pmeerw-jW+XmwGofnusTnJN9+BGXg,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: fabrice.gasnier-qxv4g6HH51o, gerald.baeza-qxv4g6HH51o,
	arnaud.pouliquen-qxv4g6HH51o,
	linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
	linaro-kernel-cunTk1MwBs8s++Sfvej+rw, Benjamin Gaignard

On 11/22/2016 05:13 PM, Benjamin Gaignard wrote:
> Define bindings for stm32 IIO timer
> 
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard-qxv4g6HH51o@public.gmane.org>
> ---
>  .../bindings/iio/timer/stm32-iio-timer.txt         | 33 ++++++++++++++++++++++
>  1 file changed, 33 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt
> 
> diff --git a/Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt b/Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt
> new file mode 100644
> index 0000000..b80025e
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt
> @@ -0,0 +1,33 @@
> +timer IIO trigger bindings for STM32
> +
> +Must be a child of STM32 multifunctions timer driver
> +
> +Required parameters:
> +- compatible: must be one of the follow value:
> +	"st,stm32-iio-timer1"
> +	"st,stm32-iio-timer2"
> +	"st,stm32-iio-timer3"
> +	"st,stm32-iio-timer4"
> +	"st,stm32-iio-timer5"
> +	"st,stm32-iio-timer6"
> +	"st,stm32-iio-timer7"
> +	"st,stm32-iio-timer8"
> +	"st,stm32-iio-timer9"
> +	"st,stm32-iio-timer10"
> +	"st,stm32-iio-timer11"
> +	"st,stm32-iio-timer12"
> +	"st,stm32-iio-timer13"
> +	"st,stm32-iio-timer14"

We can't do this. This is a binding for a driver, not for the hardware.

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 64+ messages in thread

* [PATCH 5/7] add bindings for stm32 IIO timer drivers
@ 2016-11-22 16:53     ` Lars-Peter Clausen
  0 siblings, 0 replies; 64+ messages in thread
From: Lars-Peter Clausen @ 2016-11-22 16:53 UTC (permalink / raw)
  To: linux-arm-kernel

On 11/22/2016 05:13 PM, Benjamin Gaignard wrote:
> Define bindings for stm32 IIO timer
> 
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
> ---
>  .../bindings/iio/timer/stm32-iio-timer.txt         | 33 ++++++++++++++++++++++
>  1 file changed, 33 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt
> 
> diff --git a/Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt b/Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt
> new file mode 100644
> index 0000000..b80025e
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt
> @@ -0,0 +1,33 @@
> +timer IIO trigger bindings for STM32
> +
> +Must be a child of STM32 multifunctions timer driver
> +
> +Required parameters:
> +- compatible: must be one of the follow value:
> +	"st,stm32-iio-timer1"
> +	"st,stm32-iio-timer2"
> +	"st,stm32-iio-timer3"
> +	"st,stm32-iio-timer4"
> +	"st,stm32-iio-timer5"
> +	"st,stm32-iio-timer6"
> +	"st,stm32-iio-timer7"
> +	"st,stm32-iio-timer8"
> +	"st,stm32-iio-timer9"
> +	"st,stm32-iio-timer10"
> +	"st,stm32-iio-timer11"
> +	"st,stm32-iio-timer12"
> +	"st,stm32-iio-timer13"
> +	"st,stm32-iio-timer14"

We can't do this. This is a binding for a driver, not for the hardware.

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 7/7] add stm32 multi-functions timer driver in DT
  2016-11-22 16:13   ` Benjamin Gaignard
  (?)
@ 2016-11-22 17:00     ` Alexandre Torgue
  -1 siblings, 0 replies; 64+ messages in thread
From: Alexandre Torgue @ 2016-11-22 17:00 UTC (permalink / raw)
  To: Benjamin Gaignard, lee.jones, robh+dt, mark.rutland, devicetree,
	linux-kernel, thierry.reding, linux-pwm, jic23, knaack.h, lars,
	pmeerw, linux-iio, linux-arm-kernel
  Cc: fabrice.gasnier, gerald.baeza, arnaud.pouliquen, linus.walleij,
	linaro-kernel, Benjamin Gaignard

Hi Benjamin,

On 11/22/2016 05:13 PM, Benjamin Gaignard wrote:
> Add timers MFD and childs into DT for stm32f4.
> Define and enable pwm1 and pwm3 for stm32f469 discovery board
>
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>

If you have to send a v2 for this series please change commit header by: 
"ARM: dts: stm32: ..." (if not I will do it by myself)

> ---
>  arch/arm/boot/dts/stm32f429.dtsi      | 246 ++++++++++++++++++++++++++++++++++
>  arch/arm/boot/dts/stm32f469-disco.dts |  29 ++++
>  2 files changed, 275 insertions(+)
>
> diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
> index bca491d..28a0fe9 100644
> --- a/arch/arm/boot/dts/stm32f429.dtsi
> +++ b/arch/arm/boot/dts/stm32f429.dtsi
> @@ -355,6 +355,21 @@
>  					slew-rate = <2>;
>  				};
>  			};
> +
> +			pwm1_pins: pwm@1 {
> +				pins {
> +					pinmux = <STM32F429_PA8_FUNC_TIM1_CH1>,
> +						 <STM32F429_PB13_FUNC_TIM1_CH1N>,
> +						 <STM32F429_PB12_FUNC_TIM1_BKIN>;
> +				};
> +			};
> +
> +			pwm3_pins: pwm@3 {
> +				pins {
> +					pinmux = <STM32F429_PB4_FUNC_TIM3_CH1>,
> +						 <STM32F429_PB5_FUNC_TIM3_CH2>;
> +				};
> +			};
>  		};
>
>  		rcc: rcc@40023810 {
> @@ -426,6 +441,237 @@
>  			interrupts = <80>;
>  			clocks = <&rcc 0 38>;
>  		};
> +
> +		mfd_timer1: mfdtimer1@40010000 {
> +			compatible = "st,stm32-mfd-timer1";
> +			reg = <0x40010000 0x400>;
> +			clocks = <&rcc 0 160>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <27>;
> +			status = "disabled";
> +
> +			pwm1: pwm1@40010000 {
> +				compatible = "st,stm32-pwm1";
> +				status = "disabled";
> +			};
> +
> +			iiotimer1: iiotimer1@40010000 {
> +				compatible = "st,stm32-iio-timer1";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer2: mfdtimer2@40000000 {
> +			compatible = "st,stm32-mfd-timer2";
> +			reg = <0x40000000 0x400>;
> +			clocks = <&rcc 0 128>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <28>;
> +			status = "disabled";
> +
> +			pwm2: pwm2@40000000 {
> +				compatible = "st,stm32-pwm2";
> +				status = "disabled";
> +			};
> +			iiotimer2: iiotimer2@40000000 {
> +				compatible = "st,stm32-iio-timer2";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer3: mfdtimer3@40000400 {
> +			compatible = "st,stm32-mfd-timer3";
> +			reg = <0x40000400 0x400>;
> +			clocks = <&rcc 0 129>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <29>;
> +			status = "disabled";
> +
> +			pwm3: pwm3@40000400 {
> +				compatible = "st,stm32-pwm3";
> +				status = "disabled";
> +			};
> +			iiotimer3: iiotimer3@40000400 {
> +				compatible = "st,stm32-iio-timer3";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer4: mfdtimer4@40000800 {
> +			compatible = "st,stm32-mfd-timer4";
> +			reg = <0x40000800 0x400>;
> +			clocks = <&rcc 0 130>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <30>;
> +			status = "disabled";
> +
> +			pwm4: pwm4@40000800 {
> +				compatible = "st,stm32-pwm4";
> +				status = "disabled";
> +			};
> +			iiotimer4: iiotimer4@40000800 {
> +				compatible = "st,stm32-iio-timer4";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer5: mfdtimer5@40000C00 {
> +			compatible = "st,stm32-mfd-timer5";
> +			reg = <0x40000C00 0x400>;
> +			clocks = <&rcc 0 131>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <50>;
> +			status = "disabled";
> +
> +			pwm5: pwm5@40000C00 {
> +				compatible = "st,stm32-pwm5";
> +				status = "disabled";
> +			};
> +			iiotimer5: iiotimer5@40000800 {
> +				compatible = "st,stm32-iio-timer5";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer6: mfdtimer6@40001000 {
> +			compatible = "st,stm32-mfd-timer6";
> +			reg = <0x40001000 0x400>;
> +			clocks = <&rcc 0 132>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <54>;
> +			status = "disabled";
> +
> +			iiotimer6: iiotimer6@40001000 {
> +				compatible = "st,stm32-iio-timer6";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer7: mfdtimer7@40001400 {
> +			compatible = "st,stm32-mfd-timer7";
> +			reg = <0x40001400 0x400>;
> +			clocks = <&rcc 0 133>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <55>;
> +			status = "disabled";
> +
> +			iiotimer7: iiotimer7@40001400 {
> +				compatible = "st,stm32-iio-timer7";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer8: mfdtimer8@40010400 {
> +			compatible = "st,stm32-mfd-timer8";
> +			reg = <0x40010400 0x400>;
> +			clocks = <&rcc 0 161>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <46>;
> +			status = "disabled";
> +
> +			pwm8: pwm8@40010400 {
> +				compatible = "st,stm32-pwm8";
> +				status = "disabled";
> +			};
> +
> +			iiotimer8: iiotimer7@40010400 {
> +				compatible = "st,stm32-iio-timer8";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer9: mfdtimer9@40014000 {
> +			compatible = "st,stm32-mfd-timer9";
> +			reg = <0x40014000 0x400>;
> +			clocks = <&rcc 0 176>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <24>;
> +			status = "disabled";
> +
> +			pwm9: pwm9@40014000 {
> +				compatible = "st,stm32-pwm9";
> +				status = "disabled";
> +			};
> +
> +			iiotimer9: iiotimer9@40014000 {
> +				compatible = "st,stm32-iio-timer9";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer10: mfdtimer10@40014400 {
> +			compatible = "st,stm32-mfd-timer10";
> +			reg = <0x40014400 0x400>;
> +			clocks = <&rcc 0 177>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <25>;
> +			status = "disabled";
> +
> +			pwm10: pwm10@40014400 {
> +				compatible = "st,stm32-pwm10";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer11: mfdtimer11@40014800 {
> +			compatible = "st,stm32-mfd-timer11";
> +			reg = <0x40014800 0x400>;
> +			clocks = <&rcc 0 178>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <26>;
> +			status = "disabled";
> +
> +			pwm11: pwm11@40014800 {
> +				compatible = "st,stm32-pwm11";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer12: mfdtimer12@40001800 {
> +			compatible = "st,stm32-mfd-timer12";
> +			reg = <0x40001800 0x400>;
> +			clocks = <&rcc 0 134>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <43>;
> +			status = "disabled";
> +
> +			pwm12: pwm12@40001800 {
> +				compatible = "st,stm32-pwm12";
> +				status = "disabled";
> +			};
> +			iiotimer12: iiotimer12@40001800 {
> +				compatible = "st,stm32-iio-timer12";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer13: mfdtimer13@40001C00 {
> +			compatible = "st,stm32-mfd-timer13";
> +			reg = <0x40001C00 0x400>;
> +			clocks = <&rcc 0 135>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <44>;
> +			status = "disabled";
> +
> +			pwm13: pwm13@40001C00 {
> +				compatible = "st,stm32-pwm13";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer14: mfdtimer14@40002000 {
> +			compatible = "st,stm32-mfd-timer14";
> +			reg = <0x40002000 0x400>;
> +			clocks = <&rcc 0 136>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <45>;
> +			status = "disabled";
> +
> +			pwm14: pwm14@40002000 {
> +				compatible = "st,stm32-pwm14";
> +				status = "disabled";
> +			};
> +		};
>  	};
>  };
>
> diff --git a/arch/arm/boot/dts/stm32f469-disco.dts b/arch/arm/boot/dts/stm32f469-disco.dts
> index 8a163d7..a8f1788 100644
> --- a/arch/arm/boot/dts/stm32f469-disco.dts
> +++ b/arch/arm/boot/dts/stm32f469-disco.dts
> @@ -81,3 +81,32 @@
>  &usart3 {
>  	status = "okay";
>  };
> +
> +&mfd_timer1 {
> +	status = "okay";
> +};
> +
> +&pwm1 {
> +	pinctrl-0	= <&pwm1_pins>;
> +	pinctrl-names	= "default";
> +	st,breakinput-polarity = <0>;
> +	status = "okay";
> +};
> +
> +&iiotimer1 {
> +	status = "okay";
> +};
> +
> +&mfd_timer3 {
> +	status = "okay";
> +};
> +
> +&pwm3 {
> +	pinctrl-0	= <&pwm3_pins>;
> +	pinctrl-names	= "default";
> +	status = "okay";
> +};
> +
> +&iiotimer3 {
> +	status = "okay";
> +};
>

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 7/7] add stm32 multi-functions timer driver in DT
@ 2016-11-22 17:00     ` Alexandre Torgue
  0 siblings, 0 replies; 64+ messages in thread
From: Alexandre Torgue @ 2016-11-22 17:00 UTC (permalink / raw)
  To: Benjamin Gaignard, lee.jones, robh+dt, mark.rutland, devicetree,
	linux-kernel, thierry.reding, linux-pwm, jic23, knaack.h, lars,
	pmeerw, linux-iio, linux-arm-kernel
  Cc: linaro-kernel, Benjamin Gaignard, linus.walleij,
	arnaud.pouliquen, gerald.baeza, fabrice.gasnier

Hi Benjamin,

On 11/22/2016 05:13 PM, Benjamin Gaignard wrote:
> Add timers MFD and childs into DT for stm32f4.
> Define and enable pwm1 and pwm3 for stm32f469 discovery board
>
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>

If you have to send a v2 for this series please change commit header by: 
"ARM: dts: stm32: ..." (if not I will do it by myself)

> ---
>  arch/arm/boot/dts/stm32f429.dtsi      | 246 ++++++++++++++++++++++++++++++++++
>  arch/arm/boot/dts/stm32f469-disco.dts |  29 ++++
>  2 files changed, 275 insertions(+)
>
> diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
> index bca491d..28a0fe9 100644
> --- a/arch/arm/boot/dts/stm32f429.dtsi
> +++ b/arch/arm/boot/dts/stm32f429.dtsi
> @@ -355,6 +355,21 @@
>  					slew-rate = <2>;
>  				};
>  			};
> +
> +			pwm1_pins: pwm@1 {
> +				pins {
> +					pinmux = <STM32F429_PA8_FUNC_TIM1_CH1>,
> +						 <STM32F429_PB13_FUNC_TIM1_CH1N>,
> +						 <STM32F429_PB12_FUNC_TIM1_BKIN>;
> +				};
> +			};
> +
> +			pwm3_pins: pwm@3 {
> +				pins {
> +					pinmux = <STM32F429_PB4_FUNC_TIM3_CH1>,
> +						 <STM32F429_PB5_FUNC_TIM3_CH2>;
> +				};
> +			};
>  		};
>
>  		rcc: rcc@40023810 {
> @@ -426,6 +441,237 @@
>  			interrupts = <80>;
>  			clocks = <&rcc 0 38>;
>  		};
> +
> +		mfd_timer1: mfdtimer1@40010000 {
> +			compatible = "st,stm32-mfd-timer1";
> +			reg = <0x40010000 0x400>;
> +			clocks = <&rcc 0 160>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <27>;
> +			status = "disabled";
> +
> +			pwm1: pwm1@40010000 {
> +				compatible = "st,stm32-pwm1";
> +				status = "disabled";
> +			};
> +
> +			iiotimer1: iiotimer1@40010000 {
> +				compatible = "st,stm32-iio-timer1";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer2: mfdtimer2@40000000 {
> +			compatible = "st,stm32-mfd-timer2";
> +			reg = <0x40000000 0x400>;
> +			clocks = <&rcc 0 128>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <28>;
> +			status = "disabled";
> +
> +			pwm2: pwm2@40000000 {
> +				compatible = "st,stm32-pwm2";
> +				status = "disabled";
> +			};
> +			iiotimer2: iiotimer2@40000000 {
> +				compatible = "st,stm32-iio-timer2";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer3: mfdtimer3@40000400 {
> +			compatible = "st,stm32-mfd-timer3";
> +			reg = <0x40000400 0x400>;
> +			clocks = <&rcc 0 129>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <29>;
> +			status = "disabled";
> +
> +			pwm3: pwm3@40000400 {
> +				compatible = "st,stm32-pwm3";
> +				status = "disabled";
> +			};
> +			iiotimer3: iiotimer3@40000400 {
> +				compatible = "st,stm32-iio-timer3";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer4: mfdtimer4@40000800 {
> +			compatible = "st,stm32-mfd-timer4";
> +			reg = <0x40000800 0x400>;
> +			clocks = <&rcc 0 130>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <30>;
> +			status = "disabled";
> +
> +			pwm4: pwm4@40000800 {
> +				compatible = "st,stm32-pwm4";
> +				status = "disabled";
> +			};
> +			iiotimer4: iiotimer4@40000800 {
> +				compatible = "st,stm32-iio-timer4";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer5: mfdtimer5@40000C00 {
> +			compatible = "st,stm32-mfd-timer5";
> +			reg = <0x40000C00 0x400>;
> +			clocks = <&rcc 0 131>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <50>;
> +			status = "disabled";
> +
> +			pwm5: pwm5@40000C00 {
> +				compatible = "st,stm32-pwm5";
> +				status = "disabled";
> +			};
> +			iiotimer5: iiotimer5@40000800 {
> +				compatible = "st,stm32-iio-timer5";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer6: mfdtimer6@40001000 {
> +			compatible = "st,stm32-mfd-timer6";
> +			reg = <0x40001000 0x400>;
> +			clocks = <&rcc 0 132>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <54>;
> +			status = "disabled";
> +
> +			iiotimer6: iiotimer6@40001000 {
> +				compatible = "st,stm32-iio-timer6";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer7: mfdtimer7@40001400 {
> +			compatible = "st,stm32-mfd-timer7";
> +			reg = <0x40001400 0x400>;
> +			clocks = <&rcc 0 133>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <55>;
> +			status = "disabled";
> +
> +			iiotimer7: iiotimer7@40001400 {
> +				compatible = "st,stm32-iio-timer7";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer8: mfdtimer8@40010400 {
> +			compatible = "st,stm32-mfd-timer8";
> +			reg = <0x40010400 0x400>;
> +			clocks = <&rcc 0 161>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <46>;
> +			status = "disabled";
> +
> +			pwm8: pwm8@40010400 {
> +				compatible = "st,stm32-pwm8";
> +				status = "disabled";
> +			};
> +
> +			iiotimer8: iiotimer7@40010400 {
> +				compatible = "st,stm32-iio-timer8";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer9: mfdtimer9@40014000 {
> +			compatible = "st,stm32-mfd-timer9";
> +			reg = <0x40014000 0x400>;
> +			clocks = <&rcc 0 176>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <24>;
> +			status = "disabled";
> +
> +			pwm9: pwm9@40014000 {
> +				compatible = "st,stm32-pwm9";
> +				status = "disabled";
> +			};
> +
> +			iiotimer9: iiotimer9@40014000 {
> +				compatible = "st,stm32-iio-timer9";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer10: mfdtimer10@40014400 {
> +			compatible = "st,stm32-mfd-timer10";
> +			reg = <0x40014400 0x400>;
> +			clocks = <&rcc 0 177>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <25>;
> +			status = "disabled";
> +
> +			pwm10: pwm10@40014400 {
> +				compatible = "st,stm32-pwm10";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer11: mfdtimer11@40014800 {
> +			compatible = "st,stm32-mfd-timer11";
> +			reg = <0x40014800 0x400>;
> +			clocks = <&rcc 0 178>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <26>;
> +			status = "disabled";
> +
> +			pwm11: pwm11@40014800 {
> +				compatible = "st,stm32-pwm11";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer12: mfdtimer12@40001800 {
> +			compatible = "st,stm32-mfd-timer12";
> +			reg = <0x40001800 0x400>;
> +			clocks = <&rcc 0 134>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <43>;
> +			status = "disabled";
> +
> +			pwm12: pwm12@40001800 {
> +				compatible = "st,stm32-pwm12";
> +				status = "disabled";
> +			};
> +			iiotimer12: iiotimer12@40001800 {
> +				compatible = "st,stm32-iio-timer12";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer13: mfdtimer13@40001C00 {
> +			compatible = "st,stm32-mfd-timer13";
> +			reg = <0x40001C00 0x400>;
> +			clocks = <&rcc 0 135>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <44>;
> +			status = "disabled";
> +
> +			pwm13: pwm13@40001C00 {
> +				compatible = "st,stm32-pwm13";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer14: mfdtimer14@40002000 {
> +			compatible = "st,stm32-mfd-timer14";
> +			reg = <0x40002000 0x400>;
> +			clocks = <&rcc 0 136>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <45>;
> +			status = "disabled";
> +
> +			pwm14: pwm14@40002000 {
> +				compatible = "st,stm32-pwm14";
> +				status = "disabled";
> +			};
> +		};
>  	};
>  };
>
> diff --git a/arch/arm/boot/dts/stm32f469-disco.dts b/arch/arm/boot/dts/stm32f469-disco.dts
> index 8a163d7..a8f1788 100644
> --- a/arch/arm/boot/dts/stm32f469-disco.dts
> +++ b/arch/arm/boot/dts/stm32f469-disco.dts
> @@ -81,3 +81,32 @@
>  &usart3 {
>  	status = "okay";
>  };
> +
> +&mfd_timer1 {
> +	status = "okay";
> +};
> +
> +&pwm1 {
> +	pinctrl-0	= <&pwm1_pins>;
> +	pinctrl-names	= "default";
> +	st,breakinput-polarity = <0>;
> +	status = "okay";
> +};
> +
> +&iiotimer1 {
> +	status = "okay";
> +};
> +
> +&mfd_timer3 {
> +	status = "okay";
> +};
> +
> +&pwm3 {
> +	pinctrl-0	= <&pwm3_pins>;
> +	pinctrl-names	= "default";
> +	status = "okay";
> +};
> +
> +&iiotimer3 {
> +	status = "okay";
> +};
>

^ permalink raw reply	[flat|nested] 64+ messages in thread

* [PATCH 7/7] add stm32 multi-functions timer driver in DT
@ 2016-11-22 17:00     ` Alexandre Torgue
  0 siblings, 0 replies; 64+ messages in thread
From: Alexandre Torgue @ 2016-11-22 17:00 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Benjamin,

On 11/22/2016 05:13 PM, Benjamin Gaignard wrote:
> Add timers MFD and childs into DT for stm32f4.
> Define and enable pwm1 and pwm3 for stm32f469 discovery board
>
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>

If you have to send a v2 for this series please change commit header by: 
"ARM: dts: stm32: ..." (if not I will do it by myself)

> ---
>  arch/arm/boot/dts/stm32f429.dtsi      | 246 ++++++++++++++++++++++++++++++++++
>  arch/arm/boot/dts/stm32f469-disco.dts |  29 ++++
>  2 files changed, 275 insertions(+)
>
> diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
> index bca491d..28a0fe9 100644
> --- a/arch/arm/boot/dts/stm32f429.dtsi
> +++ b/arch/arm/boot/dts/stm32f429.dtsi
> @@ -355,6 +355,21 @@
>  					slew-rate = <2>;
>  				};
>  			};
> +
> +			pwm1_pins: pwm at 1 {
> +				pins {
> +					pinmux = <STM32F429_PA8_FUNC_TIM1_CH1>,
> +						 <STM32F429_PB13_FUNC_TIM1_CH1N>,
> +						 <STM32F429_PB12_FUNC_TIM1_BKIN>;
> +				};
> +			};
> +
> +			pwm3_pins: pwm at 3 {
> +				pins {
> +					pinmux = <STM32F429_PB4_FUNC_TIM3_CH1>,
> +						 <STM32F429_PB5_FUNC_TIM3_CH2>;
> +				};
> +			};
>  		};
>
>  		rcc: rcc at 40023810 {
> @@ -426,6 +441,237 @@
>  			interrupts = <80>;
>  			clocks = <&rcc 0 38>;
>  		};
> +
> +		mfd_timer1: mfdtimer1 at 40010000 {
> +			compatible = "st,stm32-mfd-timer1";
> +			reg = <0x40010000 0x400>;
> +			clocks = <&rcc 0 160>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <27>;
> +			status = "disabled";
> +
> +			pwm1: pwm1 at 40010000 {
> +				compatible = "st,stm32-pwm1";
> +				status = "disabled";
> +			};
> +
> +			iiotimer1: iiotimer1 at 40010000 {
> +				compatible = "st,stm32-iio-timer1";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer2: mfdtimer2 at 40000000 {
> +			compatible = "st,stm32-mfd-timer2";
> +			reg = <0x40000000 0x400>;
> +			clocks = <&rcc 0 128>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <28>;
> +			status = "disabled";
> +
> +			pwm2: pwm2 at 40000000 {
> +				compatible = "st,stm32-pwm2";
> +				status = "disabled";
> +			};
> +			iiotimer2: iiotimer2 at 40000000 {
> +				compatible = "st,stm32-iio-timer2";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer3: mfdtimer3 at 40000400 {
> +			compatible = "st,stm32-mfd-timer3";
> +			reg = <0x40000400 0x400>;
> +			clocks = <&rcc 0 129>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <29>;
> +			status = "disabled";
> +
> +			pwm3: pwm3 at 40000400 {
> +				compatible = "st,stm32-pwm3";
> +				status = "disabled";
> +			};
> +			iiotimer3: iiotimer3 at 40000400 {
> +				compatible = "st,stm32-iio-timer3";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer4: mfdtimer4 at 40000800 {
> +			compatible = "st,stm32-mfd-timer4";
> +			reg = <0x40000800 0x400>;
> +			clocks = <&rcc 0 130>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <30>;
> +			status = "disabled";
> +
> +			pwm4: pwm4 at 40000800 {
> +				compatible = "st,stm32-pwm4";
> +				status = "disabled";
> +			};
> +			iiotimer4: iiotimer4 at 40000800 {
> +				compatible = "st,stm32-iio-timer4";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer5: mfdtimer5 at 40000C00 {
> +			compatible = "st,stm32-mfd-timer5";
> +			reg = <0x40000C00 0x400>;
> +			clocks = <&rcc 0 131>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <50>;
> +			status = "disabled";
> +
> +			pwm5: pwm5 at 40000C00 {
> +				compatible = "st,stm32-pwm5";
> +				status = "disabled";
> +			};
> +			iiotimer5: iiotimer5 at 40000800 {
> +				compatible = "st,stm32-iio-timer5";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer6: mfdtimer6 at 40001000 {
> +			compatible = "st,stm32-mfd-timer6";
> +			reg = <0x40001000 0x400>;
> +			clocks = <&rcc 0 132>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <54>;
> +			status = "disabled";
> +
> +			iiotimer6: iiotimer6 at 40001000 {
> +				compatible = "st,stm32-iio-timer6";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer7: mfdtimer7 at 40001400 {
> +			compatible = "st,stm32-mfd-timer7";
> +			reg = <0x40001400 0x400>;
> +			clocks = <&rcc 0 133>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <55>;
> +			status = "disabled";
> +
> +			iiotimer7: iiotimer7 at 40001400 {
> +				compatible = "st,stm32-iio-timer7";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer8: mfdtimer8 at 40010400 {
> +			compatible = "st,stm32-mfd-timer8";
> +			reg = <0x40010400 0x400>;
> +			clocks = <&rcc 0 161>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <46>;
> +			status = "disabled";
> +
> +			pwm8: pwm8 at 40010400 {
> +				compatible = "st,stm32-pwm8";
> +				status = "disabled";
> +			};
> +
> +			iiotimer8: iiotimer7 at 40010400 {
> +				compatible = "st,stm32-iio-timer8";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer9: mfdtimer9 at 40014000 {
> +			compatible = "st,stm32-mfd-timer9";
> +			reg = <0x40014000 0x400>;
> +			clocks = <&rcc 0 176>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <24>;
> +			status = "disabled";
> +
> +			pwm9: pwm9 at 40014000 {
> +				compatible = "st,stm32-pwm9";
> +				status = "disabled";
> +			};
> +
> +			iiotimer9: iiotimer9 at 40014000 {
> +				compatible = "st,stm32-iio-timer9";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer10: mfdtimer10 at 40014400 {
> +			compatible = "st,stm32-mfd-timer10";
> +			reg = <0x40014400 0x400>;
> +			clocks = <&rcc 0 177>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <25>;
> +			status = "disabled";
> +
> +			pwm10: pwm10 at 40014400 {
> +				compatible = "st,stm32-pwm10";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer11: mfdtimer11 at 40014800 {
> +			compatible = "st,stm32-mfd-timer11";
> +			reg = <0x40014800 0x400>;
> +			clocks = <&rcc 0 178>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <26>;
> +			status = "disabled";
> +
> +			pwm11: pwm11 at 40014800 {
> +				compatible = "st,stm32-pwm11";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer12: mfdtimer12 at 40001800 {
> +			compatible = "st,stm32-mfd-timer12";
> +			reg = <0x40001800 0x400>;
> +			clocks = <&rcc 0 134>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <43>;
> +			status = "disabled";
> +
> +			pwm12: pwm12 at 40001800 {
> +				compatible = "st,stm32-pwm12";
> +				status = "disabled";
> +			};
> +			iiotimer12: iiotimer12 at 40001800 {
> +				compatible = "st,stm32-iio-timer12";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer13: mfdtimer13 at 40001C00 {
> +			compatible = "st,stm32-mfd-timer13";
> +			reg = <0x40001C00 0x400>;
> +			clocks = <&rcc 0 135>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <44>;
> +			status = "disabled";
> +
> +			pwm13: pwm13 at 40001C00 {
> +				compatible = "st,stm32-pwm13";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer14: mfdtimer14 at 40002000 {
> +			compatible = "st,stm32-mfd-timer14";
> +			reg = <0x40002000 0x400>;
> +			clocks = <&rcc 0 136>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <45>;
> +			status = "disabled";
> +
> +			pwm14: pwm14 at 40002000 {
> +				compatible = "st,stm32-pwm14";
> +				status = "disabled";
> +			};
> +		};
>  	};
>  };
>
> diff --git a/arch/arm/boot/dts/stm32f469-disco.dts b/arch/arm/boot/dts/stm32f469-disco.dts
> index 8a163d7..a8f1788 100644
> --- a/arch/arm/boot/dts/stm32f469-disco.dts
> +++ b/arch/arm/boot/dts/stm32f469-disco.dts
> @@ -81,3 +81,32 @@
>  &usart3 {
>  	status = "okay";
>  };
> +
> +&mfd_timer1 {
> +	status = "okay";
> +};
> +
> +&pwm1 {
> +	pinctrl-0	= <&pwm1_pins>;
> +	pinctrl-names	= "default";
> +	st,breakinput-polarity = <0>;
> +	status = "okay";
> +};
> +
> +&iiotimer1 {
> +	status = "okay";
> +};
> +
> +&mfd_timer3 {
> +	status = "okay";
> +};
> +
> +&pwm3 {
> +	pinctrl-0	= <&pwm3_pins>;
> +	pinctrl-names	= "default";
> +	status = "okay";
> +};
> +
> +&iiotimer3 {
> +	status = "okay";
> +};
>

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 5/7] add bindings for stm32 IIO timer drivers
  2016-11-22 16:53     ` Lars-Peter Clausen
@ 2016-11-22 17:01       ` Benjamin Gaignard
  -1 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-22 17:01 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Lee Jones, robh+dt, Mark Rutland, alexandre.torgue, devicetree,
	Linux Kernel Mailing List, Thierry Reding, linux-pwm, jic23,
	knaack.h, Peter Meerwald-Stadler, linux-iio, linux-arm-kernel,
	Fabrice Gasnier, Gerald Baeza, Arnaud Pouliquen, Linus Walleij,
	Linaro Kernel Mailman List, Benjamin Gaignard

[snip]
>> +     "st,stm32-iio-timer5"
>> +     "st,stm32-iio-timer6"
>> +     "st,stm32-iio-timer7"
>> +     "st,stm32-iio-timer8"
>> +     "st,stm32-iio-timer9"
>> +     "st,stm32-iio-timer10"
>> +     "st,stm32-iio-timer11"
>> +     "st,stm32-iio-timer12"
>> +     "st,stm32-iio-timer13"
>> +     "st,stm32-iio-timer14"
>
> We can't do this. This is a binding for a driver, not for the hardware.
>

Unfortunately each instance for the hardware IP have little
differences like which triggers they could accept or size of the
counter register,
and I doesn't have value inside the hardware to distinguish them so
the only way I found is to use compatible.

^ permalink raw reply	[flat|nested] 64+ messages in thread

* [PATCH 5/7] add bindings for stm32 IIO timer drivers
@ 2016-11-22 17:01       ` Benjamin Gaignard
  0 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-22 17:01 UTC (permalink / raw)
  To: linux-arm-kernel

[snip]
>> +     "st,stm32-iio-timer5"
>> +     "st,stm32-iio-timer6"
>> +     "st,stm32-iio-timer7"
>> +     "st,stm32-iio-timer8"
>> +     "st,stm32-iio-timer9"
>> +     "st,stm32-iio-timer10"
>> +     "st,stm32-iio-timer11"
>> +     "st,stm32-iio-timer12"
>> +     "st,stm32-iio-timer13"
>> +     "st,stm32-iio-timer14"
>
> We can't do this. This is a binding for a driver, not for the hardware.
>

Unfortunately each instance for the hardware IP have little
differences like which triggers they could accept or size of the
counter register,
and I doesn't have value inside the hardware to distinguish them so
the only way I found is to use compatible.

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 5/7] add bindings for stm32 IIO timer drivers
  2016-11-22 17:01       ` Benjamin Gaignard
  (?)
@ 2016-11-22 17:02         ` Lars-Peter Clausen
  -1 siblings, 0 replies; 64+ messages in thread
From: Lars-Peter Clausen @ 2016-11-22 17:02 UTC (permalink / raw)
  To: Benjamin Gaignard
  Cc: Lee Jones, robh+dt, Mark Rutland, alexandre.torgue, devicetree,
	Linux Kernel Mailing List, Thierry Reding, linux-pwm, jic23,
	knaack.h, Peter Meerwald-Stadler, linux-iio, linux-arm-kernel,
	Fabrice Gasnier, Gerald Baeza, Arnaud Pouliquen, Linus Walleij,
	Linaro Kernel Mailman List, Benjamin Gaignard

On 11/22/2016 06:01 PM, Benjamin Gaignard wrote:
> [snip]
>>> +     "st,stm32-iio-timer5"
>>> +     "st,stm32-iio-timer6"
>>> +     "st,stm32-iio-timer7"
>>> +     "st,stm32-iio-timer8"
>>> +     "st,stm32-iio-timer9"
>>> +     "st,stm32-iio-timer10"
>>> +     "st,stm32-iio-timer11"
>>> +     "st,stm32-iio-timer12"
>>> +     "st,stm32-iio-timer13"
>>> +     "st,stm32-iio-timer14"
>>
>> We can't do this. This is a binding for a driver, not for the hardware.
>>
> 
> Unfortunately each instance for the hardware IP have little
> differences like which triggers they could accept or size of the
> counter register,
> and I doesn't have value inside the hardware to distinguish them so
> the only way I found is to use compatible.

But IIO is not a piece of hardware, its a software framework in the Linux
kernel.

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 5/7] add bindings for stm32 IIO timer drivers
@ 2016-11-22 17:02         ` Lars-Peter Clausen
  0 siblings, 0 replies; 64+ messages in thread
From: Lars-Peter Clausen @ 2016-11-22 17:02 UTC (permalink / raw)
  To: Benjamin Gaignard
  Cc: Mark Rutland, devicetree, Linaro Kernel Mailman List,
	alexandre.torgue, linux-pwm, linux-iio, Linus Walleij,
	Arnaud Pouliquen, Linux Kernel Mailing List, robh+dt,
	Thierry Reding, linux-arm-kernel, Peter Meerwald-Stadler,
	knaack.h, Gerald Baeza, Fabrice Gasnier, Lee Jones, jic23,
	Benjamin Gaignard

On 11/22/2016 06:01 PM, Benjamin Gaignard wrote:
> [snip]
>>> +     "st,stm32-iio-timer5"
>>> +     "st,stm32-iio-timer6"
>>> +     "st,stm32-iio-timer7"
>>> +     "st,stm32-iio-timer8"
>>> +     "st,stm32-iio-timer9"
>>> +     "st,stm32-iio-timer10"
>>> +     "st,stm32-iio-timer11"
>>> +     "st,stm32-iio-timer12"
>>> +     "st,stm32-iio-timer13"
>>> +     "st,stm32-iio-timer14"
>>
>> We can't do this. This is a binding for a driver, not for the hardware.
>>
> 
> Unfortunately each instance for the hardware IP have little
> differences like which triggers they could accept or size of the
> counter register,
> and I doesn't have value inside the hardware to distinguish them so
> the only way I found is to use compatible.

But IIO is not a piece of hardware, its a software framework in the Linux
kernel.

^ permalink raw reply	[flat|nested] 64+ messages in thread

* [PATCH 5/7] add bindings for stm32 IIO timer drivers
@ 2016-11-22 17:02         ` Lars-Peter Clausen
  0 siblings, 0 replies; 64+ messages in thread
From: Lars-Peter Clausen @ 2016-11-22 17:02 UTC (permalink / raw)
  To: linux-arm-kernel

On 11/22/2016 06:01 PM, Benjamin Gaignard wrote:
> [snip]
>>> +     "st,stm32-iio-timer5"
>>> +     "st,stm32-iio-timer6"
>>> +     "st,stm32-iio-timer7"
>>> +     "st,stm32-iio-timer8"
>>> +     "st,stm32-iio-timer9"
>>> +     "st,stm32-iio-timer10"
>>> +     "st,stm32-iio-timer11"
>>> +     "st,stm32-iio-timer12"
>>> +     "st,stm32-iio-timer13"
>>> +     "st,stm32-iio-timer14"
>>
>> We can't do this. This is a binding for a driver, not for the hardware.
>>
> 
> Unfortunately each instance for the hardware IP have little
> differences like which triggers they could accept or size of the
> counter register,
> and I doesn't have value inside the hardware to distinguish them so
> the only way I found is to use compatible.

But IIO is not a piece of hardware, its a software framework in the Linux
kernel.

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 5/7] add bindings for stm32 IIO timer drivers
@ 2016-11-22 17:18         ` Lee Jones
  0 siblings, 0 replies; 64+ messages in thread
From: Lee Jones @ 2016-11-22 17:18 UTC (permalink / raw)
  To: Benjamin Gaignard
  Cc: Lars-Peter Clausen, robh+dt, Mark Rutland, alexandre.torgue,
	devicetree, Linux Kernel Mailing List, Thierry Reding, linux-pwm,
	jic23, knaack.h, Peter Meerwald-Stadler, linux-iio,
	linux-arm-kernel, Fabrice Gasnier, Gerald Baeza,
	Arnaud Pouliquen, Linus Walleij, Linaro Kernel Mailman List,
	Benjamin Gaignard

On Tue, 22 Nov 2016, Benjamin Gaignard wrote:

> [snip]
> >> +     "st,stm32-iio-timer5"
> >> +     "st,stm32-iio-timer6"
> >> +     "st,stm32-iio-timer7"
> >> +     "st,stm32-iio-timer8"
> >> +     "st,stm32-iio-timer9"
> >> +     "st,stm32-iio-timer10"
> >> +     "st,stm32-iio-timer11"
> >> +     "st,stm32-iio-timer12"
> >> +     "st,stm32-iio-timer13"
> >> +     "st,stm32-iio-timer14"
> >
> > We can't do this. This is a binding for a driver, not for the hardware.
> >
> 
> Unfortunately each instance for the hardware IP have little
> differences like which triggers they could accept or size of the
> counter register,
> and I doesn't have value inside the hardware to distinguish them so
> the only way I found is to use compatible.

Can't you represent these as properties?

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 5/7] add bindings for stm32 IIO timer drivers
@ 2016-11-22 17:18         ` Lee Jones
  0 siblings, 0 replies; 64+ messages in thread
From: Lee Jones @ 2016-11-22 17:18 UTC (permalink / raw)
  To: Benjamin Gaignard
  Cc: Lars-Peter Clausen, robh+dt-DgEjT+Ai2ygdnm+yROfE0A, Mark Rutland,
	alexandre.torgue-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA,
	Linux Kernel Mailing List, Thierry Reding,
	linux-pwm-u79uwXL29TY76Z2rM5mHXA, jic23-DgEjT+Ai2ygdnm+yROfE0A,
	knaack.h-Mmb7MZpHnFY, Peter Meerwald-Stadler,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Fabrice Gasnier, Gerald Baeza, Arnaud Pouliquen, Linus Walleij,
	Linaro Kernel Mailman List, Benjamin Gaignard

On Tue, 22 Nov 2016, Benjamin Gaignard wrote:

> [snip]
> >> +     "st,stm32-iio-timer5"
> >> +     "st,stm32-iio-timer6"
> >> +     "st,stm32-iio-timer7"
> >> +     "st,stm32-iio-timer8"
> >> +     "st,stm32-iio-timer9"
> >> +     "st,stm32-iio-timer10"
> >> +     "st,stm32-iio-timer11"
> >> +     "st,stm32-iio-timer12"
> >> +     "st,stm32-iio-timer13"
> >> +     "st,stm32-iio-timer14"
> >
> > We can't do this. This is a binding for a driver, not for the hardware.
> >
> 
> Unfortunately each instance for the hardware IP have little
> differences like which triggers they could accept or size of the
> counter register,
> and I doesn't have value inside the hardware to distinguish them so
> the only way I found is to use compatible.

Can't you represent these as properties?

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 64+ messages in thread

* [PATCH 5/7] add bindings for stm32 IIO timer drivers
@ 2016-11-22 17:18         ` Lee Jones
  0 siblings, 0 replies; 64+ messages in thread
From: Lee Jones @ 2016-11-22 17:18 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 22 Nov 2016, Benjamin Gaignard wrote:

> [snip]
> >> +     "st,stm32-iio-timer5"
> >> +     "st,stm32-iio-timer6"
> >> +     "st,stm32-iio-timer7"
> >> +     "st,stm32-iio-timer8"
> >> +     "st,stm32-iio-timer9"
> >> +     "st,stm32-iio-timer10"
> >> +     "st,stm32-iio-timer11"
> >> +     "st,stm32-iio-timer12"
> >> +     "st,stm32-iio-timer13"
> >> +     "st,stm32-iio-timer14"
> >
> > We can't do this. This is a binding for a driver, not for the hardware.
> >
> 
> Unfortunately each instance for the hardware IP have little
> differences like which triggers they could accept or size of the
> counter register,
> and I doesn't have value inside the hardware to distinguish them so
> the only way I found is to use compatible.

Can't you represent these as properties?

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 1/7] add binding for stm32 multifunctions timer driver
  2016-11-22 16:52     ` Lee Jones
@ 2016-11-23  8:15       ` Benjamin Gaignard
  -1 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-23  8:15 UTC (permalink / raw)
  To: Lee Jones
  Cc: robh+dt, Mark Rutland, alexandre.torgue, devicetree,
	Linux Kernel Mailing List, Thierry Reding, linux-pwm, jic23,
	knaack.h, Lars-Peter Clausen, Peter Meerwald-Stadler, linux-iio,
	linux-arm-kernel, Fabrice Gasnier, Gerald Baeza,
	Arnaud Pouliquen, Linus Walleij, Linaro Kernel Mailman List,
	Benjamin Gaignard

2016-11-22 17:52 GMT+01:00 Lee Jones <lee.jones@linaro.org>:
> On Tue, 22 Nov 2016, Benjamin Gaignard wrote:
>
>> Add bindings information for stm32 timer MFD
>>
>> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
>> ---
>>  .../devicetree/bindings/mfd/stm32-timer.txt        | 53 ++++++++++++++++++++++
>>  1 file changed, 53 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/mfd/stm32-timer.txt
>>
>> diff --git a/Documentation/devicetree/bindings/mfd/stm32-timer.txt b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
>> new file mode 100644
>> index 0000000..3cefce1
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
>> @@ -0,0 +1,53 @@
>> +STM32 multifunctions timer driver
>
> "STM32 Multi-Function Timer/PWM device bindings"
>
> Doesn't this shared device have a better name?

In SoC documentation those hardware blocks are named "advanced-control
timers", "general purpose timers" or "basic timers"
"stm32-timer" name is already used for clock source driver, that why I
have prefix it with mfd

>
>> +stm32 timer MFD allow to handle at the same time pwm and IIO timer devices
>
> No need for this sentence.
>
OK

>> +Required parameters:
>> +- compatible: must be one of the follow value:
>> +     "st,stm32-mfd-timer1"
>> +     "st,stm32-mfd-timer2"
>> +     "st,stm32-mfd-timer3"
>> +     "st,stm32-mfd-timer4"
>> +     "st,stm32-mfd-timer5"
>> +     "st,stm32-mfd-timer6"
>> +     "st,stm32-mfd-timer7"
>> +     "st,stm32-mfd-timer8"
>> +     "st,stm32-mfd-timer9"
>> +     "st,stm32-mfd-timer10"
>> +     "st,stm32-mfd-timer11"
>> +     "st,stm32-mfd-timer12"
>> +     "st,stm32-mfd-timer13"
>> +     "st,stm32-mfd-timer14"
>
> We don't normally number devices.
>
> What's stopping you from simply doing:
>
>         pwm1: pwm1@40010000 {
>                 compatible = "st,stm32-pwm";
>         };
>         pwm2: pwm1@40020000 {
>                 compatible = "st,stm32-pwm";
>         };
>         pwm3: pwm1@40030000 {
>                 compatible = "st,stm32-pwm";
>         };
>

Because each instance of the hardware is slightly different: number of
pwm channels, triggers capabilities, etc ..
so I need to distinguish them.
Since it look to be a problem I will follow your suggestion and add a
property this driver to be able to identify each instance.
Do you think that "id" parameter (integer for 1 to 14) is acceptable ?

>> +- reg :                      Physical base address and length of the controller's
>> +                     registers.
>> +- clock-names:               Set to "mfd_timer_clk".
>
Only one but I use devm_regmap_init_mmio_clk() to avoid calling
clk_{enable/disable}
everywhere in the drivers when reading/writing regsister.
devm_regmap_init_mmio_clk() find the clock by it name that why I have
put it here
In the doc this clock in named "clk_int" I will use this name.


> How many clocks are there?
>
> If only 1, you don't need this property.
>
> "mfd_timer_clk" is not the correct name.
>
> What is it called in the datasheet?
>
>> +- clocks:            Phandle of the clock used by the timer module.
>
> "Phandle to the clock ..."
>
>> +                     For Clk properties, please refer to [1].
>> +- interrupts :               Reference to the timer interrupt
>
> Reference to?
>
> See how other binding documents describe this property.
>
>> +Optional parameters:
>> +- resets :           Reference to a reset controller asserting the timer
>
> As above.
>
>> +Optional subnodes:
>
> Either use ":" or " :" or "<tab>:", but keep it consistent.
>
>> +- pwm:                       See Documentation/devicetree/bindings/pwm/pwm-stm32.txt
>> +- iiotimer:          See Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt
>> +
>> +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
>
> Use the relative paths "../clock/", "../pwm/", "../iio/".
>
OK

>> +Example:
>> +     mfd_timer1: mfdtimer1@40010000 {
>
> This is not an "MFD timer".  MFD is a Linuxisum.
>
>> +             compatible = "st,stm32-mfd-timer1";
>
> Better description required.
>
>> +             reg = <0x40010000 0x400>;
>> +             clocks = <&rcc 0 160>;
>> +             clock-names = "mfd_timer_clk";
>> +             interrupts = <27>;
>> +
>> +             pwm1: pwm1@40010000 {
>> +                     compatible = "st,stm32-pwm1";
>> +             };
>> +
>> +             iiotimer1: iiotimer1@40010000 {
>> +                     compatible = "st,stm32-iio-timer1";
>> +             };
>> +     };

^ permalink raw reply	[flat|nested] 64+ messages in thread

* [PATCH 1/7] add binding for stm32 multifunctions timer driver
@ 2016-11-23  8:15       ` Benjamin Gaignard
  0 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-23  8:15 UTC (permalink / raw)
  To: linux-arm-kernel

2016-11-22 17:52 GMT+01:00 Lee Jones <lee.jones@linaro.org>:
> On Tue, 22 Nov 2016, Benjamin Gaignard wrote:
>
>> Add bindings information for stm32 timer MFD
>>
>> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
>> ---
>>  .../devicetree/bindings/mfd/stm32-timer.txt        | 53 ++++++++++++++++++++++
>>  1 file changed, 53 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/mfd/stm32-timer.txt
>>
>> diff --git a/Documentation/devicetree/bindings/mfd/stm32-timer.txt b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
>> new file mode 100644
>> index 0000000..3cefce1
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
>> @@ -0,0 +1,53 @@
>> +STM32 multifunctions timer driver
>
> "STM32 Multi-Function Timer/PWM device bindings"
>
> Doesn't this shared device have a better name?

In SoC documentation those hardware blocks are named "advanced-control
timers", "general purpose timers" or "basic timers"
"stm32-timer" name is already used for clock source driver, that why I
have prefix it with mfd

>
>> +stm32 timer MFD allow to handle at the same time pwm and IIO timer devices
>
> No need for this sentence.
>
OK

>> +Required parameters:
>> +- compatible: must be one of the follow value:
>> +     "st,stm32-mfd-timer1"
>> +     "st,stm32-mfd-timer2"
>> +     "st,stm32-mfd-timer3"
>> +     "st,stm32-mfd-timer4"
>> +     "st,stm32-mfd-timer5"
>> +     "st,stm32-mfd-timer6"
>> +     "st,stm32-mfd-timer7"
>> +     "st,stm32-mfd-timer8"
>> +     "st,stm32-mfd-timer9"
>> +     "st,stm32-mfd-timer10"
>> +     "st,stm32-mfd-timer11"
>> +     "st,stm32-mfd-timer12"
>> +     "st,stm32-mfd-timer13"
>> +     "st,stm32-mfd-timer14"
>
> We don't normally number devices.
>
> What's stopping you from simply doing:
>
>         pwm1: pwm1 at 40010000 {
>                 compatible = "st,stm32-pwm";
>         };
>         pwm2: pwm1 at 40020000 {
>                 compatible = "st,stm32-pwm";
>         };
>         pwm3: pwm1 at 40030000 {
>                 compatible = "st,stm32-pwm";
>         };
>

Because each instance of the hardware is slightly different: number of
pwm channels, triggers capabilities, etc ..
so I need to distinguish them.
Since it look to be a problem I will follow your suggestion and add a
property this driver to be able to identify each instance.
Do you think that "id" parameter (integer for 1 to 14) is acceptable ?

>> +- reg :                      Physical base address and length of the controller's
>> +                     registers.
>> +- clock-names:               Set to "mfd_timer_clk".
>
Only one but I use devm_regmap_init_mmio_clk() to avoid calling
clk_{enable/disable}
everywhere in the drivers when reading/writing regsister.
devm_regmap_init_mmio_clk() find the clock by it name that why I have
put it here
In the doc this clock in named "clk_int" I will use this name.


> How many clocks are there?
>
> If only 1, you don't need this property.
>
> "mfd_timer_clk" is not the correct name.
>
> What is it called in the datasheet?
>
>> +- clocks:            Phandle of the clock used by the timer module.
>
> "Phandle to the clock ..."
>
>> +                     For Clk properties, please refer to [1].
>> +- interrupts :               Reference to the timer interrupt
>
> Reference to?
>
> See how other binding documents describe this property.
>
>> +Optional parameters:
>> +- resets :           Reference to a reset controller asserting the timer
>
> As above.
>
>> +Optional subnodes:
>
> Either use ":" or " :" or "<tab>:", but keep it consistent.
>
>> +- pwm:                       See Documentation/devicetree/bindings/pwm/pwm-stm32.txt
>> +- iiotimer:          See Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt
>> +
>> +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
>
> Use the relative paths "../clock/", "../pwm/", "../iio/".
>
OK

>> +Example:
>> +     mfd_timer1: mfdtimer1 at 40010000 {
>
> This is not an "MFD timer".  MFD is a Linuxisum.
>
>> +             compatible = "st,stm32-mfd-timer1";
>
> Better description required.
>
>> +             reg = <0x40010000 0x400>;
>> +             clocks = <&rcc 0 160>;
>> +             clock-names = "mfd_timer_clk";
>> +             interrupts = <27>;
>> +
>> +             pwm1: pwm1 at 40010000 {
>> +                     compatible = "st,stm32-pwm1";
>> +             };
>> +
>> +             iiotimer1: iiotimer1 at 40010000 {
>> +                     compatible = "st,stm32-iio-timer1";
>> +             };
>> +     };

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 5/7] add bindings for stm32 IIO timer drivers
@ 2016-11-23  8:17           ` Benjamin Gaignard
  0 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-23  8:17 UTC (permalink / raw)
  To: Lee Jones
  Cc: Lars-Peter Clausen, robh+dt, Mark Rutland, alexandre.torgue,
	devicetree, Linux Kernel Mailing List, Thierry Reding, linux-pwm,
	jic23, knaack.h, Peter Meerwald-Stadler, linux-iio,
	linux-arm-kernel, Fabrice Gasnier, Gerald Baeza,
	Arnaud Pouliquen, Linus Walleij, Linaro Kernel Mailman List,
	Benjamin Gaignard

If it is ok for you I will add "id" parameter in mfd driver and
forward it to the sub-devices drivers
to be able to distinguish the hardware blocks


2016-11-22 18:18 GMT+01:00 Lee Jones <lee.jones@linaro.org>:
> On Tue, 22 Nov 2016, Benjamin Gaignard wrote:
>
>> [snip]
>> >> +     "st,stm32-iio-timer5"
>> >> +     "st,stm32-iio-timer6"
>> >> +     "st,stm32-iio-timer7"
>> >> +     "st,stm32-iio-timer8"
>> >> +     "st,stm32-iio-timer9"
>> >> +     "st,stm32-iio-timer10"
>> >> +     "st,stm32-iio-timer11"
>> >> +     "st,stm32-iio-timer12"
>> >> +     "st,stm32-iio-timer13"
>> >> +     "st,stm32-iio-timer14"
>> >
>> > We can't do this. This is a binding for a driver, not for the hardware.
>> >
>>
>> Unfortunately each instance for the hardware IP have little
>> differences like which triggers they could accept or size of the
>> counter register,
>> and I doesn't have value inside the hardware to distinguish them so
>> the only way I found is to use compatible.
>
> Can't you represent these as properties?
>
> --
> Lee Jones
> Linaro STMicroelectronics Landing Team Lead
> Linaro.org │ Open source software for ARM SoCs
> Follow Linaro: Facebook | Twitter | Blog



-- 
Benjamin Gaignard

Graphic Study Group

Linaro.org │ Open source software for ARM SoCs

Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 5/7] add bindings for stm32 IIO timer drivers
@ 2016-11-23  8:17           ` Benjamin Gaignard
  0 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-23  8:17 UTC (permalink / raw)
  To: Lee Jones
  Cc: Lars-Peter Clausen, robh+dt-DgEjT+Ai2ygdnm+yROfE0A, Mark Rutland,
	alexandre.torgue-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA,
	Linux Kernel Mailing List, Thierry Reding,
	linux-pwm-u79uwXL29TY76Z2rM5mHXA, jic23-DgEjT+Ai2ygdnm+yROfE0A,
	knaack.h-Mmb7MZpHnFY, Peter Meerwald-Stadler,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Fabrice Gasnier, Gerald Baeza, Arnaud Pouliquen, Linus Walleij,
	Linaro Kernel Mailman List, Benjamin Gaignard

If it is ok for you I will add "id" parameter in mfd driver and
forward it to the sub-devices drivers
to be able to distinguish the hardware blocks


2016-11-22 18:18 GMT+01:00 Lee Jones <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>:
> On Tue, 22 Nov 2016, Benjamin Gaignard wrote:
>
>> [snip]
>> >> +     "st,stm32-iio-timer5"
>> >> +     "st,stm32-iio-timer6"
>> >> +     "st,stm32-iio-timer7"
>> >> +     "st,stm32-iio-timer8"
>> >> +     "st,stm32-iio-timer9"
>> >> +     "st,stm32-iio-timer10"
>> >> +     "st,stm32-iio-timer11"
>> >> +     "st,stm32-iio-timer12"
>> >> +     "st,stm32-iio-timer13"
>> >> +     "st,stm32-iio-timer14"
>> >
>> > We can't do this. This is a binding for a driver, not for the hardware.
>> >
>>
>> Unfortunately each instance for the hardware IP have little
>> differences like which triggers they could accept or size of the
>> counter register,
>> and I doesn't have value inside the hardware to distinguish them so
>> the only way I found is to use compatible.
>
> Can't you represent these as properties?
>
> --
> Lee Jones
> Linaro STMicroelectronics Landing Team Lead
> Linaro.org │ Open source software for ARM SoCs
> Follow Linaro: Facebook | Twitter | Blog



-- 
Benjamin Gaignard

Graphic Study Group

Linaro.org │ Open source software for ARM SoCs

Follow Linaro: Facebook | Twitter | Blog
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 5/7] add bindings for stm32 IIO timer drivers
@ 2016-11-23  8:17           ` Benjamin Gaignard
  0 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-23  8:17 UTC (permalink / raw)
  To: Lee Jones
  Cc: Lars-Peter Clausen, robh+dt, Mark Rutland, alexandre.torgue,
	devicetree, Linux Kernel Mailing List, Thierry Reding, linux-pwm,
	jic23, knaack.h, Peter Meerwald-Stadler, linux-iio,
	linux-arm-kernel, Fabrice Gasnier, Gerald Baeza,
	Arnaud Pouliquen, Linus Walleij, Linaro Kernel Mailman List,
	Benjamin Gaignard

If it is ok for you I will add "id" parameter in mfd driver and
forward it to the sub-devices drivers
to be able to distinguish the hardware blocks


2016-11-22 18:18 GMT+01:00 Lee Jones <lee.jones@linaro.org>:
> On Tue, 22 Nov 2016, Benjamin Gaignard wrote:
>
>> [snip]
>> >> +     "st,stm32-iio-timer5"
>> >> +     "st,stm32-iio-timer6"
>> >> +     "st,stm32-iio-timer7"
>> >> +     "st,stm32-iio-timer8"
>> >> +     "st,stm32-iio-timer9"
>> >> +     "st,stm32-iio-timer10"
>> >> +     "st,stm32-iio-timer11"
>> >> +     "st,stm32-iio-timer12"
>> >> +     "st,stm32-iio-timer13"
>> >> +     "st,stm32-iio-timer14"
>> >
>> > We can't do this. This is a binding for a driver, not for the hardware=
.
>> >
>>
>> Unfortunately each instance for the hardware IP have little
>> differences like which triggers they could accept or size of the
>> counter register,
>> and I doesn't have value inside the hardware to distinguish them so
>> the only way I found is to use compatible.
>
> Can't you represent these as properties?
>
> --
> Lee Jones
> Linaro STMicroelectronics Landing Team Lead
> Linaro.org =E2=94=82 Open source software for ARM SoCs
> Follow Linaro: Facebook | Twitter | Blog



--=20
Benjamin Gaignard

Graphic Study Group

Linaro.org =E2=94=82 Open source software for ARM SoCs

Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 64+ messages in thread

* [PATCH 5/7] add bindings for stm32 IIO timer drivers
@ 2016-11-23  8:17           ` Benjamin Gaignard
  0 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-23  8:17 UTC (permalink / raw)
  To: linux-arm-kernel

If it is ok for you I will add "id" parameter in mfd driver and
forward it to the sub-devices drivers
to be able to distinguish the hardware blocks


2016-11-22 18:18 GMT+01:00 Lee Jones <lee.jones@linaro.org>:
> On Tue, 22 Nov 2016, Benjamin Gaignard wrote:
>
>> [snip]
>> >> +     "st,stm32-iio-timer5"
>> >> +     "st,stm32-iio-timer6"
>> >> +     "st,stm32-iio-timer7"
>> >> +     "st,stm32-iio-timer8"
>> >> +     "st,stm32-iio-timer9"
>> >> +     "st,stm32-iio-timer10"
>> >> +     "st,stm32-iio-timer11"
>> >> +     "st,stm32-iio-timer12"
>> >> +     "st,stm32-iio-timer13"
>> >> +     "st,stm32-iio-timer14"
>> >
>> > We can't do this. This is a binding for a driver, not for the hardware.
>> >
>>
>> Unfortunately each instance for the hardware IP have little
>> differences like which triggers they could accept or size of the
>> counter register,
>> and I doesn't have value inside the hardware to distinguish them so
>> the only way I found is to use compatible.
>
> Can't you represent these as properties?
>
> --
> Lee Jones
> Linaro STMicroelectronics Landing Team Lead
> Linaro.org ? Open source software for ARM SoCs
> Follow Linaro: Facebook | Twitter | Blog



-- 
Benjamin Gaignard

Graphic Study Group

Linaro.org ? Open source software for ARM SoCs

Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 1/7] add binding for stm32 multifunctions timer driver
  2016-11-23  8:15       ` Benjamin Gaignard
@ 2016-11-23  9:21         ` Lee Jones
  -1 siblings, 0 replies; 64+ messages in thread
From: Lee Jones @ 2016-11-23  9:21 UTC (permalink / raw)
  To: Benjamin Gaignard
  Cc: robh+dt, Mark Rutland, alexandre.torgue, devicetree,
	Linux Kernel Mailing List, Thierry Reding, linux-pwm, jic23,
	knaack.h, Lars-Peter Clausen, Peter Meerwald-Stadler, linux-iio,
	linux-arm-kernel, Fabrice Gasnier, Gerald Baeza,
	Arnaud Pouliquen, Linus Walleij, Linaro Kernel Mailman List,
	Benjamin Gaignard

On Wed, 23 Nov 2016, Benjamin Gaignard wrote:

> 2016-11-22 17:52 GMT+01:00 Lee Jones <lee.jones@linaro.org>:
> > On Tue, 22 Nov 2016, Benjamin Gaignard wrote:
> >
> >> Add bindings information for stm32 timer MFD
> >>
> >> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
> >> ---
> >>  .../devicetree/bindings/mfd/stm32-timer.txt        | 53 ++++++++++++++++++++++
> >>  1 file changed, 53 insertions(+)
> >>  create mode 100644 Documentation/devicetree/bindings/mfd/stm32-timer.txt
> >>
> >> diff --git a/Documentation/devicetree/bindings/mfd/stm32-timer.txt b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
> >> new file mode 100644
> >> index 0000000..3cefce1
> >> --- /dev/null
> >> +++ b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
> >> @@ -0,0 +1,53 @@
> >> +STM32 multifunctions timer driver
> >
> > "STM32 Multi-Function Timer/PWM device bindings"
> >
> > Doesn't this shared device have a better name?
> 
> In SoC documentation those hardware blocks are named "advanced-control
> timers", "general purpose timers" or "basic timers"
> "stm32-timer" name is already used for clock source driver, that why I
> have prefix it with mfd

MFD is a Linuxisum and has no place in hardware description.

Please used one of the names you mentioned above.

Hopefully the one that best fits.

> >> +stm32 timer MFD allow to handle at the same time pwm and IIO timer devices
> >
> > No need for this sentence.
> >
> OK
> 
> >> +Required parameters:
> >> +- compatible: must be one of the follow value:
> >> +     "st,stm32-mfd-timer1"
> >> +     "st,stm32-mfd-timer2"
> >> +     "st,stm32-mfd-timer3"
> >> +     "st,stm32-mfd-timer4"
> >> +     "st,stm32-mfd-timer5"
> >> +     "st,stm32-mfd-timer6"
> >> +     "st,stm32-mfd-timer7"
> >> +     "st,stm32-mfd-timer8"
> >> +     "st,stm32-mfd-timer9"
> >> +     "st,stm32-mfd-timer10"
> >> +     "st,stm32-mfd-timer11"
> >> +     "st,stm32-mfd-timer12"
> >> +     "st,stm32-mfd-timer13"
> >> +     "st,stm32-mfd-timer14"
> >
> > We don't normally number devices.
> >
> > What's stopping you from simply doing:
> >
> >         pwm1: pwm1@40010000 {
> >                 compatible = "st,stm32-pwm";
> >         };
> >         pwm2: pwm1@40020000 {
> >                 compatible = "st,stm32-pwm";
> >         };
> >         pwm3: pwm1@40030000 {
> >                 compatible = "st,stm32-pwm";
> >         };
> >
> 
> Because each instance of the hardware is slightly different: number of
> pwm channels, triggers capabilities, etc ..
> so I need to distinguish them.
> Since it look to be a problem I will follow your suggestion and add a
> property this driver to be able to identify each instance.
> Do you think that "id" parameter (integer for 1 to 14) is acceptable ?

Unfortunately not. IDs aren't allowed in DT.

What about "pwm-chans" and "trigger"?

pwm-chans  	       : Number of available channels available
trigger		       : Boolean value specifying whether a timer is present

Why can't you let of_platform_populate() register the devices for you?
Then you can get rid of all of the meaningless numbers all over the place.

> >> +- reg :                      Physical base address and length of the controller's
> >> +                     registers.
> >> +- clock-names:               Set to "mfd_timer_clk".
> >
> Only one but I use devm_regmap_init_mmio_clk() to avoid calling
> clk_{enable/disable}
> everywhere in the drivers when reading/writing regsister.
> devm_regmap_init_mmio_clk() find the clock by it name that why I have
> put it here
> In the doc this clock in named "clk_int" I will use this name.

Please reply *below* the quote.

But okay, "clk_int" sounds like a more suitable name.

> > How many clocks are there?
> >
> > If only 1, you don't need this property.
> >
> > "mfd_timer_clk" is not the correct name.
> >
> > What is it called in the datasheet?
> >
> >> +- clocks:            Phandle of the clock used by the timer module.
> >
> > "Phandle to the clock ..."
> >
> >> +                     For Clk properties, please refer to [1].
> >> +- interrupts :               Reference to the timer interrupt
> >
> > Reference to?
> >
> > See how other binding documents describe this property.
> >
> >> +Optional parameters:
> >> +- resets :           Reference to a reset controller asserting the timer
> >
> > As above.
> >
> >> +Optional subnodes:
> >
> > Either use ":" or " :" or "<tab>:", but keep it consistent.
> >
> >> +- pwm:                       See Documentation/devicetree/bindings/pwm/pwm-stm32.txt
> >> +- iiotimer:          See Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt
> >> +
> >> +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
> >
> > Use the relative paths "../clock/", "../pwm/", "../iio/".
> >
> OK
> 
> >> +Example:
> >> +     mfd_timer1: mfdtimer1@40010000 {
> >
> > This is not an "MFD timer".  MFD is a Linuxisum.
> >
> >> +             compatible = "st,stm32-mfd-timer1";
> >
> > Better description required.
> >
> >> +             reg = <0x40010000 0x400>;
> >> +             clocks = <&rcc 0 160>;
> >> +             clock-names = "mfd_timer_clk";
> >> +             interrupts = <27>;
> >> +
> >> +             pwm1: pwm1@40010000 {
> >> +                     compatible = "st,stm32-pwm1";
> >> +             };
> >> +
> >> +             iiotimer1: iiotimer1@40010000 {
> >> +                     compatible = "st,stm32-iio-timer1";
> >> +             };
> >> +     };

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 64+ messages in thread

* [PATCH 1/7] add binding for stm32 multifunctions timer driver
@ 2016-11-23  9:21         ` Lee Jones
  0 siblings, 0 replies; 64+ messages in thread
From: Lee Jones @ 2016-11-23  9:21 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, 23 Nov 2016, Benjamin Gaignard wrote:

> 2016-11-22 17:52 GMT+01:00 Lee Jones <lee.jones@linaro.org>:
> > On Tue, 22 Nov 2016, Benjamin Gaignard wrote:
> >
> >> Add bindings information for stm32 timer MFD
> >>
> >> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
> >> ---
> >>  .../devicetree/bindings/mfd/stm32-timer.txt        | 53 ++++++++++++++++++++++
> >>  1 file changed, 53 insertions(+)
> >>  create mode 100644 Documentation/devicetree/bindings/mfd/stm32-timer.txt
> >>
> >> diff --git a/Documentation/devicetree/bindings/mfd/stm32-timer.txt b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
> >> new file mode 100644
> >> index 0000000..3cefce1
> >> --- /dev/null
> >> +++ b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
> >> @@ -0,0 +1,53 @@
> >> +STM32 multifunctions timer driver
> >
> > "STM32 Multi-Function Timer/PWM device bindings"
> >
> > Doesn't this shared device have a better name?
> 
> In SoC documentation those hardware blocks are named "advanced-control
> timers", "general purpose timers" or "basic timers"
> "stm32-timer" name is already used for clock source driver, that why I
> have prefix it with mfd

MFD is a Linuxisum and has no place in hardware description.

Please used one of the names you mentioned above.

Hopefully the one that best fits.

> >> +stm32 timer MFD allow to handle at the same time pwm and IIO timer devices
> >
> > No need for this sentence.
> >
> OK
> 
> >> +Required parameters:
> >> +- compatible: must be one of the follow value:
> >> +     "st,stm32-mfd-timer1"
> >> +     "st,stm32-mfd-timer2"
> >> +     "st,stm32-mfd-timer3"
> >> +     "st,stm32-mfd-timer4"
> >> +     "st,stm32-mfd-timer5"
> >> +     "st,stm32-mfd-timer6"
> >> +     "st,stm32-mfd-timer7"
> >> +     "st,stm32-mfd-timer8"
> >> +     "st,stm32-mfd-timer9"
> >> +     "st,stm32-mfd-timer10"
> >> +     "st,stm32-mfd-timer11"
> >> +     "st,stm32-mfd-timer12"
> >> +     "st,stm32-mfd-timer13"
> >> +     "st,stm32-mfd-timer14"
> >
> > We don't normally number devices.
> >
> > What's stopping you from simply doing:
> >
> >         pwm1: pwm1 at 40010000 {
> >                 compatible = "st,stm32-pwm";
> >         };
> >         pwm2: pwm1 at 40020000 {
> >                 compatible = "st,stm32-pwm";
> >         };
> >         pwm3: pwm1 at 40030000 {
> >                 compatible = "st,stm32-pwm";
> >         };
> >
> 
> Because each instance of the hardware is slightly different: number of
> pwm channels, triggers capabilities, etc ..
> so I need to distinguish them.
> Since it look to be a problem I will follow your suggestion and add a
> property this driver to be able to identify each instance.
> Do you think that "id" parameter (integer for 1 to 14) is acceptable ?

Unfortunately not. IDs aren't allowed in DT.

What about "pwm-chans" and "trigger"?

pwm-chans  	       : Number of available channels available
trigger		       : Boolean value specifying whether a timer is present

Why can't you let of_platform_populate() register the devices for you?
Then you can get rid of all of the meaningless numbers all over the place.

> >> +- reg :                      Physical base address and length of the controller's
> >> +                     registers.
> >> +- clock-names:               Set to "mfd_timer_clk".
> >
> Only one but I use devm_regmap_init_mmio_clk() to avoid calling
> clk_{enable/disable}
> everywhere in the drivers when reading/writing regsister.
> devm_regmap_init_mmio_clk() find the clock by it name that why I have
> put it here
> In the doc this clock in named "clk_int" I will use this name.

Please reply *below* the quote.

But okay, "clk_int" sounds like a more suitable name.

> > How many clocks are there?
> >
> > If only 1, you don't need this property.
> >
> > "mfd_timer_clk" is not the correct name.
> >
> > What is it called in the datasheet?
> >
> >> +- clocks:            Phandle of the clock used by the timer module.
> >
> > "Phandle to the clock ..."
> >
> >> +                     For Clk properties, please refer to [1].
> >> +- interrupts :               Reference to the timer interrupt
> >
> > Reference to?
> >
> > See how other binding documents describe this property.
> >
> >> +Optional parameters:
> >> +- resets :           Reference to a reset controller asserting the timer
> >
> > As above.
> >
> >> +Optional subnodes:
> >
> > Either use ":" or " :" or "<tab>:", but keep it consistent.
> >
> >> +- pwm:                       See Documentation/devicetree/bindings/pwm/pwm-stm32.txt
> >> +- iiotimer:          See Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt
> >> +
> >> +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
> >
> > Use the relative paths "../clock/", "../pwm/", "../iio/".
> >
> OK
> 
> >> +Example:
> >> +     mfd_timer1: mfdtimer1 at 40010000 {
> >
> > This is not an "MFD timer".  MFD is a Linuxisum.
> >
> >> +             compatible = "st,stm32-mfd-timer1";
> >
> > Better description required.
> >
> >> +             reg = <0x40010000 0x400>;
> >> +             clocks = <&rcc 0 160>;
> >> +             clock-names = "mfd_timer_clk";
> >> +             interrupts = <27>;
> >> +
> >> +             pwm1: pwm1 at 40010000 {
> >> +                     compatible = "st,stm32-pwm1";
> >> +             };
> >> +
> >> +             iiotimer1: iiotimer1 at 40010000 {
> >> +                     compatible = "st,stm32-iio-timer1";
> >> +             };
> >> +     };

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 7/7] add stm32 multi-functions timer driver in DT
  2016-11-22 16:13   ` Benjamin Gaignard
  (?)
@ 2016-11-23  9:53     ` Lee Jones
  -1 siblings, 0 replies; 64+ messages in thread
From: Lee Jones @ 2016-11-23  9:53 UTC (permalink / raw)
  To: Benjamin Gaignard
  Cc: robh+dt, mark.rutland, alexandre.torgue, devicetree,
	linux-kernel, thierry.reding, linux-pwm, jic23, knaack.h, lars,
	pmeerw, linux-iio, linux-arm-kernel, fabrice.gasnier,
	gerald.baeza, arnaud.pouliquen, linus.walleij, linaro-kernel,
	Benjamin Gaignard

On Tue, 22 Nov 2016, Benjamin Gaignard wrote:

> Add timers MFD and childs into DT for stm32f4.
> Define and enable pwm1 and pwm3 for stm32f469 discovery board
> 
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
> ---
>  arch/arm/boot/dts/stm32f429.dtsi      | 246 ++++++++++++++++++++++++++++++++++
>  arch/arm/boot/dts/stm32f469-disco.dts |  29 ++++
>  2 files changed, 275 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
> index bca491d..28a0fe9 100644
> --- a/arch/arm/boot/dts/stm32f429.dtsi
> +++ b/arch/arm/boot/dts/stm32f429.dtsi
> @@ -355,6 +355,21 @@
>  					slew-rate = <2>;
>  				};
>  			};
> +
> +			pwm1_pins: pwm@1 {
> +				pins {
> +					pinmux = <STM32F429_PA8_FUNC_TIM1_CH1>,
> +						 <STM32F429_PB13_FUNC_TIM1_CH1N>,
> +						 <STM32F429_PB12_FUNC_TIM1_BKIN>;
> +				};
> +			};
> +
> +			pwm3_pins: pwm@3 {
> +				pins {
> +					pinmux = <STM32F429_PB4_FUNC_TIM3_CH1>,
> +						 <STM32F429_PB5_FUNC_TIM3_CH2>;
> +				};
> +			};
>  		};
>  
>  		rcc: rcc@40023810 {
> @@ -426,6 +441,237 @@
>  			interrupts = <80>;
>  			clocks = <&rcc 0 38>;
>  		};
> +
> +		mfd_timer1: mfdtimer1@40010000 {

Do you reference this node?

If not, it should read:

  advanced-control@40010000

> +			compatible = "st,stm32-mfd-timer1";

"st,stm32-advanced-control"

> +			reg = <0x40010000 0x400>;
> +			clocks = <&rcc 0 160>;
> +			clock-names = "mfd_timer_clk";

"clk_int"

> +			interrupts = <27>;

This is a timer property.

Also move the associated registration C code into the timer driver.

> +			status = "disabled";
> +
> +			pwm1: pwm1@40010000 {

  pwm@0 {

> +				compatible = "st,stm32-pwm1";

st,stm32-advanced-control-pwm

> +				status = "disabled";
> +			};
> +
> +			iiotimer1: iiotimer1@40010000 {

Same here:

  timer@0

> +				compatible = "st,stm32-iio-timer1";

st,stm32-advanced-control-timer

> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer2: mfdtimer2@40000000 {
> +			compatible = "st,stm32-mfd-timer2";
> +			reg = <0x40000000 0x400>;
> +			clocks = <&rcc 0 128>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <28>;
> +			status = "disabled";
> +
> +			pwm2: pwm2@40000000 {
> +				compatible = "st,stm32-pwm2";
> +				status = "disabled";
> +			};
> +			iiotimer2: iiotimer2@40000000 {
> +				compatible = "st,stm32-iio-timer2";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer3: mfdtimer3@40000400 {
> +			compatible = "st,stm32-mfd-timer3";
> +			reg = <0x40000400 0x400>;
> +			clocks = <&rcc 0 129>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <29>;
> +			status = "disabled";
> +
> +			pwm3: pwm3@40000400 {
> +				compatible = "st,stm32-pwm3";
> +				status = "disabled";
> +			};
> +			iiotimer3: iiotimer3@40000400 {
> +				compatible = "st,stm32-iio-timer3";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer4: mfdtimer4@40000800 {
> +			compatible = "st,stm32-mfd-timer4";
> +			reg = <0x40000800 0x400>;
> +			clocks = <&rcc 0 130>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <30>;
> +			status = "disabled";
> +
> +			pwm4: pwm4@40000800 {
> +				compatible = "st,stm32-pwm4";
> +				status = "disabled";
> +			};
> +			iiotimer4: iiotimer4@40000800 {
> +				compatible = "st,stm32-iio-timer4";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer5: mfdtimer5@40000C00 {
> +			compatible = "st,stm32-mfd-timer5";
> +			reg = <0x40000C00 0x400>;
> +			clocks = <&rcc 0 131>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <50>;
> +			status = "disabled";
> +
> +			pwm5: pwm5@40000C00 {
> +				compatible = "st,stm32-pwm5";
> +				status = "disabled";
> +			};
> +			iiotimer5: iiotimer5@40000800 {
> +				compatible = "st,stm32-iio-timer5";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer6: mfdtimer6@40001000 {
> +			compatible = "st,stm32-mfd-timer6";
> +			reg = <0x40001000 0x400>;
> +			clocks = <&rcc 0 132>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <54>;
> +			status = "disabled";
> +
> +			iiotimer6: iiotimer6@40001000 {
> +				compatible = "st,stm32-iio-timer6";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer7: mfdtimer7@40001400 {
> +			compatible = "st,stm32-mfd-timer7";
> +			reg = <0x40001400 0x400>;
> +			clocks = <&rcc 0 133>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <55>;
> +			status = "disabled";
> +
> +			iiotimer7: iiotimer7@40001400 {
> +				compatible = "st,stm32-iio-timer7";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer8: mfdtimer8@40010400 {
> +			compatible = "st,stm32-mfd-timer8";
> +			reg = <0x40010400 0x400>;
> +			clocks = <&rcc 0 161>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <46>;
> +			status = "disabled";
> +
> +			pwm8: pwm8@40010400 {
> +				compatible = "st,stm32-pwm8";
> +				status = "disabled";
> +			};
> +
> +			iiotimer8: iiotimer7@40010400 {
> +				compatible = "st,stm32-iio-timer8";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer9: mfdtimer9@40014000 {
> +			compatible = "st,stm32-mfd-timer9";
> +			reg = <0x40014000 0x400>;
> +			clocks = <&rcc 0 176>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <24>;
> +			status = "disabled";
> +
> +			pwm9: pwm9@40014000 {
> +				compatible = "st,stm32-pwm9";
> +				status = "disabled";
> +			};
> +
> +			iiotimer9: iiotimer9@40014000 {
> +				compatible = "st,stm32-iio-timer9";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer10: mfdtimer10@40014400 {
> +			compatible = "st,stm32-mfd-timer10";
> +			reg = <0x40014400 0x400>;
> +			clocks = <&rcc 0 177>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <25>;
> +			status = "disabled";
> +
> +			pwm10: pwm10@40014400 {
> +				compatible = "st,stm32-pwm10";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer11: mfdtimer11@40014800 {
> +			compatible = "st,stm32-mfd-timer11";
> +			reg = <0x40014800 0x400>;
> +			clocks = <&rcc 0 178>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <26>;
> +			status = "disabled";
> +
> +			pwm11: pwm11@40014800 {
> +				compatible = "st,stm32-pwm11";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer12: mfdtimer12@40001800 {
> +			compatible = "st,stm32-mfd-timer12";
> +			reg = <0x40001800 0x400>;
> +			clocks = <&rcc 0 134>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <43>;
> +			status = "disabled";
> +
> +			pwm12: pwm12@40001800 {
> +				compatible = "st,stm32-pwm12";
> +				status = "disabled";
> +			};
> +			iiotimer12: iiotimer12@40001800 {
> +				compatible = "st,stm32-iio-timer12";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer13: mfdtimer13@40001C00 {
> +			compatible = "st,stm32-mfd-timer13";
> +			reg = <0x40001C00 0x400>;
> +			clocks = <&rcc 0 135>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <44>;
> +			status = "disabled";
> +
> +			pwm13: pwm13@40001C00 {
> +				compatible = "st,stm32-pwm13";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer14: mfdtimer14@40002000 {
> +			compatible = "st,stm32-mfd-timer14";
> +			reg = <0x40002000 0x400>;
> +			clocks = <&rcc 0 136>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <45>;
> +			status = "disabled";
> +
> +			pwm14: pwm14@40002000 {
> +				compatible = "st,stm32-pwm14";
> +				status = "disabled";
> +			};
> +		};
>  	};
>  };
>  
> diff --git a/arch/arm/boot/dts/stm32f469-disco.dts b/arch/arm/boot/dts/stm32f469-disco.dts
> index 8a163d7..a8f1788 100644
> --- a/arch/arm/boot/dts/stm32f469-disco.dts
> +++ b/arch/arm/boot/dts/stm32f469-disco.dts
> @@ -81,3 +81,32 @@
>  &usart3 {
>  	status = "okay";
>  };
> +
> +&mfd_timer1 {
> +	status = "okay";
> +};
> +
> +&pwm1 {
> +	pinctrl-0	= <&pwm1_pins>;
> +	pinctrl-names	= "default";
> +	st,breakinput-polarity = <0>;

Is this documented?

I'm sure we have generic polarity properties somewhere already?

> +	status = "okay";
> +};
> +
> +&iiotimer1 {
> +	status = "okay";
> +};
> +
> +&mfd_timer3 {
> +	status = "okay";
> +};
> +
> +&pwm3 {
> +	pinctrl-0	= <&pwm3_pins>;
> +	pinctrl-names	= "default";
> +	status = "okay";
> +};
> +
> +&iiotimer3 {
> +	status = "okay";
> +};

I've always disliked this way of referencing nodes!

Any chance we can represent them in a hierarchy, so we don't lose that
information and we can get rid of all those horrible labels?

I'm happy to do the work.

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 7/7] add stm32 multi-functions timer driver in DT
@ 2016-11-23  9:53     ` Lee Jones
  0 siblings, 0 replies; 64+ messages in thread
From: Lee Jones @ 2016-11-23  9:53 UTC (permalink / raw)
  To: Benjamin Gaignard
  Cc: mark.rutland, devicetree, lars, alexandre.torgue, linux-pwm,
	linux-iio, linus.walleij, arnaud.pouliquen, linux-kernel,
	robh+dt, thierry.reding, linux-arm-kernel, pmeerw, knaack.h,
	gerald.baeza, fabrice.gasnier, linaro-kernel, jic23,
	Benjamin Gaignard

On Tue, 22 Nov 2016, Benjamin Gaignard wrote:

> Add timers MFD and childs into DT for stm32f4.
> Define and enable pwm1 and pwm3 for stm32f469 discovery board
> 
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
> ---
>  arch/arm/boot/dts/stm32f429.dtsi      | 246 ++++++++++++++++++++++++++++++++++
>  arch/arm/boot/dts/stm32f469-disco.dts |  29 ++++
>  2 files changed, 275 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
> index bca491d..28a0fe9 100644
> --- a/arch/arm/boot/dts/stm32f429.dtsi
> +++ b/arch/arm/boot/dts/stm32f429.dtsi
> @@ -355,6 +355,21 @@
>  					slew-rate = <2>;
>  				};
>  			};
> +
> +			pwm1_pins: pwm@1 {
> +				pins {
> +					pinmux = <STM32F429_PA8_FUNC_TIM1_CH1>,
> +						 <STM32F429_PB13_FUNC_TIM1_CH1N>,
> +						 <STM32F429_PB12_FUNC_TIM1_BKIN>;
> +				};
> +			};
> +
> +			pwm3_pins: pwm@3 {
> +				pins {
> +					pinmux = <STM32F429_PB4_FUNC_TIM3_CH1>,
> +						 <STM32F429_PB5_FUNC_TIM3_CH2>;
> +				};
> +			};
>  		};
>  
>  		rcc: rcc@40023810 {
> @@ -426,6 +441,237 @@
>  			interrupts = <80>;
>  			clocks = <&rcc 0 38>;
>  		};
> +
> +		mfd_timer1: mfdtimer1@40010000 {

Do you reference this node?

If not, it should read:

  advanced-control@40010000

> +			compatible = "st,stm32-mfd-timer1";

"st,stm32-advanced-control"

> +			reg = <0x40010000 0x400>;
> +			clocks = <&rcc 0 160>;
> +			clock-names = "mfd_timer_clk";

"clk_int"

> +			interrupts = <27>;

This is a timer property.

Also move the associated registration C code into the timer driver.

> +			status = "disabled";
> +
> +			pwm1: pwm1@40010000 {

  pwm@0 {

> +				compatible = "st,stm32-pwm1";

st,stm32-advanced-control-pwm

> +				status = "disabled";
> +			};
> +
> +			iiotimer1: iiotimer1@40010000 {

Same here:

  timer@0

> +				compatible = "st,stm32-iio-timer1";

st,stm32-advanced-control-timer

> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer2: mfdtimer2@40000000 {
> +			compatible = "st,stm32-mfd-timer2";
> +			reg = <0x40000000 0x400>;
> +			clocks = <&rcc 0 128>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <28>;
> +			status = "disabled";
> +
> +			pwm2: pwm2@40000000 {
> +				compatible = "st,stm32-pwm2";
> +				status = "disabled";
> +			};
> +			iiotimer2: iiotimer2@40000000 {
> +				compatible = "st,stm32-iio-timer2";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer3: mfdtimer3@40000400 {
> +			compatible = "st,stm32-mfd-timer3";
> +			reg = <0x40000400 0x400>;
> +			clocks = <&rcc 0 129>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <29>;
> +			status = "disabled";
> +
> +			pwm3: pwm3@40000400 {
> +				compatible = "st,stm32-pwm3";
> +				status = "disabled";
> +			};
> +			iiotimer3: iiotimer3@40000400 {
> +				compatible = "st,stm32-iio-timer3";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer4: mfdtimer4@40000800 {
> +			compatible = "st,stm32-mfd-timer4";
> +			reg = <0x40000800 0x400>;
> +			clocks = <&rcc 0 130>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <30>;
> +			status = "disabled";
> +
> +			pwm4: pwm4@40000800 {
> +				compatible = "st,stm32-pwm4";
> +				status = "disabled";
> +			};
> +			iiotimer4: iiotimer4@40000800 {
> +				compatible = "st,stm32-iio-timer4";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer5: mfdtimer5@40000C00 {
> +			compatible = "st,stm32-mfd-timer5";
> +			reg = <0x40000C00 0x400>;
> +			clocks = <&rcc 0 131>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <50>;
> +			status = "disabled";
> +
> +			pwm5: pwm5@40000C00 {
> +				compatible = "st,stm32-pwm5";
> +				status = "disabled";
> +			};
> +			iiotimer5: iiotimer5@40000800 {
> +				compatible = "st,stm32-iio-timer5";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer6: mfdtimer6@40001000 {
> +			compatible = "st,stm32-mfd-timer6";
> +			reg = <0x40001000 0x400>;
> +			clocks = <&rcc 0 132>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <54>;
> +			status = "disabled";
> +
> +			iiotimer6: iiotimer6@40001000 {
> +				compatible = "st,stm32-iio-timer6";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer7: mfdtimer7@40001400 {
> +			compatible = "st,stm32-mfd-timer7";
> +			reg = <0x40001400 0x400>;
> +			clocks = <&rcc 0 133>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <55>;
> +			status = "disabled";
> +
> +			iiotimer7: iiotimer7@40001400 {
> +				compatible = "st,stm32-iio-timer7";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer8: mfdtimer8@40010400 {
> +			compatible = "st,stm32-mfd-timer8";
> +			reg = <0x40010400 0x400>;
> +			clocks = <&rcc 0 161>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <46>;
> +			status = "disabled";
> +
> +			pwm8: pwm8@40010400 {
> +				compatible = "st,stm32-pwm8";
> +				status = "disabled";
> +			};
> +
> +			iiotimer8: iiotimer7@40010400 {
> +				compatible = "st,stm32-iio-timer8";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer9: mfdtimer9@40014000 {
> +			compatible = "st,stm32-mfd-timer9";
> +			reg = <0x40014000 0x400>;
> +			clocks = <&rcc 0 176>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <24>;
> +			status = "disabled";
> +
> +			pwm9: pwm9@40014000 {
> +				compatible = "st,stm32-pwm9";
> +				status = "disabled";
> +			};
> +
> +			iiotimer9: iiotimer9@40014000 {
> +				compatible = "st,stm32-iio-timer9";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer10: mfdtimer10@40014400 {
> +			compatible = "st,stm32-mfd-timer10";
> +			reg = <0x40014400 0x400>;
> +			clocks = <&rcc 0 177>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <25>;
> +			status = "disabled";
> +
> +			pwm10: pwm10@40014400 {
> +				compatible = "st,stm32-pwm10";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer11: mfdtimer11@40014800 {
> +			compatible = "st,stm32-mfd-timer11";
> +			reg = <0x40014800 0x400>;
> +			clocks = <&rcc 0 178>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <26>;
> +			status = "disabled";
> +
> +			pwm11: pwm11@40014800 {
> +				compatible = "st,stm32-pwm11";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer12: mfdtimer12@40001800 {
> +			compatible = "st,stm32-mfd-timer12";
> +			reg = <0x40001800 0x400>;
> +			clocks = <&rcc 0 134>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <43>;
> +			status = "disabled";
> +
> +			pwm12: pwm12@40001800 {
> +				compatible = "st,stm32-pwm12";
> +				status = "disabled";
> +			};
> +			iiotimer12: iiotimer12@40001800 {
> +				compatible = "st,stm32-iio-timer12";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer13: mfdtimer13@40001C00 {
> +			compatible = "st,stm32-mfd-timer13";
> +			reg = <0x40001C00 0x400>;
> +			clocks = <&rcc 0 135>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <44>;
> +			status = "disabled";
> +
> +			pwm13: pwm13@40001C00 {
> +				compatible = "st,stm32-pwm13";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer14: mfdtimer14@40002000 {
> +			compatible = "st,stm32-mfd-timer14";
> +			reg = <0x40002000 0x400>;
> +			clocks = <&rcc 0 136>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <45>;
> +			status = "disabled";
> +
> +			pwm14: pwm14@40002000 {
> +				compatible = "st,stm32-pwm14";
> +				status = "disabled";
> +			};
> +		};
>  	};
>  };
>  
> diff --git a/arch/arm/boot/dts/stm32f469-disco.dts b/arch/arm/boot/dts/stm32f469-disco.dts
> index 8a163d7..a8f1788 100644
> --- a/arch/arm/boot/dts/stm32f469-disco.dts
> +++ b/arch/arm/boot/dts/stm32f469-disco.dts
> @@ -81,3 +81,32 @@
>  &usart3 {
>  	status = "okay";
>  };
> +
> +&mfd_timer1 {
> +	status = "okay";
> +};
> +
> +&pwm1 {
> +	pinctrl-0	= <&pwm1_pins>;
> +	pinctrl-names	= "default";
> +	st,breakinput-polarity = <0>;

Is this documented?

I'm sure we have generic polarity properties somewhere already?

> +	status = "okay";
> +};
> +
> +&iiotimer1 {
> +	status = "okay";
> +};
> +
> +&mfd_timer3 {
> +	status = "okay";
> +};
> +
> +&pwm3 {
> +	pinctrl-0	= <&pwm3_pins>;
> +	pinctrl-names	= "default";
> +	status = "okay";
> +};
> +
> +&iiotimer3 {
> +	status = "okay";
> +};

I've always disliked this way of referencing nodes!

Any chance we can represent them in a hierarchy, so we don't lose that
information and we can get rid of all those horrible labels?

I'm happy to do the work.

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 64+ messages in thread

* [PATCH 7/7] add stm32 multi-functions timer driver in DT
@ 2016-11-23  9:53     ` Lee Jones
  0 siblings, 0 replies; 64+ messages in thread
From: Lee Jones @ 2016-11-23  9:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 22 Nov 2016, Benjamin Gaignard wrote:

> Add timers MFD and childs into DT for stm32f4.
> Define and enable pwm1 and pwm3 for stm32f469 discovery board
> 
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
> ---
>  arch/arm/boot/dts/stm32f429.dtsi      | 246 ++++++++++++++++++++++++++++++++++
>  arch/arm/boot/dts/stm32f469-disco.dts |  29 ++++
>  2 files changed, 275 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
> index bca491d..28a0fe9 100644
> --- a/arch/arm/boot/dts/stm32f429.dtsi
> +++ b/arch/arm/boot/dts/stm32f429.dtsi
> @@ -355,6 +355,21 @@
>  					slew-rate = <2>;
>  				};
>  			};
> +
> +			pwm1_pins: pwm at 1 {
> +				pins {
> +					pinmux = <STM32F429_PA8_FUNC_TIM1_CH1>,
> +						 <STM32F429_PB13_FUNC_TIM1_CH1N>,
> +						 <STM32F429_PB12_FUNC_TIM1_BKIN>;
> +				};
> +			};
> +
> +			pwm3_pins: pwm at 3 {
> +				pins {
> +					pinmux = <STM32F429_PB4_FUNC_TIM3_CH1>,
> +						 <STM32F429_PB5_FUNC_TIM3_CH2>;
> +				};
> +			};
>  		};
>  
>  		rcc: rcc at 40023810 {
> @@ -426,6 +441,237 @@
>  			interrupts = <80>;
>  			clocks = <&rcc 0 38>;
>  		};
> +
> +		mfd_timer1: mfdtimer1 at 40010000 {

Do you reference this node?

If not, it should read:

  advanced-control at 40010000

> +			compatible = "st,stm32-mfd-timer1";

"st,stm32-advanced-control"

> +			reg = <0x40010000 0x400>;
> +			clocks = <&rcc 0 160>;
> +			clock-names = "mfd_timer_clk";

"clk_int"

> +			interrupts = <27>;

This is a timer property.

Also move the associated registration C code into the timer driver.

> +			status = "disabled";
> +
> +			pwm1: pwm1 at 40010000 {

  pwm at 0 {

> +				compatible = "st,stm32-pwm1";

st,stm32-advanced-control-pwm

> +				status = "disabled";
> +			};
> +
> +			iiotimer1: iiotimer1 at 40010000 {

Same here:

  timer at 0

> +				compatible = "st,stm32-iio-timer1";

st,stm32-advanced-control-timer

> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer2: mfdtimer2 at 40000000 {
> +			compatible = "st,stm32-mfd-timer2";
> +			reg = <0x40000000 0x400>;
> +			clocks = <&rcc 0 128>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <28>;
> +			status = "disabled";
> +
> +			pwm2: pwm2 at 40000000 {
> +				compatible = "st,stm32-pwm2";
> +				status = "disabled";
> +			};
> +			iiotimer2: iiotimer2 at 40000000 {
> +				compatible = "st,stm32-iio-timer2";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer3: mfdtimer3 at 40000400 {
> +			compatible = "st,stm32-mfd-timer3";
> +			reg = <0x40000400 0x400>;
> +			clocks = <&rcc 0 129>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <29>;
> +			status = "disabled";
> +
> +			pwm3: pwm3 at 40000400 {
> +				compatible = "st,stm32-pwm3";
> +				status = "disabled";
> +			};
> +			iiotimer3: iiotimer3 at 40000400 {
> +				compatible = "st,stm32-iio-timer3";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer4: mfdtimer4 at 40000800 {
> +			compatible = "st,stm32-mfd-timer4";
> +			reg = <0x40000800 0x400>;
> +			clocks = <&rcc 0 130>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <30>;
> +			status = "disabled";
> +
> +			pwm4: pwm4 at 40000800 {
> +				compatible = "st,stm32-pwm4";
> +				status = "disabled";
> +			};
> +			iiotimer4: iiotimer4 at 40000800 {
> +				compatible = "st,stm32-iio-timer4";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer5: mfdtimer5 at 40000C00 {
> +			compatible = "st,stm32-mfd-timer5";
> +			reg = <0x40000C00 0x400>;
> +			clocks = <&rcc 0 131>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <50>;
> +			status = "disabled";
> +
> +			pwm5: pwm5 at 40000C00 {
> +				compatible = "st,stm32-pwm5";
> +				status = "disabled";
> +			};
> +			iiotimer5: iiotimer5 at 40000800 {
> +				compatible = "st,stm32-iio-timer5";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer6: mfdtimer6 at 40001000 {
> +			compatible = "st,stm32-mfd-timer6";
> +			reg = <0x40001000 0x400>;
> +			clocks = <&rcc 0 132>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <54>;
> +			status = "disabled";
> +
> +			iiotimer6: iiotimer6 at 40001000 {
> +				compatible = "st,stm32-iio-timer6";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer7: mfdtimer7 at 40001400 {
> +			compatible = "st,stm32-mfd-timer7";
> +			reg = <0x40001400 0x400>;
> +			clocks = <&rcc 0 133>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <55>;
> +			status = "disabled";
> +
> +			iiotimer7: iiotimer7 at 40001400 {
> +				compatible = "st,stm32-iio-timer7";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer8: mfdtimer8 at 40010400 {
> +			compatible = "st,stm32-mfd-timer8";
> +			reg = <0x40010400 0x400>;
> +			clocks = <&rcc 0 161>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <46>;
> +			status = "disabled";
> +
> +			pwm8: pwm8 at 40010400 {
> +				compatible = "st,stm32-pwm8";
> +				status = "disabled";
> +			};
> +
> +			iiotimer8: iiotimer7 at 40010400 {
> +				compatible = "st,stm32-iio-timer8";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer9: mfdtimer9 at 40014000 {
> +			compatible = "st,stm32-mfd-timer9";
> +			reg = <0x40014000 0x400>;
> +			clocks = <&rcc 0 176>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <24>;
> +			status = "disabled";
> +
> +			pwm9: pwm9 at 40014000 {
> +				compatible = "st,stm32-pwm9";
> +				status = "disabled";
> +			};
> +
> +			iiotimer9: iiotimer9 at 40014000 {
> +				compatible = "st,stm32-iio-timer9";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer10: mfdtimer10 at 40014400 {
> +			compatible = "st,stm32-mfd-timer10";
> +			reg = <0x40014400 0x400>;
> +			clocks = <&rcc 0 177>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <25>;
> +			status = "disabled";
> +
> +			pwm10: pwm10 at 40014400 {
> +				compatible = "st,stm32-pwm10";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer11: mfdtimer11 at 40014800 {
> +			compatible = "st,stm32-mfd-timer11";
> +			reg = <0x40014800 0x400>;
> +			clocks = <&rcc 0 178>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <26>;
> +			status = "disabled";
> +
> +			pwm11: pwm11 at 40014800 {
> +				compatible = "st,stm32-pwm11";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer12: mfdtimer12 at 40001800 {
> +			compatible = "st,stm32-mfd-timer12";
> +			reg = <0x40001800 0x400>;
> +			clocks = <&rcc 0 134>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <43>;
> +			status = "disabled";
> +
> +			pwm12: pwm12 at 40001800 {
> +				compatible = "st,stm32-pwm12";
> +				status = "disabled";
> +			};
> +			iiotimer12: iiotimer12 at 40001800 {
> +				compatible = "st,stm32-iio-timer12";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer13: mfdtimer13 at 40001C00 {
> +			compatible = "st,stm32-mfd-timer13";
> +			reg = <0x40001C00 0x400>;
> +			clocks = <&rcc 0 135>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <44>;
> +			status = "disabled";
> +
> +			pwm13: pwm13 at 40001C00 {
> +				compatible = "st,stm32-pwm13";
> +				status = "disabled";
> +			};
> +		};
> +
> +		mfd_timer14: mfdtimer14 at 40002000 {
> +			compatible = "st,stm32-mfd-timer14";
> +			reg = <0x40002000 0x400>;
> +			clocks = <&rcc 0 136>;
> +			clock-names = "mfd_timer_clk";
> +			interrupts = <45>;
> +			status = "disabled";
> +
> +			pwm14: pwm14 at 40002000 {
> +				compatible = "st,stm32-pwm14";
> +				status = "disabled";
> +			};
> +		};
>  	};
>  };
>  
> diff --git a/arch/arm/boot/dts/stm32f469-disco.dts b/arch/arm/boot/dts/stm32f469-disco.dts
> index 8a163d7..a8f1788 100644
> --- a/arch/arm/boot/dts/stm32f469-disco.dts
> +++ b/arch/arm/boot/dts/stm32f469-disco.dts
> @@ -81,3 +81,32 @@
>  &usart3 {
>  	status = "okay";
>  };
> +
> +&mfd_timer1 {
> +	status = "okay";
> +};
> +
> +&pwm1 {
> +	pinctrl-0	= <&pwm1_pins>;
> +	pinctrl-names	= "default";
> +	st,breakinput-polarity = <0>;

Is this documented?

I'm sure we have generic polarity properties somewhere already?

> +	status = "okay";
> +};
> +
> +&iiotimer1 {
> +	status = "okay";
> +};
> +
> +&mfd_timer3 {
> +	status = "okay";
> +};
> +
> +&pwm3 {
> +	pinctrl-0	= <&pwm3_pins>;
> +	pinctrl-names	= "default";
> +	status = "okay";
> +};
> +
> +&iiotimer3 {
> +	status = "okay";
> +};

I've always disliked this way of referencing nodes!

Any chance we can represent them in a hierarchy, so we don't lose that
information and we can get rid of all those horrible labels?

I'm happy to do the work.

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 1/7] add binding for stm32 multifunctions timer driver
@ 2016-11-23 17:02           ` Benjamin Gaignard
  0 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-23 17:02 UTC (permalink / raw)
  To: Lee Jones
  Cc: robh+dt, Mark Rutland, alexandre.torgue, devicetree,
	Linux Kernel Mailing List, Thierry Reding, linux-pwm, jic23,
	knaack.h, Lars-Peter Clausen, Peter Meerwald-Stadler, linux-iio,
	linux-arm-kernel, Fabrice Gasnier, Gerald Baeza,
	Arnaud Pouliquen, Linus Walleij, Linaro Kernel Mailman List,
	Benjamin Gaignard

2016-11-23 10:21 GMT+01:00 Lee Jones <lee.jones@linaro.org>:
> On Wed, 23 Nov 2016, Benjamin Gaignard wrote:
>
>> 2016-11-22 17:52 GMT+01:00 Lee Jones <lee.jones@linaro.org>:
>> > On Tue, 22 Nov 2016, Benjamin Gaignard wrote:
>> >
>> >> Add bindings information for stm32 timer MFD
>> >>
>> >> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
>> >> ---
>> >>  .../devicetree/bindings/mfd/stm32-timer.txt        | 53 ++++++++++++++++++++++
>> >>  1 file changed, 53 insertions(+)
>> >>  create mode 100644 Documentation/devicetree/bindings/mfd/stm32-timer.txt
>> >>
>> >> diff --git a/Documentation/devicetree/bindings/mfd/stm32-timer.txt b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
>> >> new file mode 100644
>> >> index 0000000..3cefce1
>> >> --- /dev/null
>> >> +++ b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
>> >> @@ -0,0 +1,53 @@
>> >> +STM32 multifunctions timer driver
>> >
>> > "STM32 Multi-Function Timer/PWM device bindings"
>> >
>> > Doesn't this shared device have a better name?
>>
>> In SoC documentation those hardware blocks are named "advanced-control
>> timers", "general purpose timers" or "basic timers"
>> "stm32-timer" name is already used for clock source driver, that why I
>> have prefix it with mfd
>
> MFD is a Linuxisum and has no place in hardware description.
>
> Please used one of the names you mentioned above.

I will go for "st,stm32-advanced-timer"

>
> Hopefully the one that best fits.
>
>> >> +stm32 timer MFD allow to handle at the same time pwm and IIO timer devices
>> >
>> > No need for this sentence.
>> >
>> OK
>>
>> >> +Required parameters:
>> >> +- compatible: must be one of the follow value:
>> >> +     "st,stm32-mfd-timer1"
>> >> +     "st,stm32-mfd-timer2"
>> >> +     "st,stm32-mfd-timer3"
>> >> +     "st,stm32-mfd-timer4"
>> >> +     "st,stm32-mfd-timer5"
>> >> +     "st,stm32-mfd-timer6"
>> >> +     "st,stm32-mfd-timer7"
>> >> +     "st,stm32-mfd-timer8"
>> >> +     "st,stm32-mfd-timer9"
>> >> +     "st,stm32-mfd-timer10"
>> >> +     "st,stm32-mfd-timer11"
>> >> +     "st,stm32-mfd-timer12"
>> >> +     "st,stm32-mfd-timer13"
>> >> +     "st,stm32-mfd-timer14"
>> >
>> > We don't normally number devices.
>> >
>> > What's stopping you from simply doing:
>> >
>> >         pwm1: pwm1@40010000 {
>> >                 compatible = "st,stm32-pwm";
>> >         };
>> >         pwm2: pwm1@40020000 {
>> >                 compatible = "st,stm32-pwm";
>> >         };
>> >         pwm3: pwm1@40030000 {
>> >                 compatible = "st,stm32-pwm";
>> >         };
>> >
>>
>> Because each instance of the hardware is slightly different: number of
>> pwm channels, triggers capabilities, etc ..
>> so I need to distinguish them.
>> Since it look to be a problem I will follow your suggestion and add a
>> property this driver to be able to identify each instance.
>> Do you think that "id" parameter (integer for 1 to 14) is acceptable ?
>
> Unfortunately not. IDs aren't allowed in DT.
>
> What about "pwm-chans" and "trigger"?
>
> pwm-chans              : Number of available channels available

For pwm I need those 4 properties:
st,pwm-number: the number of PWM devices
st,complementary: if exist have complementary ouput
st,32bit-counter: if exist have 32 bits counter
st,breakinput-polarity: if set enable break input feature.

Is it acceptable from pwm maintainer point of view ?

> trigger                : Boolean value specifying whether a timer is present

Following our discussion on IRC I will try to code for your proposal:

advanced-timer@40010000 {
        compatible = "st,stm32-advanced-timer";
        reg = <0x40010000 0x400>;
        clocks = <&rcc 0 160>;
        clock-names = "clk_int";

        pwm@0 {
                compatible = "st,stm32-pwm";
                st,pwm-number= <4>;
                st,complementary;
                st,breakinput;
        };

        timer@0 {
                reg = <1>;
                compatible = "st,stm32-iio-timer";
                interrupts = <27>;
                triggers = <5 2 3 4>;
        };
};

triggers parameter will be used to know which trigger are valid for
the IIO device

[snip]

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 1/7] add binding for stm32 multifunctions timer driver
@ 2016-11-23 17:02           ` Benjamin Gaignard
  0 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-23 17:02 UTC (permalink / raw)
  To: Lee Jones
  Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, Mark Rutland,
	alexandre.torgue-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA,
	Linux Kernel Mailing List, Thierry Reding,
	linux-pwm-u79uwXL29TY76Z2rM5mHXA, jic23-DgEjT+Ai2ygdnm+yROfE0A,
	knaack.h-Mmb7MZpHnFY, Lars-Peter Clausen, Peter Meerwald-Stadler,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Fabrice Gasnier, Gerald Baeza, Arnaud Pouliquen, Linus Walleij,
	Linaro Kernel Mailman List, Benjamin Gaignard

2016-11-23 10:21 GMT+01:00 Lee Jones <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>:
> On Wed, 23 Nov 2016, Benjamin Gaignard wrote:
>
>> 2016-11-22 17:52 GMT+01:00 Lee Jones <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>:
>> > On Tue, 22 Nov 2016, Benjamin Gaignard wrote:
>> >
>> >> Add bindings information for stm32 timer MFD
>> >>
>> >> Signed-off-by: Benjamin Gaignard <benjamin.gaignard-qxv4g6HH51o@public.gmane.org>
>> >> ---
>> >>  .../devicetree/bindings/mfd/stm32-timer.txt        | 53 ++++++++++++++++++++++
>> >>  1 file changed, 53 insertions(+)
>> >>  create mode 100644 Documentation/devicetree/bindings/mfd/stm32-timer.txt
>> >>
>> >> diff --git a/Documentation/devicetree/bindings/mfd/stm32-timer.txt b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
>> >> new file mode 100644
>> >> index 0000000..3cefce1
>> >> --- /dev/null
>> >> +++ b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
>> >> @@ -0,0 +1,53 @@
>> >> +STM32 multifunctions timer driver
>> >
>> > "STM32 Multi-Function Timer/PWM device bindings"
>> >
>> > Doesn't this shared device have a better name?
>>
>> In SoC documentation those hardware blocks are named "advanced-control
>> timers", "general purpose timers" or "basic timers"
>> "stm32-timer" name is already used for clock source driver, that why I
>> have prefix it with mfd
>
> MFD is a Linuxisum and has no place in hardware description.
>
> Please used one of the names you mentioned above.

I will go for "st,stm32-advanced-timer"

>
> Hopefully the one that best fits.
>
>> >> +stm32 timer MFD allow to handle at the same time pwm and IIO timer devices
>> >
>> > No need for this sentence.
>> >
>> OK
>>
>> >> +Required parameters:
>> >> +- compatible: must be one of the follow value:
>> >> +     "st,stm32-mfd-timer1"
>> >> +     "st,stm32-mfd-timer2"
>> >> +     "st,stm32-mfd-timer3"
>> >> +     "st,stm32-mfd-timer4"
>> >> +     "st,stm32-mfd-timer5"
>> >> +     "st,stm32-mfd-timer6"
>> >> +     "st,stm32-mfd-timer7"
>> >> +     "st,stm32-mfd-timer8"
>> >> +     "st,stm32-mfd-timer9"
>> >> +     "st,stm32-mfd-timer10"
>> >> +     "st,stm32-mfd-timer11"
>> >> +     "st,stm32-mfd-timer12"
>> >> +     "st,stm32-mfd-timer13"
>> >> +     "st,stm32-mfd-timer14"
>> >
>> > We don't normally number devices.
>> >
>> > What's stopping you from simply doing:
>> >
>> >         pwm1: pwm1@40010000 {
>> >                 compatible = "st,stm32-pwm";
>> >         };
>> >         pwm2: pwm1@40020000 {
>> >                 compatible = "st,stm32-pwm";
>> >         };
>> >         pwm3: pwm1@40030000 {
>> >                 compatible = "st,stm32-pwm";
>> >         };
>> >
>>
>> Because each instance of the hardware is slightly different: number of
>> pwm channels, triggers capabilities, etc ..
>> so I need to distinguish them.
>> Since it look to be a problem I will follow your suggestion and add a
>> property this driver to be able to identify each instance.
>> Do you think that "id" parameter (integer for 1 to 14) is acceptable ?
>
> Unfortunately not. IDs aren't allowed in DT.
>
> What about "pwm-chans" and "trigger"?
>
> pwm-chans              : Number of available channels available

For pwm I need those 4 properties:
st,pwm-number: the number of PWM devices
st,complementary: if exist have complementary ouput
st,32bit-counter: if exist have 32 bits counter
st,breakinput-polarity: if set enable break input feature.

Is it acceptable from pwm maintainer point of view ?

> trigger                : Boolean value specifying whether a timer is present

Following our discussion on IRC I will try to code for your proposal:

advanced-timer@40010000 {
        compatible = "st,stm32-advanced-timer";
        reg = <0x40010000 0x400>;
        clocks = <&rcc 0 160>;
        clock-names = "clk_int";

        pwm@0 {
                compatible = "st,stm32-pwm";
                st,pwm-number= <4>;
                st,complementary;
                st,breakinput;
        };

        timer@0 {
                reg = <1>;
                compatible = "st,stm32-iio-timer";
                interrupts = <27>;
                triggers = <5 2 3 4>;
        };
};

triggers parameter will be used to know which trigger are valid for
the IIO device

[snip]

^ permalink raw reply	[flat|nested] 64+ messages in thread

* [PATCH 1/7] add binding for stm32 multifunctions timer driver
@ 2016-11-23 17:02           ` Benjamin Gaignard
  0 siblings, 0 replies; 64+ messages in thread
From: Benjamin Gaignard @ 2016-11-23 17:02 UTC (permalink / raw)
  To: linux-arm-kernel

2016-11-23 10:21 GMT+01:00 Lee Jones <lee.jones@linaro.org>:
> On Wed, 23 Nov 2016, Benjamin Gaignard wrote:
>
>> 2016-11-22 17:52 GMT+01:00 Lee Jones <lee.jones@linaro.org>:
>> > On Tue, 22 Nov 2016, Benjamin Gaignard wrote:
>> >
>> >> Add bindings information for stm32 timer MFD
>> >>
>> >> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
>> >> ---
>> >>  .../devicetree/bindings/mfd/stm32-timer.txt        | 53 ++++++++++++++++++++++
>> >>  1 file changed, 53 insertions(+)
>> >>  create mode 100644 Documentation/devicetree/bindings/mfd/stm32-timer.txt
>> >>
>> >> diff --git a/Documentation/devicetree/bindings/mfd/stm32-timer.txt b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
>> >> new file mode 100644
>> >> index 0000000..3cefce1
>> >> --- /dev/null
>> >> +++ b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
>> >> @@ -0,0 +1,53 @@
>> >> +STM32 multifunctions timer driver
>> >
>> > "STM32 Multi-Function Timer/PWM device bindings"
>> >
>> > Doesn't this shared device have a better name?
>>
>> In SoC documentation those hardware blocks are named "advanced-control
>> timers", "general purpose timers" or "basic timers"
>> "stm32-timer" name is already used for clock source driver, that why I
>> have prefix it with mfd
>
> MFD is a Linuxisum and has no place in hardware description.
>
> Please used one of the names you mentioned above.

I will go for "st,stm32-advanced-timer"

>
> Hopefully the one that best fits.
>
>> >> +stm32 timer MFD allow to handle at the same time pwm and IIO timer devices
>> >
>> > No need for this sentence.
>> >
>> OK
>>
>> >> +Required parameters:
>> >> +- compatible: must be one of the follow value:
>> >> +     "st,stm32-mfd-timer1"
>> >> +     "st,stm32-mfd-timer2"
>> >> +     "st,stm32-mfd-timer3"
>> >> +     "st,stm32-mfd-timer4"
>> >> +     "st,stm32-mfd-timer5"
>> >> +     "st,stm32-mfd-timer6"
>> >> +     "st,stm32-mfd-timer7"
>> >> +     "st,stm32-mfd-timer8"
>> >> +     "st,stm32-mfd-timer9"
>> >> +     "st,stm32-mfd-timer10"
>> >> +     "st,stm32-mfd-timer11"
>> >> +     "st,stm32-mfd-timer12"
>> >> +     "st,stm32-mfd-timer13"
>> >> +     "st,stm32-mfd-timer14"
>> >
>> > We don't normally number devices.
>> >
>> > What's stopping you from simply doing:
>> >
>> >         pwm1: pwm1 at 40010000 {
>> >                 compatible = "st,stm32-pwm";
>> >         };
>> >         pwm2: pwm1 at 40020000 {
>> >                 compatible = "st,stm32-pwm";
>> >         };
>> >         pwm3: pwm1 at 40030000 {
>> >                 compatible = "st,stm32-pwm";
>> >         };
>> >
>>
>> Because each instance of the hardware is slightly different: number of
>> pwm channels, triggers capabilities, etc ..
>> so I need to distinguish them.
>> Since it look to be a problem I will follow your suggestion and add a
>> property this driver to be able to identify each instance.
>> Do you think that "id" parameter (integer for 1 to 14) is acceptable ?
>
> Unfortunately not. IDs aren't allowed in DT.
>
> What about "pwm-chans" and "trigger"?
>
> pwm-chans              : Number of available channels available

For pwm I need those 4 properties:
st,pwm-number: the number of PWM devices
st,complementary: if exist have complementary ouput
st,32bit-counter: if exist have 32 bits counter
st,breakinput-polarity: if set enable break input feature.

Is it acceptable from pwm maintainer point of view ?

> trigger                : Boolean value specifying whether a timer is present

Following our discussion on IRC I will try to code for your proposal:

advanced-timer at 40010000 {
        compatible = "st,stm32-advanced-timer";
        reg = <0x40010000 0x400>;
        clocks = <&rcc 0 160>;
        clock-names = "clk_int";

        pwm at 0 {
                compatible = "st,stm32-pwm";
                st,pwm-number= <4>;
                st,complementary;
                st,breakinput;
        };

        timer at 0 {
                reg = <1>;
                compatible = "st,stm32-iio-timer";
                interrupts = <27>;
                triggers = <5 2 3 4>;
        };
};

triggers parameter will be used to know which trigger are valid for
the IIO device

[snip]

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 1/7] add binding for stm32 multifunctions timer driver
@ 2016-11-24  8:52             ` Lee Jones
  0 siblings, 0 replies; 64+ messages in thread
From: Lee Jones @ 2016-11-24  8:52 UTC (permalink / raw)
  To: Benjamin Gaignard
  Cc: robh+dt, Mark Rutland, alexandre.torgue, devicetree,
	Linux Kernel Mailing List, Thierry Reding, linux-pwm, jic23,
	knaack.h, Lars-Peter Clausen, Peter Meerwald-Stadler, linux-iio,
	linux-arm-kernel, Fabrice Gasnier, Gerald Baeza,
	Arnaud Pouliquen, Linus Walleij, Linaro Kernel Mailman List,
	Benjamin Gaignard

Rob,

Would you mind casting an eye on this please?

On Wed, 23 Nov 2016, Benjamin Gaignard wrote:
> 2016-11-23 10:21 GMT+01:00 Lee Jones <lee.jones@linaro.org>:
> > On Wed, 23 Nov 2016, Benjamin Gaignard wrote:
> >
> >> 2016-11-22 17:52 GMT+01:00 Lee Jones <lee.jones@linaro.org>:
> >> > On Tue, 22 Nov 2016, Benjamin Gaignard wrote:
> >> >
> >> >> Add bindings information for stm32 timer MFD
> >> >>
> >> >> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
> >> >> ---
> >> >>  .../devicetree/bindings/mfd/stm32-timer.txt        | 53 ++++++++++++++++++++++
> >> >>  1 file changed, 53 insertions(+)
> >> >>  create mode 100644 Documentation/devicetree/bindings/mfd/stm32-timer.txt
> >> >>
> >> >> diff --git a/Documentation/devicetree/bindings/mfd/stm32-timer.txt b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
> >> >> new file mode 100644
> >> >> index 0000000..3cefce1
> >> >> --- /dev/null
> >> >> +++ b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
> >> >> @@ -0,0 +1,53 @@
> >> >> +STM32 multifunctions timer driver
> >> >
> >> > "STM32 Multi-Function Timer/PWM device bindings"
> >> >
> >> > Doesn't this shared device have a better name?
> >>
> >> In SoC documentation those hardware blocks are named "advanced-control
> >> timers", "general purpose timers" or "basic timers"
> >> "stm32-timer" name is already used for clock source driver, that why I
> >> have prefix it with mfd
> >
> > MFD is a Linuxisum and has no place in hardware description.
> >
> > Please used one of the names you mentioned above.
> 
> I will go for "st,stm32-advanced-timer"
> 
> >
> > Hopefully the one that best fits.
> >
> >> >> +stm32 timer MFD allow to handle at the same time pwm and IIO timer devices
> >> >
> >> > No need for this sentence.
> >> >
> >> OK
> >>
> >> >> +Required parameters:
> >> >> +- compatible: must be one of the follow value:
> >> >> +     "st,stm32-mfd-timer1"
> >> >> +     "st,stm32-mfd-timer2"
> >> >> +     "st,stm32-mfd-timer3"
> >> >> +     "st,stm32-mfd-timer4"
> >> >> +     "st,stm32-mfd-timer5"
> >> >> +     "st,stm32-mfd-timer6"
> >> >> +     "st,stm32-mfd-timer7"
> >> >> +     "st,stm32-mfd-timer8"
> >> >> +     "st,stm32-mfd-timer9"
> >> >> +     "st,stm32-mfd-timer10"
> >> >> +     "st,stm32-mfd-timer11"
> >> >> +     "st,stm32-mfd-timer12"
> >> >> +     "st,stm32-mfd-timer13"
> >> >> +     "st,stm32-mfd-timer14"
> >> >
> >> > We don't normally number devices.
> >> >
> >> > What's stopping you from simply doing:
> >> >
> >> >         pwm1: pwm1@40010000 {
> >> >                 compatible = "st,stm32-pwm";
> >> >         };
> >> >         pwm2: pwm1@40020000 {
> >> >                 compatible = "st,stm32-pwm";
> >> >         };
> >> >         pwm3: pwm1@40030000 {
> >> >                 compatible = "st,stm32-pwm";
> >> >         };
> >> >
> >>
> >> Because each instance of the hardware is slightly different: number of
> >> pwm channels, triggers capabilities, etc ..
> >> so I need to distinguish them.
> >> Since it look to be a problem I will follow your suggestion and add a
> >> property this driver to be able to identify each instance.
> >> Do you think that "id" parameter (integer for 1 to 14) is acceptable ?
> >
> > Unfortunately not. IDs aren't allowed in DT.
> >
> > What about "pwm-chans" and "trigger"?
> >
> > pwm-chans              : Number of available channels available
> 
> For pwm I need those 4 properties:
> st,pwm-number: the number of PWM devices

st,pwm-num-chan is already documented.

Please use that instead of creating new properties.

> st,complementary: if exist have complementary ouput
> st,32bit-counter: if exist have 32 bits counter
> st,breakinput-polarity: if set enable break input feature.
> 
> Is it acceptable from pwm maintainer point of view ?
> 
> > trigger                : Boolean value specifying whether a timer is present
> 
> Following our discussion on IRC I will try to code for your proposal:
> 
> advanced-timer@40010000 {
>         compatible = "st,stm32-advanced-timer";
>         reg = <0x40010000 0x400>;
>         clocks = <&rcc 0 160>;
>         clock-names = "clk_int";
> 
>         pwm@0 {
>                 compatible = "st,stm32-pwm";
>                 st,pwm-number= <4>;
>                 st,complementary;
>                 st,breakinput;
>         };
> 
>         timer@0 {
>                 reg = <1>;
>                 compatible = "st,stm32-iio-timer";
>                 interrupts = <27>;
>                 triggers = <5 2 3 4>;
>         };
> };
> 
> triggers parameter will be used to know which trigger are valid for
> the IIO device

Except for "st,pwm-number" as mentioned above, this looks good to me.

Rob, would what do you think?

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 1/7] add binding for stm32 multifunctions timer driver
@ 2016-11-24  8:52             ` Lee Jones
  0 siblings, 0 replies; 64+ messages in thread
From: Lee Jones @ 2016-11-24  8:52 UTC (permalink / raw)
  To: Benjamin Gaignard
  Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, Mark Rutland,
	alexandre.torgue-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA,
	Linux Kernel Mailing List, Thierry Reding,
	linux-pwm-u79uwXL29TY76Z2rM5mHXA, jic23-DgEjT+Ai2ygdnm+yROfE0A,
	knaack.h-Mmb7MZpHnFY, Lars-Peter Clausen, Peter Meerwald-Stadler,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Fabrice Gasnier, Gerald Baeza, Arnaud Pouliquen, Linus Walleij,
	Linaro Kernel Mailman List, Benjamin Gaignard

Rob,

Would you mind casting an eye on this please?

On Wed, 23 Nov 2016, Benjamin Gaignard wrote:
> 2016-11-23 10:21 GMT+01:00 Lee Jones <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>:
> > On Wed, 23 Nov 2016, Benjamin Gaignard wrote:
> >
> >> 2016-11-22 17:52 GMT+01:00 Lee Jones <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>:
> >> > On Tue, 22 Nov 2016, Benjamin Gaignard wrote:
> >> >
> >> >> Add bindings information for stm32 timer MFD
> >> >>
> >> >> Signed-off-by: Benjamin Gaignard <benjamin.gaignard-qxv4g6HH51o@public.gmane.org>
> >> >> ---
> >> >>  .../devicetree/bindings/mfd/stm32-timer.txt        | 53 ++++++++++++++++++++++
> >> >>  1 file changed, 53 insertions(+)
> >> >>  create mode 100644 Documentation/devicetree/bindings/mfd/stm32-timer.txt
> >> >>
> >> >> diff --git a/Documentation/devicetree/bindings/mfd/stm32-timer.txt b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
> >> >> new file mode 100644
> >> >> index 0000000..3cefce1
> >> >> --- /dev/null
> >> >> +++ b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
> >> >> @@ -0,0 +1,53 @@
> >> >> +STM32 multifunctions timer driver
> >> >
> >> > "STM32 Multi-Function Timer/PWM device bindings"
> >> >
> >> > Doesn't this shared device have a better name?
> >>
> >> In SoC documentation those hardware blocks are named "advanced-control
> >> timers", "general purpose timers" or "basic timers"
> >> "stm32-timer" name is already used for clock source driver, that why I
> >> have prefix it with mfd
> >
> > MFD is a Linuxisum and has no place in hardware description.
> >
> > Please used one of the names you mentioned above.
> 
> I will go for "st,stm32-advanced-timer"
> 
> >
> > Hopefully the one that best fits.
> >
> >> >> +stm32 timer MFD allow to handle at the same time pwm and IIO timer devices
> >> >
> >> > No need for this sentence.
> >> >
> >> OK
> >>
> >> >> +Required parameters:
> >> >> +- compatible: must be one of the follow value:
> >> >> +     "st,stm32-mfd-timer1"
> >> >> +     "st,stm32-mfd-timer2"
> >> >> +     "st,stm32-mfd-timer3"
> >> >> +     "st,stm32-mfd-timer4"
> >> >> +     "st,stm32-mfd-timer5"
> >> >> +     "st,stm32-mfd-timer6"
> >> >> +     "st,stm32-mfd-timer7"
> >> >> +     "st,stm32-mfd-timer8"
> >> >> +     "st,stm32-mfd-timer9"
> >> >> +     "st,stm32-mfd-timer10"
> >> >> +     "st,stm32-mfd-timer11"
> >> >> +     "st,stm32-mfd-timer12"
> >> >> +     "st,stm32-mfd-timer13"
> >> >> +     "st,stm32-mfd-timer14"
> >> >
> >> > We don't normally number devices.
> >> >
> >> > What's stopping you from simply doing:
> >> >
> >> >         pwm1: pwm1@40010000 {
> >> >                 compatible = "st,stm32-pwm";
> >> >         };
> >> >         pwm2: pwm1@40020000 {
> >> >                 compatible = "st,stm32-pwm";
> >> >         };
> >> >         pwm3: pwm1@40030000 {
> >> >                 compatible = "st,stm32-pwm";
> >> >         };
> >> >
> >>
> >> Because each instance of the hardware is slightly different: number of
> >> pwm channels, triggers capabilities, etc ..
> >> so I need to distinguish them.
> >> Since it look to be a problem I will follow your suggestion and add a
> >> property this driver to be able to identify each instance.
> >> Do you think that "id" parameter (integer for 1 to 14) is acceptable ?
> >
> > Unfortunately not. IDs aren't allowed in DT.
> >
> > What about "pwm-chans" and "trigger"?
> >
> > pwm-chans              : Number of available channels available
> 
> For pwm I need those 4 properties:
> st,pwm-number: the number of PWM devices

st,pwm-num-chan is already documented.

Please use that instead of creating new properties.

> st,complementary: if exist have complementary ouput
> st,32bit-counter: if exist have 32 bits counter
> st,breakinput-polarity: if set enable break input feature.
> 
> Is it acceptable from pwm maintainer point of view ?
> 
> > trigger                : Boolean value specifying whether a timer is present
> 
> Following our discussion on IRC I will try to code for your proposal:
> 
> advanced-timer@40010000 {
>         compatible = "st,stm32-advanced-timer";
>         reg = <0x40010000 0x400>;
>         clocks = <&rcc 0 160>;
>         clock-names = "clk_int";
> 
>         pwm@0 {
>                 compatible = "st,stm32-pwm";
>                 st,pwm-number= <4>;
>                 st,complementary;
>                 st,breakinput;
>         };
> 
>         timer@0 {
>                 reg = <1>;
>                 compatible = "st,stm32-iio-timer";
>                 interrupts = <27>;
>                 triggers = <5 2 3 4>;
>         };
> };
> 
> triggers parameter will be used to know which trigger are valid for
> the IIO device

Except for "st,pwm-number" as mentioned above, this looks good to me.

Rob, would what do you think?

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 64+ messages in thread

* [PATCH 1/7] add binding for stm32 multifunctions timer driver
@ 2016-11-24  8:52             ` Lee Jones
  0 siblings, 0 replies; 64+ messages in thread
From: Lee Jones @ 2016-11-24  8:52 UTC (permalink / raw)
  To: linux-arm-kernel

Rob,

Would you mind casting an eye on this please?

On Wed, 23 Nov 2016, Benjamin Gaignard wrote:
> 2016-11-23 10:21 GMT+01:00 Lee Jones <lee.jones@linaro.org>:
> > On Wed, 23 Nov 2016, Benjamin Gaignard wrote:
> >
> >> 2016-11-22 17:52 GMT+01:00 Lee Jones <lee.jones@linaro.org>:
> >> > On Tue, 22 Nov 2016, Benjamin Gaignard wrote:
> >> >
> >> >> Add bindings information for stm32 timer MFD
> >> >>
> >> >> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
> >> >> ---
> >> >>  .../devicetree/bindings/mfd/stm32-timer.txt        | 53 ++++++++++++++++++++++
> >> >>  1 file changed, 53 insertions(+)
> >> >>  create mode 100644 Documentation/devicetree/bindings/mfd/stm32-timer.txt
> >> >>
> >> >> diff --git a/Documentation/devicetree/bindings/mfd/stm32-timer.txt b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
> >> >> new file mode 100644
> >> >> index 0000000..3cefce1
> >> >> --- /dev/null
> >> >> +++ b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
> >> >> @@ -0,0 +1,53 @@
> >> >> +STM32 multifunctions timer driver
> >> >
> >> > "STM32 Multi-Function Timer/PWM device bindings"
> >> >
> >> > Doesn't this shared device have a better name?
> >>
> >> In SoC documentation those hardware blocks are named "advanced-control
> >> timers", "general purpose timers" or "basic timers"
> >> "stm32-timer" name is already used for clock source driver, that why I
> >> have prefix it with mfd
> >
> > MFD is a Linuxisum and has no place in hardware description.
> >
> > Please used one of the names you mentioned above.
> 
> I will go for "st,stm32-advanced-timer"
> 
> >
> > Hopefully the one that best fits.
> >
> >> >> +stm32 timer MFD allow to handle at the same time pwm and IIO timer devices
> >> >
> >> > No need for this sentence.
> >> >
> >> OK
> >>
> >> >> +Required parameters:
> >> >> +- compatible: must be one of the follow value:
> >> >> +     "st,stm32-mfd-timer1"
> >> >> +     "st,stm32-mfd-timer2"
> >> >> +     "st,stm32-mfd-timer3"
> >> >> +     "st,stm32-mfd-timer4"
> >> >> +     "st,stm32-mfd-timer5"
> >> >> +     "st,stm32-mfd-timer6"
> >> >> +     "st,stm32-mfd-timer7"
> >> >> +     "st,stm32-mfd-timer8"
> >> >> +     "st,stm32-mfd-timer9"
> >> >> +     "st,stm32-mfd-timer10"
> >> >> +     "st,stm32-mfd-timer11"
> >> >> +     "st,stm32-mfd-timer12"
> >> >> +     "st,stm32-mfd-timer13"
> >> >> +     "st,stm32-mfd-timer14"
> >> >
> >> > We don't normally number devices.
> >> >
> >> > What's stopping you from simply doing:
> >> >
> >> >         pwm1: pwm1 at 40010000 {
> >> >                 compatible = "st,stm32-pwm";
> >> >         };
> >> >         pwm2: pwm1 at 40020000 {
> >> >                 compatible = "st,stm32-pwm";
> >> >         };
> >> >         pwm3: pwm1 at 40030000 {
> >> >                 compatible = "st,stm32-pwm";
> >> >         };
> >> >
> >>
> >> Because each instance of the hardware is slightly different: number of
> >> pwm channels, triggers capabilities, etc ..
> >> so I need to distinguish them.
> >> Since it look to be a problem I will follow your suggestion and add a
> >> property this driver to be able to identify each instance.
> >> Do you think that "id" parameter (integer for 1 to 14) is acceptable ?
> >
> > Unfortunately not. IDs aren't allowed in DT.
> >
> > What about "pwm-chans" and "trigger"?
> >
> > pwm-chans              : Number of available channels available
> 
> For pwm I need those 4 properties:
> st,pwm-number: the number of PWM devices

st,pwm-num-chan is already documented.

Please use that instead of creating new properties.

> st,complementary: if exist have complementary ouput
> st,32bit-counter: if exist have 32 bits counter
> st,breakinput-polarity: if set enable break input feature.
> 
> Is it acceptable from pwm maintainer point of view ?
> 
> > trigger                : Boolean value specifying whether a timer is present
> 
> Following our discussion on IRC I will try to code for your proposal:
> 
> advanced-timer at 40010000 {
>         compatible = "st,stm32-advanced-timer";
>         reg = <0x40010000 0x400>;
>         clocks = <&rcc 0 160>;
>         clock-names = "clk_int";
> 
>         pwm at 0 {
>                 compatible = "st,stm32-pwm";
>                 st,pwm-number= <4>;
>                 st,complementary;
>                 st,breakinput;
>         };
> 
>         timer at 0 {
>                 reg = <1>;
>                 compatible = "st,stm32-iio-timer";
>                 interrupts = <27>;
>                 triggers = <5 2 3 4>;
>         };
> };
> 
> triggers parameter will be used to know which trigger are valid for
> the IIO device

Except for "st,pwm-number" as mentioned above, this looks good to me.

Rob, would what do you think?

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 5/7] add bindings for stm32 IIO timer drivers
@ 2016-11-28 21:44             ` Rob Herring
  0 siblings, 0 replies; 64+ messages in thread
From: Rob Herring @ 2016-11-28 21:44 UTC (permalink / raw)
  To: Benjamin Gaignard
  Cc: Lee Jones, Lars-Peter Clausen, Mark Rutland, alexandre.torgue,
	devicetree, Linux Kernel Mailing List, Thierry Reding, linux-pwm,
	jic23, knaack.h, Peter Meerwald-Stadler, linux-iio,
	linux-arm-kernel, Fabrice Gasnier, Gerald Baeza,
	Arnaud Pouliquen, Linus Walleij, Linaro Kernel Mailman List,
	Benjamin Gaignard

On Wed, Nov 23, 2016 at 09:17:58AM +0100, Benjamin Gaignard wrote:
> If it is ok for you I will add "id" parameter in mfd driver and
> forward it to the sub-devices drivers
> to be able to distinguish the hardware blocks

Please don't top post.

No, it's not okay. If the counter sizes are different, then have a 
property for the counter size. Describe how they are different without 
numbering them. If you can't describe the differences, then it shouldn't 
matter which ones the OS picks to use.

> 2016-11-22 18:18 GMT+01:00 Lee Jones <lee.jones@linaro.org>:
> > On Tue, 22 Nov 2016, Benjamin Gaignard wrote:
> >
> >> [snip]
> >> >> +     "st,stm32-iio-timer5"
> >> >> +     "st,stm32-iio-timer6"
> >> >> +     "st,stm32-iio-timer7"
> >> >> +     "st,stm32-iio-timer8"
> >> >> +     "st,stm32-iio-timer9"
> >> >> +     "st,stm32-iio-timer10"
> >> >> +     "st,stm32-iio-timer11"
> >> >> +     "st,stm32-iio-timer12"
> >> >> +     "st,stm32-iio-timer13"
> >> >> +     "st,stm32-iio-timer14"

I doubt the h/w manual calls these "IIO timers".

> >> >
> >> > We can't do this. This is a binding for a driver, not for the hardware.
> >> >
> >>
> >> Unfortunately each instance for the hardware IP have little
> >> differences like which triggers they could accept or size of the
> >> counter register,
> >> and I doesn't have value inside the hardware to distinguish them so
> >> the only way I found is to use compatible.
> >
> > Can't you represent these as properties?
> >
> > --
> > Lee Jones
> > Linaro STMicroelectronics Landing Team Lead
> > Linaro.org │ Open source software for ARM SoCs
> > Follow Linaro: Facebook | Twitter | Blog
> 
> 
> 
> -- 
> Benjamin Gaignard
> 
> Graphic Study Group
> 
> Linaro.org │ Open source software for ARM SoCs
> 
> Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 64+ messages in thread

* Re: [PATCH 5/7] add bindings for stm32 IIO timer drivers
@ 2016-11-28 21:44             ` Rob Herring
  0 siblings, 0 replies; 64+ messages in thread
From: Rob Herring @ 2016-11-28 21:44 UTC (permalink / raw)
  To: Benjamin Gaignard
  Cc: Lee Jones, Lars-Peter Clausen, Mark Rutland,
	alexandre.torgue-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA,
	Linux Kernel Mailing List, Thierry Reding,
	linux-pwm-u79uwXL29TY76Z2rM5mHXA, jic23-DgEjT+Ai2ygdnm+yROfE0A,
	knaack.h-Mmb7MZpHnFY, Peter Meerwald-Stadler,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Fabrice Gasnier, Gerald Baeza, Arnaud Pouliquen, Linus Walleij,
	Linaro Kernel Mailman List, Benjamin Gaignard

On Wed, Nov 23, 2016 at 09:17:58AM +0100, Benjamin Gaignard wrote:
> If it is ok for you I will add "id" parameter in mfd driver and
> forward it to the sub-devices drivers
> to be able to distinguish the hardware blocks

Please don't top post.

No, it's not okay. If the counter sizes are different, then have a 
property for the counter size. Describe how they are different without 
numbering them. If you can't describe the differences, then it shouldn't 
matter which ones the OS picks to use.

> 2016-11-22 18:18 GMT+01:00 Lee Jones <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>:
> > On Tue, 22 Nov 2016, Benjamin Gaignard wrote:
> >
> >> [snip]
> >> >> +     "st,stm32-iio-timer5"
> >> >> +     "st,stm32-iio-timer6"
> >> >> +     "st,stm32-iio-timer7"
> >> >> +     "st,stm32-iio-timer8"
> >> >> +     "st,stm32-iio-timer9"
> >> >> +     "st,stm32-iio-timer10"
> >> >> +     "st,stm32-iio-timer11"
> >> >> +     "st,stm32-iio-timer12"
> >> >> +     "st,stm32-iio-timer13"
> >> >> +     "st,stm32-iio-timer14"

I doubt the h/w manual calls these "IIO timers".

> >> >
> >> > We can't do this. This is a binding for a driver, not for the hardware.
> >> >
> >>
> >> Unfortunately each instance for the hardware IP have little
> >> differences like which triggers they could accept or size of the
> >> counter register,
> >> and I doesn't have value inside the hardware to distinguish them so
> >> the only way I found is to use compatible.
> >
> > Can't you represent these as properties?
> >
> > --
> > Lee Jones
> > Linaro STMicroelectronics Landing Team Lead
> > Linaro.org │ Open source software for ARM SoCs
> > Follow Linaro: Facebook | Twitter | Blog
> 
> 
> 
> -- 
> Benjamin Gaignard
> 
> Graphic Study Group
> 
> Linaro.org │ Open source software for ARM SoCs
> 
> Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 64+ messages in thread

* [PATCH 5/7] add bindings for stm32 IIO timer drivers
@ 2016-11-28 21:44             ` Rob Herring
  0 siblings, 0 replies; 64+ messages in thread
From: Rob Herring @ 2016-11-28 21:44 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Nov 23, 2016 at 09:17:58AM +0100, Benjamin Gaignard wrote:
> If it is ok for you I will add "id" parameter in mfd driver and
> forward it to the sub-devices drivers
> to be able to distinguish the hardware blocks

Please don't top post.

No, it's not okay. If the counter sizes are different, then have a 
property for the counter size. Describe how they are different without 
numbering them. If you can't describe the differences, then it shouldn't 
matter which ones the OS picks to use.

> 2016-11-22 18:18 GMT+01:00 Lee Jones <lee.jones@linaro.org>:
> > On Tue, 22 Nov 2016, Benjamin Gaignard wrote:
> >
> >> [snip]
> >> >> +     "st,stm32-iio-timer5"
> >> >> +     "st,stm32-iio-timer6"
> >> >> +     "st,stm32-iio-timer7"
> >> >> +     "st,stm32-iio-timer8"
> >> >> +     "st,stm32-iio-timer9"
> >> >> +     "st,stm32-iio-timer10"
> >> >> +     "st,stm32-iio-timer11"
> >> >> +     "st,stm32-iio-timer12"
> >> >> +     "st,stm32-iio-timer13"
> >> >> +     "st,stm32-iio-timer14"

I doubt the h/w manual calls these "IIO timers".

> >> >
> >> > We can't do this. This is a binding for a driver, not for the hardware.
> >> >
> >>
> >> Unfortunately each instance for the hardware IP have little
> >> differences like which triggers they could accept or size of the
> >> counter register,
> >> and I doesn't have value inside the hardware to distinguish them so
> >> the only way I found is to use compatible.
> >
> > Can't you represent these as properties?
> >
> > --
> > Lee Jones
> > Linaro STMicroelectronics Landing Team Lead
> > Linaro.org ? Open source software for ARM SoCs
> > Follow Linaro: Facebook | Twitter | Blog
> 
> 
> 
> -- 
> Benjamin Gaignard
> 
> Graphic Study Group
> 
> Linaro.org ? Open source software for ARM SoCs
> 
> Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 64+ messages in thread

end of thread, other threads:[~2016-11-28 21:45 UTC | newest]

Thread overview: 64+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-11-22 16:13 [PATCH 0/7] Add pwm and IIO timer drivers for stm32 Benjamin Gaignard
2016-11-22 16:13 ` Benjamin Gaignard
2016-11-22 16:13 ` [PATCH 1/7] add binding for stm32 multifunctions timer driver Benjamin Gaignard
2016-11-22 16:13   ` Benjamin Gaignard
2016-11-22 16:13   ` Benjamin Gaignard
2016-11-22 16:52   ` Lee Jones
2016-11-22 16:52     ` Lee Jones
2016-11-23  8:15     ` Benjamin Gaignard
2016-11-23  8:15       ` Benjamin Gaignard
2016-11-23  9:21       ` Lee Jones
2016-11-23  9:21         ` Lee Jones
2016-11-23 17:02         ` Benjamin Gaignard
2016-11-23 17:02           ` Benjamin Gaignard
2016-11-23 17:02           ` Benjamin Gaignard
2016-11-24  8:52           ` Lee Jones
2016-11-24  8:52             ` Lee Jones
2016-11-24  8:52             ` Lee Jones
2016-11-22 16:13 ` [PATCH 2/7] add MFD for stm32 timer IP Benjamin Gaignard
2016-11-22 16:13   ` Benjamin Gaignard
2016-11-22 16:13   ` Benjamin Gaignard
2016-11-22 16:30   ` Lee Jones
2016-11-22 16:30     ` Lee Jones
2016-11-22 16:41     ` Lee Jones
2016-11-22 16:41       ` Lee Jones
2016-11-22 16:41       ` Lee Jones
2016-11-22 16:40       ` Benjamin Gaignard
2016-11-22 16:40         ` Benjamin Gaignard
2016-11-22 16:40         ` Benjamin Gaignard
2016-11-22 16:13 ` [PATCH 3/7] add pwm-stm32 DT bindings Benjamin Gaignard
2016-11-22 16:13   ` Benjamin Gaignard
2016-11-22 16:13   ` Benjamin Gaignard
2016-11-22 16:13 ` [PATCH 4/7] add pwm driver for stm32 plaftorm Benjamin Gaignard
2016-11-22 16:13   ` Benjamin Gaignard
2016-11-22 16:13   ` Benjamin Gaignard
2016-11-22 16:13 ` [PATCH 5/7] add bindings for stm32 IIO timer drivers Benjamin Gaignard
2016-11-22 16:13   ` Benjamin Gaignard
2016-11-22 16:53   ` Lars-Peter Clausen
2016-11-22 16:53     ` Lars-Peter Clausen
2016-11-22 16:53     ` Lars-Peter Clausen
2016-11-22 17:01     ` Benjamin Gaignard
2016-11-22 17:01       ` Benjamin Gaignard
2016-11-22 17:02       ` Lars-Peter Clausen
2016-11-22 17:02         ` Lars-Peter Clausen
2016-11-22 17:02         ` Lars-Peter Clausen
2016-11-22 17:18       ` Lee Jones
2016-11-22 17:18         ` Lee Jones
2016-11-22 17:18         ` Lee Jones
2016-11-23  8:17         ` Benjamin Gaignard
2016-11-23  8:17           ` Benjamin Gaignard
2016-11-23  8:17           ` Benjamin Gaignard
2016-11-23  8:17           ` Benjamin Gaignard
2016-11-28 21:44           ` Rob Herring
2016-11-28 21:44             ` Rob Herring
2016-11-28 21:44             ` Rob Herring
2016-11-22 16:13 ` [PATCH 6/7] add STM32 IIO timer driver Benjamin Gaignard
2016-11-22 16:13   ` Benjamin Gaignard
2016-11-22 16:13 ` [PATCH 7/7] add stm32 multi-functions timer driver in DT Benjamin Gaignard
2016-11-22 16:13   ` Benjamin Gaignard
2016-11-22 17:00   ` Alexandre Torgue
2016-11-22 17:00     ` Alexandre Torgue
2016-11-22 17:00     ` Alexandre Torgue
2016-11-23  9:53   ` Lee Jones
2016-11-23  9:53     ` Lee Jones
2016-11-23  9:53     ` Lee Jones

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.