* [RFC PATCH 1/2] arm64: dts: add MUSB node to Allwinner A64 dtsi
From: Icenowy Zheng @ 2016-11-22 16:59 UTC (permalink / raw)
To: linux-arm-kernel
Allwinner A64 SoC has a MUSB controller like the one in A33, so add
a node for it, just use the compatible of A33 MUSB.
Host mode is tested to work properly on Pine64 and will be added into
the device tree of Pine64 in next patch.
Peripheral mode is also tested on Pine64, by changing dr_mode property
of usb_otg node and use a non-standard USB Type-A to Type-A cable.
Signed-off-by: Icenowy Zheng <icenowy@aosc.xyz>
---
This patchset depends on my patch which adds usbphy to A64 dtsi.
( http://lists.infradead.org/pipermail/linux-arm-kernel/2016-November/469561.html )
arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
index 2572dd6..261324a 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
@@ -122,6 +122,19 @@
#size-cells = <1>;
ranges;
+ usb_otg: usb at 01c19000 {
+ compatible = "allwinner,sun8i-a33-musb";
+ reg = <0x01c19000 0x0400>;
+ clocks = <&ccu CLK_BUS_OTG>;
+ resets = <&ccu RST_BUS_OTG>;
+ interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "mc";
+ phys = <&usbphy 0>;
+ phy-names = "usb";
+ extcon = <&usbphy 0>;
+ status = "disabled";
+ };
+
usbphy: phy at 01c19400 {
compatible = "allwinner,sun50i-a64-usb-phy";
reg = <0x01c19400 0x14>,
--
2.10.2
^ permalink raw reply related
* [RFC PATCH 11/11] ARM: Allow ARCH_MULTIPLATFORM to be selected for NOMMU
From: Vladimir Murzin @ 2016-11-22 16:57 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <16587553.f9R1mxJih5@wuerfel>
On 22/11/16 10:17, Arnd Bergmann wrote:
> On Tuesday, November 22, 2016 9:26:08 AM CET Vladimir Murzin wrote:
>> With this patch applied potentially any platform can be built in NOMMU
>> configurations if CONFIG_EXPERT is selected. However, there is no
>> guaranty that platform can successfully run such Image. So the main
>> motivation behind of this patch:
>> - bring build coverage for NOMMU configurations
>> - allow known working NOMMU platforms (like R-class) to be used
>> - pave a way to add support for single address space (aka 1:1 mapping)
>> for MMU platforms, so they can be usable in NOMMU configurations
>>
>> Cc: Hartley Sweeten <hsweeten@visionengravers.com>
>> Cc: Ryan Mallon <rmallon@gmail.com>
>> Cc: Tony Lindgren <tony@atomide.com>
>> Cc: Thierry Reding <thierry.reding@gmail.com>
>> Cc: Russell King <linux@armlinux.org.uk>
>> Signed-off-by: Vladimir Murzin <vladimir.murzin@arm.com>
>
> I'd have to give this a spin with my randconfig build setup, I'd
> rather not introduce build regressions. Have you tried an
> allmodconfig build with CONFIG_MMU disabled?
I used defconfigs and just got results for allmodconfig apart of complain on
isb instruction in arch/arm/kernel/head-nommu.S [1] there are several link
time errors [2].
>
> Can you provide a git tree that I can try pulling in?
>
Unfortunately, I can't provide you with git tree at the moment I'll try to
do something around this before proposing the next version.
> Another question is what architecture levels and what platforms
> we want to support without MMU. The only ARMv4/v5 platform we
> still have that can actually use NOMMU cores is Integrator
> with its ARM7TDMI, ARM920T and ARM966E core tiles (and possibly
> others I couldn't immediately find). Do we actually care about
> them any more now that all the NOMMU world is ARMv7-M? Are
> there any benefits in running an ARM920T or ARM926E core
> with MMU disabled, and does this work with your patches?
>
I don't have such hardware, so I can't acctually test it - it is why "there is
no guaranty" :( OTOH, if sombody has these platforms these pathces is a good
start to try NOMMU.
> If not, we could limit it to ARMv7-A/R and possibly ARMv6.
> Depending on how the build tests go, a per-platform opt-in
> might be easier than having an opt-out for things that
> don't work.
>
> Arnd
>
[1]
AS arch/arm/kernel/head-nommu.o
arch/arm/kernel/head-nommu.S: Assembler messages:
arch/arm/kernel/head-nommu.S:223: Error: selected processor does not support ARM mode `isb'
arch/arm/kernel/head-nommu.S:231: Error: selected processor does not support ARM mode `isb'
arch/arm/kernel/head-nommu.S:235: Error: selected processor does not support ARM mode `isb'
arch/arm/kernel/head-nommu.S:244: Error: selected processor does not support ARM mode `isb'
arch/arm/kernel/head-nommu.S:248: Error: selected processor does not support ARM mode `isb'
arch/arm/kernel/head-nommu.S:258: Error: selected processor does not support ARM mode `isb'
arch/arm/kernel/head-nommu.S:265: Error: selected processor does not support ARM mode `isb'
make[1]: *** [arch/arm/kernel/head-nommu.o] Error 1
[2]
arch/arm/kernel/head-nommu.o: In function `secondary_startup':
(.text+0x1c): undefined reference to `__setup_mpu'
arch/arm/kernel/head-nommu.o: In function `stext':
(.head.text+0x30): undefined reference to `__setup_mpu'
arch/arm/kernel/built-in.o: In function `setup_arch':
arch/arm/kernel/smccc-call.o:(.init.text+0xa50): undefined reference to `erratum_a15_798181_init'
kernel/built-in.o: In function `kimage_free_entry':
memremap.c:(.text+0xd3d9c): undefined reference to `arch_phys_to_idmap_offset'
kernel/built-in.o: In function `kimage_alloc_page':
memremap.c:(.text+0xd4338): undefined reference to `arch_phys_to_idmap_offset'
kernel/built-in.o: In function `kimage_alloc_control_pages':
memremap.c:(.text+0xd4ac8): undefined reference to `arch_phys_to_idmap_offset'
kernel/built-in.o: In function `kimage_load_segment':
memremap.c:(.text+0xd4f40): undefined reference to `arch_phys_to_idmap_offset'
kernel/built-in.o: In function `crash_free_reserved_phys_range':
memremap.c:(.text+0xd50bc): undefined reference to `arch_phys_to_idmap_offset'
arch/arm/mach-mediatek/built-in.o: In function `__mtk_smp_prepare_cpus':
mediatek.c:(.init.text+0xe8): undefined reference to `secondary_startup_arm'
arch/arm/mach-qcom/built-in.o: In function `qcom_smp_prepare_cpus':
platsmp.c:(.init.text+0xe8): undefined reference to `secondary_startup_arm'
mm/built-in.o: In function `do_mmu_notifier_register':
usercopy.c:(.text+0x34d10): undefined reference to `mm_take_all_locks'
usercopy.c:(.text+0x34d9c): undefined reference to `mm_drop_all_locks'
usercopy.c:(.text+0x34de4): undefined reference to `mm_take_all_locks'
make: *** [vmlinux] Error 1
Cheers
Vladimir
^ permalink raw reply
* [PATCH 5/7] add bindings for stm32 IIO timer drivers
From: Lars-Peter Clausen @ 2016-11-22 16:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479831207-32699-6-git-send-email-benjamin.gaignard@st.com>
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
* [PATCH 1/7] add binding for stm32 multifunctions timer driver
From: Lee Jones @ 2016-11-22 16:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479831207-32699-2-git-send-email-benjamin.gaignard@st.com>
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
* [PATCH net-next 4/4] ARM64: dts: marvell: Add network support for Armada 3700
From: Gregory CLEMENT @ 2016-11-22 16:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161122164844.19566-1-gregory.clement@free-electrons.com>
Add neta nodes for network support both in device tree for the SoC and
the board.
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
arch/arm64/boot/dts/marvell/armada-3720-db.dts | 23 +++++++++++++++++++++++
arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 23 +++++++++++++++++++++++
2 files changed, 46 insertions(+)
diff --git a/arch/arm64/boot/dts/marvell/armada-3720-db.dts b/arch/arm64/boot/dts/marvell/armada-3720-db.dts
index 1372e9a6aaa4..c8b82e4145de 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-db.dts
+++ b/arch/arm64/boot/dts/marvell/armada-3720-db.dts
@@ -81,3 +81,26 @@
&pcie0 {
status = "okay";
};
+
+&mdio {
+ status = "okay";
+ phy0: ethernet-phy at 0 {
+ reg = <0>;
+ };
+
+ phy1: ethernet-phy at 1 {
+ reg = <1>;
+ };
+};
+
+ð0 {
+ phy-mode = "rgmii-id";
+ phy = <&phy0>;
+ status = "okay";
+};
+
+ð1 {
+ phy-mode = "rgmii-id";
+ phy = <&phy1>;
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
index c4762538ec01..a7278ce9e523 100644
--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
@@ -140,6 +140,29 @@
};
};
+ eth0: ethernet at 30000 {
+ compatible = "marvell,armada-3700-neta";
+ reg = <0x30000 0x4000>;
+ interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&sb_periph_clk 8>;
+ status = "disabled";
+ };
+
+ mdio: mdio at 32004 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "marvell,orion-mdio";
+ reg = <0x32004 0x4>;
+ };
+
+ eth1: ethernet at 40000 {
+ compatible = "marvell,armada-3700-neta";
+ reg = <0x40000 0x4000>;
+ interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&sb_periph_clk 7>;
+ status = "disabled";
+ };
+
usb3: usb at 58000 {
compatible = "marvell,armada3700-xhci",
"generic-xhci";
--
2.10.2
^ permalink raw reply related
* [PATCH net-next 3/4] net: mvneta: Add network support for Armada 3700 SoC
From: Gregory CLEMENT @ 2016-11-22 16:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161122164844.19566-1-gregory.clement@free-electrons.com>
From: Marcin Wojtas <mw@semihalf.com>
Armada 3700 is a new ARMv8 SoC from Marvell using same network controller
as older Armada 370/38x/XP. There are however some differences that
needed taking into account when adding support for it:
* open default MBUS window to 4GB of DRAM - Armada 3700 SoC's Mbus
configuration for network controller has to be done on two levels:
global and per-port. The first one is inherited from the
bootloader. The latter can be opened in a default way, leaving
arbitration to the bus controller. Hence filled mbus_dram_target_info
structure is not needed
* make per-CPU operation optional - Recent patches adding RSS and XPS
support for Armada 38x/XP enabled per-CPU operation of the controller
by default. Contrary to older SoC's Armada 3700 SoC's network
controller is not capable of per-CPU processing due to interrupt lines'
connectivity. This patch restores non-per-CPU operation, which is now
optional and depends on neta_armada3700 flag value in mvneta_port
structure. In order not to complicate the code, separate interrupt
subroutine is implemented.
For now, on the Armada 3700, RSS is disabled as the current
implementation depend on precpu interrupt.
[gregory.clement at free-electrons.com: extract from a larger patch, replace
some ifdef and port to net-next for v4.10]
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
.../bindings/net/marvell-armada-370-neta.txt | 7 +-
drivers/net/ethernet/marvell/Kconfig | 7 +-
drivers/net/ethernet/marvell/mvneta.c | 287 +++++++++++++++------
3 files changed, 214 insertions(+), 87 deletions(-)
diff --git a/Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt b/Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt
index 73be8970815e..7aa840c8768d 100644
--- a/Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt
+++ b/Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt
@@ -1,7 +1,10 @@
-* Marvell Armada 370 / Armada XP Ethernet Controller (NETA)
+* Marvell Armada 370 / Armada XP / Armada 3700 Ethernet Controller (NETA)
Required properties:
-- compatible: "marvell,armada-370-neta" or "marvell,armada-xp-neta".
+- compatible: could be one of the followings
+ "marvell,armada-370-neta"
+ "marvell,armada-xp-neta"
+ "marvell,armada-3700-neta"
- reg: address and length of the register set for the device.
- interrupts: interrupt for the device
- phy: See ethernet.txt file in the same directory.
diff --git a/drivers/net/ethernet/marvell/Kconfig b/drivers/net/ethernet/marvell/Kconfig
index 2ccea9dd9248..3b8f11fe5e13 100644
--- a/drivers/net/ethernet/marvell/Kconfig
+++ b/drivers/net/ethernet/marvell/Kconfig
@@ -56,14 +56,15 @@ config MVNETA_BM_ENABLE
buffer management.
config MVNETA
- tristate "Marvell Armada 370/38x/XP network interface support"
- depends on PLAT_ORION || COMPILE_TEST
+ tristate "Marvell Armada 370/38x/XP/37xx network interface support"
+ depends on ARCH_MVEBU || COMPILE_TEST
depends on HAS_DMA
select MVMDIO
select FIXED_PHY
---help---
This driver supports the network interface units in the
- Marvell ARMADA XP, ARMADA 370 and ARMADA 38x SoC family.
+ Marvell ARMADA XP, ARMADA 370, ARMADA 38x and
+ ARMADA 37xx SoC family.
Note that this driver is distinct from the mv643xx_eth
driver, which should be used for the older Marvell SoCs
diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index 67f6465d96ba..7438ffd5639a 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -397,6 +397,9 @@ struct mvneta_port {
spinlock_t lock;
bool is_stopped;
+ u32 cause_rx_tx;
+ struct napi_struct napi;
+
/* Core clock */
struct clk *clk;
/* AXI clock */
@@ -422,6 +425,9 @@ struct mvneta_port {
u64 ethtool_stats[ARRAY_SIZE(mvneta_statistics)];
u32 indir[MVNETA_RSS_LU_TABLE_SIZE];
+
+ /* Flags for special SoC configurations */
+ bool neta_armada3700;
#ifdef CONFIG_64BIT
u64 data_high;
#endif
@@ -964,14 +970,9 @@ static int mvneta_mbus_io_win_set(struct mvneta_port *pp, u32 base, u32 wsize,
return 0;
}
-/* Assign and initialize pools for port. In case of fail
- * buffer manager will remain disabled for current port.
- */
-static int mvneta_bm_port_init(struct platform_device *pdev,
- struct mvneta_port *pp)
+static int mvneta_bm_port_mbus_init(struct mvneta_port *pp)
{
- struct device_node *dn = pdev->dev.of_node;
- u32 long_pool_id, short_pool_id, wsize;
+ u32 wsize;
u8 target, attr;
int err;
@@ -990,6 +991,25 @@ static int mvneta_bm_port_init(struct platform_device *pdev,
netdev_info(pp->dev, "fail to configure mbus window to BM\n");
return err;
}
+ return 0;
+}
+
+/* Assign and initialize pools for port. In case of fail
+ * buffer manager will remain disabled for current port.
+ */
+static int mvneta_bm_port_init(struct platform_device *pdev,
+ struct mvneta_port *pp)
+{
+ struct device_node *dn = pdev->dev.of_node;
+ u32 long_pool_id, short_pool_id;
+
+ if (!pp->neta_armada3700) {
+ int ret;
+
+ ret = mvneta_bm_port_mbus_init(pp);
+ if (ret)
+ return ret;
+ }
if (of_property_read_u32(dn, "bm,pool-long", &long_pool_id)) {
netdev_info(pp->dev, "missing long pool id\n");
@@ -1358,22 +1378,27 @@ static void mvneta_defaults_set(struct mvneta_port *pp)
for_each_present_cpu(cpu) {
int rxq_map = 0, txq_map = 0;
int rxq, txq;
+ if (!pp->neta_armada3700) {
+ for (rxq = 0; rxq < rxq_number; rxq++)
+ if ((rxq % max_cpu) == cpu)
+ rxq_map |= MVNETA_CPU_RXQ_ACCESS(rxq);
+
+ for (txq = 0; txq < txq_number; txq++)
+ if ((txq % max_cpu) == cpu)
+ txq_map |= MVNETA_CPU_TXQ_ACCESS(txq);
+
+ /* With only one TX queue we configure a special case
+ * which will allow to get all the irq on a single
+ * CPU
+ */
+ if (txq_number == 1)
+ txq_map = (cpu == pp->rxq_def) ?
+ MVNETA_CPU_TXQ_ACCESS(1) : 0;
- for (rxq = 0; rxq < rxq_number; rxq++)
- if ((rxq % max_cpu) == cpu)
- rxq_map |= MVNETA_CPU_RXQ_ACCESS(rxq);
-
- for (txq = 0; txq < txq_number; txq++)
- if ((txq % max_cpu) == cpu)
- txq_map |= MVNETA_CPU_TXQ_ACCESS(txq);
-
- /* With only one TX queue we configure a special case
- * which will allow to get all the irq on a single
- * CPU
- */
- if (txq_number == 1)
- txq_map = (cpu == pp->rxq_def) ?
- MVNETA_CPU_TXQ_ACCESS(1) : 0;
+ } else {
+ txq_map = MVNETA_CPU_TXQ_ACCESS_ALL_MASK;
+ rxq_map = MVNETA_CPU_RXQ_ACCESS_ALL_MASK;
+ }
mvreg_write(pp, MVNETA_CPU_MAP(cpu), rxq_map | txq_map);
}
@@ -2652,6 +2677,17 @@ static void mvneta_set_rx_mode(struct net_device *dev)
/* Interrupt handling - the callback for request_irq() */
static irqreturn_t mvneta_isr(int irq, void *dev_id)
{
+ struct mvneta_port *pp = (struct mvneta_port *)dev_id;
+
+ mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0);
+ napi_schedule(&pp->napi);
+
+ return IRQ_HANDLED;
+}
+
+/* Interrupt handling - the callback for request_percpu_irq() */
+static irqreturn_t mvneta_percpu_isr(int irq, void *dev_id)
+{
struct mvneta_pcpu_port *port = (struct mvneta_pcpu_port *)dev_id;
disable_percpu_irq(port->pp->dev->irq);
@@ -2699,7 +2735,7 @@ static int mvneta_poll(struct napi_struct *napi, int budget)
struct mvneta_pcpu_port *port = this_cpu_ptr(pp->ports);
if (!netif_running(pp->dev)) {
- napi_complete(&port->napi);
+ napi_complete(napi);
return rx_done;
}
@@ -2728,7 +2764,8 @@ static int mvneta_poll(struct napi_struct *napi, int budget)
*/
rx_queue = fls(((cause_rx_tx >> 8) & 0xff));
- cause_rx_tx |= port->cause_rx_tx;
+ cause_rx_tx |= pp->neta_armada3700 ? pp->cause_rx_tx :
+ port->cause_rx_tx;
if (rx_queue) {
rx_queue = rx_queue - 1;
@@ -2742,11 +2779,27 @@ static int mvneta_poll(struct napi_struct *napi, int budget)
if (budget > 0) {
cause_rx_tx = 0;
- napi_complete(&port->napi);
- enable_percpu_irq(pp->dev->irq, 0);
+ napi_complete(napi);
+
+ if (pp->neta_armada3700) {
+ unsigned long flags;
+
+ local_irq_save(flags);
+ mvreg_write(pp, MVNETA_INTR_NEW_MASK,
+ MVNETA_RX_INTR_MASK(rxq_number) |
+ MVNETA_TX_INTR_MASK(txq_number) |
+ MVNETA_MISCINTR_INTR_MASK);
+ local_irq_restore(flags);
+ } else {
+ enable_percpu_irq(pp->dev->irq, 0);
+ }
}
- port->cause_rx_tx = cause_rx_tx;
+ if (pp->neta_armada3700)
+ pp->cause_rx_tx = cause_rx_tx;
+ else
+ port->cause_rx_tx = cause_rx_tx;
+
return rx_done;
}
@@ -3032,11 +3085,16 @@ static void mvneta_start_dev(struct mvneta_port *pp)
/* start the Rx/Tx activity */
mvneta_port_enable(pp);
- /* Enable polling on the port */
- for_each_online_cpu(cpu) {
- struct mvneta_pcpu_port *port = per_cpu_ptr(pp->ports, cpu);
+ if (!pp->neta_armada3700) {
+ /* Enable polling on the port */
+ for_each_online_cpu(cpu) {
+ struct mvneta_pcpu_port *port =
+ per_cpu_ptr(pp->ports, cpu);
- napi_enable(&port->napi);
+ napi_enable(&port->napi);
+ }
+ } else {
+ napi_enable(&pp->napi);
}
/* Unmask interrupts. It has to be done from each CPU */
@@ -3058,10 +3116,15 @@ static void mvneta_stop_dev(struct mvneta_port *pp)
phy_stop(ndev->phydev);
- for_each_online_cpu(cpu) {
- struct mvneta_pcpu_port *port = per_cpu_ptr(pp->ports, cpu);
+ if (!pp->neta_armada3700) {
+ for_each_online_cpu(cpu) {
+ struct mvneta_pcpu_port *port =
+ per_cpu_ptr(pp->ports, cpu);
- napi_disable(&port->napi);
+ napi_disable(&port->napi);
+ }
+ } else {
+ napi_disable(&pp->napi);
}
netif_carrier_off(pp->dev);
@@ -3471,31 +3534,37 @@ static int mvneta_open(struct net_device *dev)
goto err_cleanup_rxqs;
/* Connect to port interrupt line */
- ret = request_percpu_irq(pp->dev->irq, mvneta_isr,
- MVNETA_DRIVER_NAME, pp->ports);
+ if (pp->neta_armada3700)
+ ret = request_irq(pp->dev->irq, mvneta_isr, 0,
+ dev->name, pp);
+ else
+ ret = request_percpu_irq(pp->dev->irq, mvneta_percpu_isr,
+ dev->name, pp->ports);
if (ret) {
netdev_err(pp->dev, "cannot request irq %d\n", pp->dev->irq);
goto err_cleanup_txqs;
}
- /* Enable per-CPU interrupt on all the CPU to handle our RX
- * queue interrupts
- */
- on_each_cpu(mvneta_percpu_enable, pp, true);
+ if (!pp->neta_armada3700) {
+ /* Enable per-CPU interrupt on all the CPU to handle our RX
+ * queue interrupts
+ */
+ on_each_cpu(mvneta_percpu_enable, pp, true);
- pp->is_stopped = false;
- /* Register a CPU notifier to handle the case where our CPU
- * might be taken offline.
- */
- ret = cpuhp_state_add_instance_nocalls(online_hpstate,
- &pp->node_online);
- if (ret)
- goto err_free_irq;
+ pp->is_stopped = false;
+ /* Register a CPU notifier to handle the case where our CPU
+ * might be taken offline.
+ */
+ ret = cpuhp_state_add_instance_nocalls(online_hpstate,
+ &pp->node_online);
+ if (ret)
+ goto err_free_irq;
- ret = cpuhp_state_add_instance_nocalls(CPUHP_NET_MVNETA_DEAD,
- &pp->node_dead);
- if (ret)
- goto err_free_online_hp;
+ ret = cpuhp_state_add_instance_nocalls(CPUHP_NET_MVNETA_DEAD,
+ &pp->node_dead);
+ if (ret)
+ goto err_free_online_hp;
+ }
/* In default link is down */
netif_carrier_off(pp->dev);
@@ -3511,13 +3580,20 @@ static int mvneta_open(struct net_device *dev)
return 0;
err_free_dead_hp:
- cpuhp_state_remove_instance_nocalls(CPUHP_NET_MVNETA_DEAD,
- &pp->node_dead);
+ if (!pp->neta_armada3700)
+ cpuhp_state_remove_instance_nocalls(CPUHP_NET_MVNETA_DEAD,
+ &pp->node_dead);
err_free_online_hp:
- cpuhp_state_remove_instance_nocalls(online_hpstate, &pp->node_online);
+ if (!pp->neta_armada3700)
+ cpuhp_state_remove_instance_nocalls(online_hpstate,
+ &pp->node_online);
err_free_irq:
- on_each_cpu(mvneta_percpu_disable, pp, true);
- free_percpu_irq(pp->dev->irq, pp->ports);
+ if (pp->neta_armada3700) {
+ free_irq(pp->dev->irq, pp);
+ } else {
+ on_each_cpu(mvneta_percpu_disable, pp, true);
+ free_percpu_irq(pp->dev->irq, pp->ports);
+ }
err_cleanup_txqs:
mvneta_cleanup_txqs(pp);
err_cleanup_rxqs:
@@ -3530,23 +3606,30 @@ static int mvneta_stop(struct net_device *dev)
{
struct mvneta_port *pp = netdev_priv(dev);
- /* Inform that we are stopping so we don't want to setup the
- * driver for new CPUs in the notifiers. The code of the
- * notifier for CPU online is protected by the same spinlock,
- * so when we get the lock, the notifer work is done.
- */
- spin_lock(&pp->lock);
- pp->is_stopped = true;
- spin_unlock(&pp->lock);
+ if (!pp->neta_armada3700) {
+ /* Inform that we are stopping so we don't want to setup the
+ * driver for new CPUs in the notifiers. The code of the
+ * notifier for CPU online is protected by the same spinlock,
+ * so when we get the lock, the notifer work is done.
+ */
+ spin_lock(&pp->lock);
+ pp->is_stopped = true;
+ spin_unlock(&pp->lock);
- mvneta_stop_dev(pp);
- mvneta_mdio_remove(pp);
+ mvneta_stop_dev(pp);
+ mvneta_mdio_remove(pp);
cpuhp_state_remove_instance_nocalls(online_hpstate, &pp->node_online);
cpuhp_state_remove_instance_nocalls(CPUHP_NET_MVNETA_DEAD,
&pp->node_dead);
- on_each_cpu(mvneta_percpu_disable, pp, true);
- free_percpu_irq(dev->irq, pp->ports);
+ on_each_cpu(mvneta_percpu_disable, pp, true);
+ free_percpu_irq(dev->irq, pp->ports);
+ } else {
+ mvneta_stop_dev(pp);
+ mvneta_mdio_remove(pp);
+ free_irq(dev->irq, pp);
+ }
+
mvneta_cleanup_rxqs(pp);
mvneta_cleanup_txqs(pp);
@@ -3825,6 +3908,11 @@ static int mvneta_ethtool_set_rxfh(struct net_device *dev, const u32 *indir,
const u8 *key, const u8 hfunc)
{
struct mvneta_port *pp = netdev_priv(dev);
+
+ /* Current code for Armada 3700 doesn't support RSS features yet */
+ if (pp->neta_armada3700)
+ return -EOPNOTSUPP;
+
/* We require at least one supported parameter to be changed
* and no change in any of the unsupported parameters
*/
@@ -3845,6 +3933,10 @@ static int mvneta_ethtool_get_rxfh(struct net_device *dev, u32 *indir, u8 *key,
{
struct mvneta_port *pp = netdev_priv(dev);
+ /* Current code for Armada 3700 doesn't support RSS features yet */
+ if (pp->neta_armada3700)
+ return -EOPNOTSUPP;
+
if (hfunc)
*hfunc = ETH_RSS_HASH_TOP;
@@ -3947,16 +4039,29 @@ static void mvneta_conf_mbus_windows(struct mvneta_port *pp,
win_enable = 0x3f;
win_protect = 0;
- for (i = 0; i < dram->num_cs; i++) {
- const struct mbus_dram_window *cs = dram->cs + i;
- mvreg_write(pp, MVNETA_WIN_BASE(i), (cs->base & 0xffff0000) |
- (cs->mbus_attr << 8) | dram->mbus_dram_target_id);
+ if (dram) {
+ for (i = 0; i < dram->num_cs; i++) {
+ const struct mbus_dram_window *cs = dram->cs + i;
+
+ mvreg_write(pp, MVNETA_WIN_BASE(i),
+ (cs->base & 0xffff0000) |
+ (cs->mbus_attr << 8) |
+ dram->mbus_dram_target_id);
- mvreg_write(pp, MVNETA_WIN_SIZE(i),
- (cs->size - 1) & 0xffff0000);
+ mvreg_write(pp, MVNETA_WIN_SIZE(i),
+ (cs->size - 1) & 0xffff0000);
- win_enable &= ~(1 << i);
- win_protect |= 3 << (2 * i);
+ win_enable &= ~(1 << i);
+ win_protect |= 3 << (2 * i);
+ }
+ } else {
+ /* For Armada3700 open default 4GB Mbus window, leaving
+ * arbitration of target/attribute to a different layer
+ * of configuration.
+ */
+ mvreg_write(pp, MVNETA_WIN_SIZE(0), 0xffff0000);
+ win_enable &= ~BIT(0);
+ win_protect = 3;
}
mvreg_write(pp, MVNETA_BASE_ADDR_ENABLE, win_enable);
@@ -4086,6 +4191,10 @@ static int mvneta_probe(struct platform_device *pdev)
pp->indir[0] = rxq_def;
+ /* Get special SoC configurations */
+ if (of_device_is_compatible(dn, "marvell,armada-3700-neta"))
+ pp->neta_armada3700 = true;
+
pp->clk = devm_clk_get(&pdev->dev, "core");
if (IS_ERR(pp->clk))
pp->clk = devm_clk_get(&pdev->dev, NULL);
@@ -4153,7 +4262,11 @@ static int mvneta_probe(struct platform_device *pdev)
pp->tx_csum_limit = tx_csum_limit;
dram_target_info = mv_mbus_dram_info();
- if (dram_target_info)
+ /* Armada3700 requires setting default configuration of Mbus
+ * windows, however without using filled mbus_dram_target_info
+ * structure.
+ */
+ if (dram_target_info || pp->neta_armada3700)
mvneta_conf_mbus_windows(pp, dram_target_info);
pp->tx_ring_size = MVNETA_MAX_TXD;
@@ -4186,11 +4299,20 @@ static int mvneta_probe(struct platform_device *pdev)
goto err_netdev;
}
- for_each_present_cpu(cpu) {
- struct mvneta_pcpu_port *port = per_cpu_ptr(pp->ports, cpu);
+ /* Armada3700 network controller does not support per-cpu
+ * operation, so only single NAPI should be initialized.
+ */
+ if (pp->neta_armada3700) {
+ netif_napi_add(dev, &pp->napi, mvneta_poll, NAPI_POLL_WEIGHT);
+ } else {
+ for_each_present_cpu(cpu) {
+ struct mvneta_pcpu_port *port =
+ per_cpu_ptr(pp->ports, cpu);
- netif_napi_add(dev, &port->napi, mvneta_poll, NAPI_POLL_WEIGHT);
- port->pp = pp;
+ netif_napi_add(dev, &port->napi, mvneta_poll,
+ NAPI_POLL_WEIGHT);
+ port->pp = pp;
+ }
}
dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
@@ -4275,6 +4397,7 @@ static int mvneta_remove(struct platform_device *pdev)
static const struct of_device_id mvneta_match[] = {
{ .compatible = "marvell,armada-370-neta" },
{ .compatible = "marvell,armada-xp-neta" },
+ { .compatible = "marvell,armada-3700-neta" },
{ }
};
MODULE_DEVICE_TABLE(of, mvneta_match);
--
2.10.2
^ permalink raw reply related
* [PATCH net-next 2/4] net: mvneta: Only disable mvneta_bm for 64-bits
From: Gregory CLEMENT @ 2016-11-22 16:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161122164844.19566-1-gregory.clement@free-electrons.com>
Actually only the mvneta_bm support is not 64-bits compatible.
The mvneta code itself can run on 64-bits architecture.
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
drivers/net/ethernet/marvell/Kconfig | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/marvell/Kconfig b/drivers/net/ethernet/marvell/Kconfig
index 66fd9dbb2ca7..2ccea9dd9248 100644
--- a/drivers/net/ethernet/marvell/Kconfig
+++ b/drivers/net/ethernet/marvell/Kconfig
@@ -44,6 +44,7 @@ config MVMDIO
config MVNETA_BM_ENABLE
tristate "Marvell Armada 38x/XP network interface BM support"
depends on MVNETA
+ depends on !64BIT
---help---
This driver supports auxiliary block of the network
interface units in the Marvell ARMADA XP and ARMADA 38x SoC
@@ -58,7 +59,6 @@ config MVNETA
tristate "Marvell Armada 370/38x/XP network interface support"
depends on PLAT_ORION || COMPILE_TEST
depends on HAS_DMA
- depends on !64BIT
select MVMDIO
select FIXED_PHY
---help---
@@ -71,6 +71,7 @@ config MVNETA
config MVNETA_BM
tristate
+ depends on !64BIT
default y if MVNETA=y && MVNETA_BM_ENABLE!=n
default MVNETA_BM_ENABLE
select HWBM
--
2.10.2
^ permalink raw reply related
* [PATCH net-next 1/4] net: mvneta: Convert to be 64 bits compatible
From: Gregory CLEMENT @ 2016-11-22 16:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161122164844.19566-1-gregory.clement@free-electrons.com>
From: Marcin Wojtas <mw@semihalf.com>
Prepare the mvneta driver in order to be usable on the 64 bits platform
such as the Armada 3700.
[gregory.clement at free-electrons.com]: this patch was extract from a larger
one to ease review and maintenance.
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
drivers/net/ethernet/marvell/mvneta.c | 77 ++++++++++++++++++++++++++++++++---
1 file changed, 71 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index 87274d4ab102..67f6465d96ba 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -296,6 +296,12 @@
/* descriptor aligned size */
#define MVNETA_DESC_ALIGNED_SIZE 32
+/* Number of bytes to be taken into account by HW when putting incoming data
+ * to the buffers. It is needed in case NET_SKB_PAD exceeds maximum packet
+ * offset supported in MVNETA_RXQ_CONFIG_REG(q) registers.
+ */
+#define MVNETA_RX_PKT_OFFSET_CORRECTION 64
+
#define MVNETA_RX_PKT_SIZE(mtu) \
ALIGN((mtu) + MVNETA_MH_SIZE + MVNETA_VLAN_TAG_LEN + \
ETH_HLEN + ETH_FCS_LEN, \
@@ -416,8 +422,11 @@ struct mvneta_port {
u64 ethtool_stats[ARRAY_SIZE(mvneta_statistics)];
u32 indir[MVNETA_RSS_LU_TABLE_SIZE];
+#ifdef CONFIG_64BIT
+ u64 data_high;
+#endif
+ u16 rx_offset_correction;
};
-
/* The mvneta_tx_desc and mvneta_rx_desc structures describe the
* layout of the transmit and reception DMA descriptors, and their
* layout is therefore defined by the hardware design
@@ -1791,6 +1800,10 @@ static int mvneta_rx_refill(struct mvneta_port *pp,
if (!data)
return -ENOMEM;
+#ifdef CONFIG_64BIT
+ if (unlikely(pp->data_high != (u64)upper_32_bits((u64)data) << 32))
+ return -ENOMEM;
+#endif
phys_addr = dma_map_single(pp->dev->dev.parent, data,
MVNETA_RX_BUF_SIZE(pp->pkt_size),
DMA_FROM_DEVICE);
@@ -1799,7 +1812,8 @@ static int mvneta_rx_refill(struct mvneta_port *pp,
return -ENOMEM;
}
- mvneta_rx_desc_fill(rx_desc, phys_addr, (u32)data);
+ phys_addr += pp->rx_offset_correction;
+ mvneta_rx_desc_fill(rx_desc, phys_addr, (uintptr_t)data);
return 0;
}
@@ -1861,8 +1875,16 @@ static void mvneta_rxq_drop_pkts(struct mvneta_port *pp,
for (i = 0; i < rxq->size; i++) {
struct mvneta_rx_desc *rx_desc = rxq->descs + i;
- void *data = (void *)rx_desc->buf_cookie;
-
+ void *data = (u8 *)(uintptr_t)rx_desc->buf_cookie;
+#ifdef CONFIG_64BIT
+ /* In Neta HW only 32 bits data is supported, so in
+ * order to obtain whole 64 bits address from RX
+ * descriptor, we store the upper 32 bits when
+ * allocating buffer, and put it back when using
+ * buffer cookie for accessing packet in memory.
+ */
+ data = (u8 *)(pp->data_high | (u64)data);
+#endif
dma_unmap_single(pp->dev->dev.parent, rx_desc->buf_phys_addr,
MVNETA_RX_BUF_SIZE(pp->pkt_size), DMA_FROM_DEVICE);
mvneta_frag_free(pp->frag_size, data);
@@ -1899,7 +1921,17 @@ static int mvneta_rx_swbm(struct mvneta_port *pp, int rx_todo,
rx_done++;
rx_status = rx_desc->status;
rx_bytes = rx_desc->data_size - (ETH_FCS_LEN + MVNETA_MH_SIZE);
+#ifdef CONFIG_64BIT
+ /* In Neta HW only 32 bits data is supported, so in
+ * order to obtain whole 64 bits address from RX
+ * descriptor, we store the upper 32 bits when
+ * allocating buffer, and put it back when using
+ * buffer cookie for accessing packet in memory.
+ */
+ data = (u8 *)(pp->data_high | (u64)rx_desc->buf_cookie);
+#else
data = (unsigned char *)rx_desc->buf_cookie;
+#endif
phys_addr = rx_desc->buf_phys_addr;
if (!mvneta_rxq_desc_is_first_last(rx_status) ||
@@ -2020,7 +2052,17 @@ static int mvneta_rx_hwbm(struct mvneta_port *pp, int rx_todo,
rx_done++;
rx_status = rx_desc->status;
rx_bytes = rx_desc->data_size - (ETH_FCS_LEN + MVNETA_MH_SIZE);
- data = (unsigned char *)rx_desc->buf_cookie;
+#ifdef CONFIG_64BIT
+ /* In Neta HW only 32 bits data is supported, so in
+ * order to obtain whole 64 bits address from RX
+ * descriptor, we store the upper 32 bits when
+ * allocating buffer, and put it back when using
+ * buffer cookie for accessing packet in memory.
+ */
+ data = (u8 *)(pp->data_high | (u64)rx_desc->buf_cookie);
+#else
+ data = (u8 *)rx_desc->buf_cookie;
+#endif
phys_addr = rx_desc->buf_phys_addr;
pool_id = MVNETA_RX_GET_BM_POOL_ID(rx_desc);
bm_pool = &pp->bm_priv->bm_pools[pool_id];
@@ -2773,7 +2815,7 @@ static int mvneta_rxq_init(struct mvneta_port *pp,
mvreg_write(pp, MVNETA_RXQ_SIZE_REG(rxq->id), rxq->size);
/* Set Offset */
- mvneta_rxq_offset_set(pp, rxq, NET_SKB_PAD);
+ mvneta_rxq_offset_set(pp, rxq, NET_SKB_PAD - pp->rx_offset_correction);
/* Set coalescing pkts and time */
mvneta_rx_pkts_coal_set(pp, rxq, rxq->pkts_coal);
@@ -2930,6 +2972,22 @@ static void mvneta_cleanup_rxqs(struct mvneta_port *pp)
static int mvneta_setup_rxqs(struct mvneta_port *pp)
{
int queue;
+#ifdef CONFIG_64BIT
+ void *data_tmp;
+
+ /* In Neta HW only 32 bits data is supported, so in order to
+ * obtain whole 64 bits address from RX descriptor, we store
+ * the upper 32 bits when allocating buffer, and put it back
+ * when using buffer cookie for accessing packet in memory.
+ * Frags should be allocated from single 'memory' region,
+ * hence common upper address half should be sufficient.
+ */
+ data_tmp = mvneta_frag_alloc(pp->frag_size);
+ if (data_tmp) {
+ pp->data_high = (u64)upper_32_bits((u64)data_tmp) << 32;
+ mvneta_frag_free(pp->frag_size, data_tmp);
+ }
+#endif
for (queue = 0; queue < rxq_number; queue++) {
int err = mvneta_rxq_init(pp, &pp->rxqs[queue]);
@@ -4019,6 +4077,13 @@ static int mvneta_probe(struct platform_device *pdev)
pp->rxq_def = rxq_def;
+ /* Set RX packet offset correction for platforms, whose
+ * NET_SKB_PAD, exceeds 64B. It should be 64B for 64-bit
+ * platforms and 0B for 32-bit ones.
+ */
+ pp->rx_offset_correction =
+ max(0, NET_SKB_PAD - MVNETA_RX_PKT_OFFSET_CORRECTION);
+
pp->indir[0] = rxq_def;
pp->clk = devm_clk_get(&pdev->dev, "core");
--
2.10.2
^ permalink raw reply related
* [PATCH net-next 0/4] Extend mvneta to support Armada 3700 (ARM 64)
From: Gregory CLEMENT @ 2016-11-22 16:48 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
This series enable the use of mvneta driver on the Armada 3700
SoCs. Armada 3700 is a new ARMv8 SoC from Marvell using same network
controller as older Armada 370/38x/XP.
Besides the changes needed to be used on 64-bits architecture done in
the 1st patch, there are also few difference related to the Armada
3700 SoC. The main one being the used of shared interrupt instead of
the private ones. It has been addressed in the 3rd patch.
Not all the feature supported on the older Soc have been ported yet
for this new SoC.
Gregory CLEMENT (2):
net: mvneta: Only disable mvneta_bm for 64-bits
ARM64: dts: marvell: Add network support for Armada 3700
Marcin Wojtas (2):
net: mvneta: Convert to be 64 bits compatible
net: mvneta: Add network support for Armada 3700 SoC
.../bindings/net/marvell-armada-370-neta.txt | 7 +-
arch/arm64/boot/dts/marvell/armada-3720-db.dts | 23 ++
arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 23 ++
drivers/net/ethernet/marvell/Kconfig | 10 +-
drivers/net/ethernet/marvell/mvneta.c | 364 ++++++++++++++++-----
5 files changed, 333 insertions(+), 94 deletions(-)
--
2.10.2
^ permalink raw reply
* [PATCH 2/7] add MFD for stm32 timer IP
From: Lee Jones @ 2016-11-22 16:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161122163018.GI10134@dell.home>
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
* [PATCH 2/7] add MFD for stm32 timer IP
From: Benjamin Gaignard @ 2016-11-22 16:40 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161122164106.GJ10134@dell.home>
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
* [PATCH] ARM: davinci: PM: fix build when da850 not compiled in
From: Kevin Hilman @ 2016-11-22 16:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <b36c5d16-9d49-e4db-8992-c02e9244f04c@ti.com>
Sekhar Nori <nsekhar@ti.com> writes:
> On Wednesday 16 November 2016 10:14 PM, Kevin Hilman wrote:
>> Currently, suspend/resume support is only available on da850 platforms,
>> and the platform PM code has dependencies on da850 functions. However,
>> CONFIG_SUSPEND might be enabled even when da850 support is not, causing
>> build failure:
>>
>> arch/arm/mach-davinci/built-in.o: In function `davinci_pm_init':
>> pm_domain.c:(.init.text+0x1fb8): undefined reference to `da8xx_get_mem_ctlr'
>> pm_domain.c:(.init.text+0x20b0): undefined reference to `da8xx_syscfg1_base'
>>
>> Fix this by only building the PM core when da850 is enabled.
>>
>> Reported-by: Sekhar Nori <nsekhar@ti.com>
>> Fixes: aa9aa1ec2df6 ARM: davinci: PM: rework init, remove platform device
>> Signed-off-by: Kevin Hilman <khilman@baylibre.com>
>
> Applied. Documentation asks for ("") around commit headline in Fixes:
> tag, so I added that.
Thanks,
Kevin
^ permalink raw reply
* [PATCH net-next] net: mvneta: Only disable mvneta_bm for 64-bits
From: Gregory CLEMENT @ 2016-11-22 16:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161122.111223.676925674747527292.davem@davemloft.net>
Hi David,
On mar., nov. 22 2016, David Miller <davem@davemloft.net> wrote:
> From: Gregory CLEMENT <gregory.clement@free-electrons.com>
> Date: Tue, 22 Nov 2016 17:00:37 +0100
>
>> Actually only the mvneta_bm support is not 64-bits compatible.
>> The mvneta code itself can run on 64-bits architecture.
>>
>> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
>
> No it cannot, it emits warnings because it casts pointers to and
> from 32-bit integers.
>
> I'm not applying this.
>
> drivers/net/ethernet/marvell/mvneta.c: In function ?mvneta_rx_refill?:
> drivers/net/ethernet/marvell/mvneta.c:1802:42: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
> mvneta_rx_desc_fill(rx_desc, phys_addr, (u32)data);
> ^
> drivers/net/ethernet/marvell/mvneta.c: In function ?mvneta_rxq_drop_pkts?:
> drivers/net/ethernet/marvell/mvneta.c:1864:16: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
> void *data = (void *)rx_desc->buf_cookie;
> ^
> drivers/net/ethernet/marvell/mvneta.c: In function ?mvneta_rx_swbm?:
> drivers/net/ethernet/marvell/mvneta.c:1902:10: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
> data = (unsigned char *)rx_desc->buf_cookie;
> ^
> drivers/net/ethernet/marvell/mvneta.c: In function ?mvneta_rx_hwbm?:
> drivers/net/ethernet/marvell/mvneta.c:2023:10: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
> data = (unsigned char *)rx_desc->buf_cookie;
> ^
Indeed!
There was a missing patch for it that I had in my tree and I didn't
submit yet. I am bout to doing it now.
Thanks,
Gregory
--
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
^ permalink raw reply
* [PATCH 2/2] MAINTAINERS: Add myself as co-maintainer to fpga mgr framework.
From: Jason Gunthorpe @ 2016-11-22 16:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <47eb36a7-ee48-53bd-fbdc-15225c3147ec@xilinx.com>
On Tue, Nov 22, 2016 at 08:48:57AM +0100, Michal Simek wrote:
> TBH. I think it is not a bad option. I do normally have backup person
> for all repos I do maintain. It doesn't mean that second maintainer does
> something but it has all accesses to repos you maintain.
I agree, it is a good idea to have a maintainer team model as early as
possible just because stuff does happen. We've had to recover from MIA
maintainers in RDMA and TPM, and it is not really nice. Generally
a lot of patches just get dropped :(
Jason
^ permalink raw reply
* [PATCH 1/2] kbuild: provide include/asm/asm-prototypes.h for ARM
From: Nicolas Pitre @ 2016-11-22 16:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161122110557.1533467-1-arnd@arndb.de>
On Tue, 22 Nov 2016, Arnd Bergmann wrote:
> This adds an asm/asm-prototypes.h header for ARM to fix the broken symbol
> versioning for symbols exported from assembler files.
>
> I couldn't find the correct prototypes for the compiler builtins,
> so I went with the fake 'void f(void)' prototypes that we had
> before, restoring the state before they were moved.
>
> Originally I assumed that the problem was just a harmless warning
> in unusual configurations, but as Uwe found, we actually need this
> to load most modules when symbol versioning is enabled, as it is
> in many distro kernels.
>
> Cc: Uwe Kleine-K?nig <uwe@kleine-koenig.org>
> Fixes: 4dd1837d7589 ("arm: move exports to definitions")
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
> Compared to the earlier version, I dropped the changes to the
> csumpartial files, which now get handled correctly by Kbuild
> even when the export comes from a macro, and I also dropped the
> changes to the bitops files, which were already fixed in a
> patch from Nico.
>
> The patch applies cleanly on top of the rmk/fixes tree but has
> no effect there, as it also needs 4efca4ed05cb ("kbuild: modversions
> for EXPORT_SYMBOL() for asm") and cc6acc11cad1 ("kbuild: be more
> careful about matching preprocessed asm ___EXPORT_SYMBOL").
>
> With the combination of rmk/fixes, torvalds/master and these two
> patches, symbol versioning works again on ARM. As it is still
> broken on almost all other architectures (powerpc is fixed,
> x86 has a patch), I wonder if we should make CONFIG_MODVERSIONS
> as broken for everything else.
I'm not sure I like this at all.
The goal for moving EXPORT_SYMBOL() to assembly code where symbols were
defined is to make things close together and avoid those centralized
list of symbols that you can easily miss when modifying the actual code.
This series is therefore bringing back a centralized list of symbols in
a slightly different form, nullifying the advantages from having moved
EXPORT_SYMBOL() to asm code. To me this looks like a big step backward.
Why not simply extending the original idea of keeping exports close to
the actual code by _also_ having a macro that provides the function
prototype alongside the EXPORT_SYMBOL() instance? That could even be
expressed with some EXPORT_SYMBOL_PROTO(ret, sym, arg...) macro that
does it all.
Nicolas
^ permalink raw reply
* [GIT PULL] STM32 DT changes for v4.10 #2
From: Alexandre Torgue @ 2016-11-22 16:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161118183736.GJ8882@localhost>
Hi Olof,
On 11/18/2016 07:37 PM, Olof Johansson wrote:
> On Tue, Nov 15, 2016 at 03:40:24PM +0100, Alexandre Torgue wrote:
>> Hi Olof, Arnd and Kevin,
>>
>> Please consider this second round of STM32 DT updates for v4.10:
>>
>> The following changes since commit f6dbbff4f0af1a5c0d6eaf414572b5eff7a73a8b:
>>
>> ARM: dts: stm32f429: add LSI and LSE clocks (2016-11-04 15:08:08 +0100)
>>
>> are available in the git repository at:
>>
>> git://git.kernel.org/pub/scm/linux/kernel/git/atorgue/stm32.git
>> tags/stm32-dt-for-v4.10-2
>>
>> for you to fetch changes up to 2ecaa477b404d707bac93c56f09a0a6162e04ed7:
>>
>> ARM: dts: stm32f429: Add QSPI clock (2016-11-15 13:59:11 +0100)
>>
>> ----------------------------------------------------------------
>> STM32 DT updates for v4.10, round 2.
>>
>> Highlights:
>> ----------
>> - Add support of STM32F746 MCU and STM32746G-Eval board
>> - Add QSPI support for STM32F469-Disco board
>>
>> ----------------------------------------------------------------
>> Alexandre TORGUE (1):
>> ARM: dts: Add STM32F746 MCU and STM32746g-EVAL board
>>
>> Gabriel Fernandez (1):
>> ARM: dts: stm32f429: Add QSPI clock
>
> Hi, merged. But here too, please use common prefixes in the future,
> please. I'd recommend 'ARM: dts: stm32: <...>'.
Thanks. I would take care next time.
Alex
>
>
> Thanks!
>
>
> -Olof
>
^ permalink raw reply
* [PATCH 2/7] add MFD for stm32 timer IP
From: Lee Jones @ 2016-11-22 16:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479831207-32699-3-git-send-email-benjamin.gaignard@st.com>
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
* [PATCH v2 1/2] ARM64: dts: Add support for Meson GXM
From: Kevin Hilman @ 2016-11-22 16:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161122100046.25899-2-narmstrong@baylibre.com>
Neil Armstrong <narmstrong@baylibre.com> writes:
> Following the Amlogic Linux kernel, it seem the only differences
> between the GXL and GXM SoCs are the CPU Clusters.
>
> This commit renames the gxl-s905d-p23x DTSI in a common file for
> S905D p23x and S912 q20x boards.
>
> Then adds a meson-gxm dtsi and reproduce the P23x to Q20x boards
> dts files since the S905D and S912 SoCs shares the same pinout
> and the P23x and Q20x boards are identical.
>
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Applied v2 of both patches,
Kevin
^ permalink raw reply
* [PATCH] ARM64: dts: meson-gxl: Add support for Nexbox A95X
From: Kevin Hilman @ 2016-11-22 16:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161122114154.17566-1-narmstrong@baylibre.com>
Neil Armstrong <narmstrong@baylibre.com> writes:
> The Nexbox A95X exists with a Meson GXBB (S905) Soc or a Meson GXL SoC (S905X).
> Add the S905X variant which uses the internal PHY instead of an external PHY.
Missing SoB?
Kevin
^ permalink raw reply
* [PATCH v2 1/4] spi: spi-fsl-dspi: Fix SPI transfer issue when using multiple SPI_IOC_MESSAGE
From: Mark Brown @ 2016-11-22 16:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161121191850.GB24521@Sanchayan-Arch.localdomain>
On Tue, Nov 22, 2016 at 12:48:50AM +0530, maitysanchayan at gmail.com wrote:
> On 16-11-22 00:44:30, maitysanchayan at gmail.com wrote:
> > This is not a resend of an applied patch. The whole series applies on
> > top of your topic/fsl-dspi branch and has fixes for the SPI DMA as
> > incremental changes
> Sorry. I take that back. I now see you applied the patch and I got the applied
> mail after I replied.
Ah, I did apply it on Friday but somehow it didn't get pushed until
yesterday. Sorry for the confusion.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 455 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161122/ce824c66/attachment.sig>
^ permalink raw reply
* [PATCH] arm64: tegra: Add VDD_GPU regulator to Jetson TX1
From: Thierry Reding @ 2016-11-22 16:16 UTC (permalink / raw)
To: linux-arm-kernel
From: Alexandre Courbot <acourbot@nvidia.com>
Add the VDD_GPU regulator (a GPIO-enabled PWM regulator) to the Jetson
TX1 board. This addition allows the GPU to be used provided the
bootloader properly enabled the GPU node.
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
---
Hi ARM-SoC maintainers,
This was part of a pull request for v4.8 but it seems everything of the
pull request except this one patch made it upstream. I think perhaps it
may have been the dependency on the regulator tree that made you defer
this to after v4.8-rc1 and then I forgot to resend.
Here's a link to the pull request:
http://lists.infradead.org/pipermail/linux-arm-kernel/2016-July/443469.html
There was no discussion on the list, but we might have discussed it on
IRC.
Can you please pick this up for v4.10-rc1?
Thanks,
Thierry
arch/arm64/boot/dts/nvidia/tegra210-p2180.dtsi | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p2180.dtsi b/arch/arm64/boot/dts/nvidia/tegra210-p2180.dtsi
index 5fda583351d7..906fb836d241 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210-p2180.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra210-p2180.dtsi
@@ -21,6 +21,10 @@
reg = <0x0 0x80000000 0x1 0x0>;
};
+ gpu at 57000000 {
+ vdd-supply = <&vdd_gpu>;
+ };
+
/* debug port */
serial at 70006000 {
status = "okay";
@@ -291,4 +295,18 @@
clock-frequency = <32768>;
};
};
+
+ regulators {
+ vdd_gpu: regulator at 100 {
+ compatible = "pwm-regulator";
+ reg = <100>;
+ pwms = <&pwm 1 4880>;
+ regulator-name = "VDD_GPU";
+ regulator-min-microvolt = <710000>;
+ regulator-max-microvolt = <1320000>;
+ enable-gpios = <&pmic 6 GPIO_ACTIVE_HIGH>;
+ regulator-ramp-delay = <80>;
+ regulator-enable-ramp-delay = <1000>;
+ };
+ };
};
--
2.10.2
^ permalink raw reply related
* [RFC PATCH 04/11] PCI: tegra: limit to MMU build only
From: Stephen Warren @ 2016-11-22 16:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479806768-39911-5-git-send-email-vladimir.murzin@arm.com>
On 11/22/2016 02:26 AM, Vladimir Murzin wrote:
> This driver uses functionality which available for MMU build only,
> thus add dependency on MMU.
I'd expect ARCH_TEGRA to depend on MMU instead.
^ permalink raw reply
* [PATCH 7/7] add stm32 multi-functions timer driver in DT
From: Benjamin Gaignard @ 2016-11-22 16:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479831207-32699-1-git-send-email-benjamin.gaignard@st.com>
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
* [PATCH 6/7] add STM32 IIO timer driver
From: Benjamin Gaignard @ 2016-11-22 16:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479831207-32699-1-git-send-email-benjamin.gaignard@st.com>
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
* [PATCH 5/7] add bindings for stm32 IIO timer drivers
From: Benjamin Gaignard @ 2016-11-22 16:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479831207-32699-1-git-send-email-benjamin.gaignard@st.com>
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
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox