* [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
* [PATCH 4/7] add pwm driver for stm32 plaftorm
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>
This driver add support for pwm driver on stm32 platform.
The SoC have multiple instances of the hardware IP and each
of them could have small differences: number of channels,
complementary output, counter register size...
To handle those variations each block have its own compatible
linked to internal table that describe them.
Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
---
drivers/pwm/Kconfig | 8 ++
drivers/pwm/Makefile | 1 +
drivers/pwm/pwm-stm32.c | 358 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 367 insertions(+)
create mode 100644 drivers/pwm/pwm-stm32.c
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index bf01288..aeee045 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -388,6 +388,14 @@ config PWM_STI
To compile this driver as a module, choose M here: the module
will be called pwm-sti.
+config PWM_STM32
+ bool "STMicroelectronics STM32 PWM"
+ depends on ARCH_STM32
+ depends on OF
+ select MFD_STM32_TIMER
+ help
+ Generic PWM framework driver for STM32 SoCs.
+
config PWM_STMPE
bool "STMPE expander PWM export"
depends on MFD_STMPE
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 1194c54..5aa9308 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o
obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o
obj-$(CONFIG_PWM_STI) += pwm-sti.o
+obj-$(CONFIG_PWM_STM32) += pwm-stm32.o
obj-$(CONFIG_PWM_STMPE) += pwm-stmpe.o
obj-$(CONFIG_PWM_SUN4I) += pwm-sun4i.o
obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c
new file mode 100644
index 0000000..2d71ee7
--- /dev/null
+++ b/drivers/pwm/pwm-stm32.c
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) STMicroelectronics 2016
+ * Author: Gerald Baeza <gerald.baeza@st.com>
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Inspired by timer-stm32.c from Maxime Coquelin
+ * pwm-atmel.c from Bo Shen
+ */
+
+#include <linux/module.h>
+#include <linux/pwm.h>
+
+#include <linux/mfd/stm32-mfd-timer.h>
+
+#define DRIVER_NAME "stm32-pwm"
+
+#define CAP_COMPLEMENTARY BIT(0)
+#define CAP_32BIT_COUNTER BIT(1)
+#define CAP_BREAKINPUT BIT(2)
+
+struct stm32_pwm_cfg {
+ int npwm;
+ int caps;
+};
+
+static struct stm32_pwm_cfg f4_pwm_cfg[] = {
+ /* for pwm 1 and 8 */
+ {
+ .npwm = 4,
+ .caps = CAP_COMPLEMENTARY | CAP_BREAKINPUT,
+ },
+ /* for pwm 2 and 5 */
+ {
+ .npwm = 4,
+ .caps = CAP_32BIT_COUNTER,
+ },
+ /* for pwm 3 and 4 */
+ {
+ .npwm = 4,
+ .caps = 0,
+ },
+ /* for pwm 9 and 12 */
+ {
+ .npwm = 2,
+ .caps = 0,
+ },
+ /* for pwm 10, 11, 13 and 14 */
+ {
+ .npwm = 1,
+ .caps = 0,
+ },
+};
+
+struct stm32_pwm_dev {
+ struct device *dev;
+ struct clk *clk;
+ struct regmap *regmap;
+ struct pwm_chip chip;
+ struct stm32_pwm_cfg *cfg;
+ bool have_breakinput;
+ u32 breakinput_polarity;
+};
+
+#define to_stm32_pwm_dev(x) container_of(chip, struct stm32_pwm_dev, chip)
+
+static u32 __active_channels(struct stm32_pwm_dev *pwm_dev)
+{
+ u32 ccer;
+
+ regmap_read(pwm_dev->regmap, TIM_CCER, &ccer);
+
+ return ccer & TIM_CCER_CCXE;
+}
+
+static int write_ccrx(struct stm32_pwm_dev *dev, struct pwm_device *pwm,
+ u32 ccr)
+{
+ switch (pwm->hwpwm) {
+ case 0:
+ return regmap_write(dev->regmap, TIM_CCR1, ccr);
+ case 1:
+ return regmap_write(dev->regmap, TIM_CCR2, ccr);
+ case 2:
+ return regmap_write(dev->regmap, TIM_CCR3, ccr);
+ case 3:
+ return regmap_write(dev->regmap, TIM_CCR4, ccr);
+ }
+ return -EINVAL;
+}
+
+static int stm32_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+ int duty_ns, int period_ns)
+{
+ struct stm32_pwm_dev *dev = to_stm32_pwm_dev(chip);
+ unsigned long long prd, div, dty;
+ int prescaler = 0;
+ u32 max_arr = 0xFFFF, ccmr, mask, shift, bdtr;
+
+ if (dev->cfg->caps & CAP_32BIT_COUNTER)
+ max_arr = 0xFFFFFFFF;
+
+ /* Period and prescaler values depends of clock rate */
+ div = (unsigned long long)clk_get_rate(dev->clk) * period_ns;
+
+ do_div(div, NSEC_PER_SEC);
+ prd = div;
+
+ while (div > max_arr) {
+ prescaler++;
+ div = prd;
+ do_div(div, (prescaler + 1));
+ }
+ prd = div;
+
+ if (prescaler > MAX_TIM_PSC) {
+ dev_err(chip->dev, "prescaler exceeds the maximum value\n");
+ return -EINVAL;
+ }
+
+ /* All channels share the same prescaler and counter so
+ * when two channels are active at the same we can't change them
+ */
+ if (__active_channels(dev) & ~(1 << pwm->hwpwm * 4)) {
+ u32 psc, arr;
+
+ regmap_read(dev->regmap, TIM_PSC, &psc);
+ regmap_read(dev->regmap, TIM_ARR, &arr);
+
+ if ((psc != prescaler) || (arr != prd - 1))
+ return -EINVAL;
+ }
+
+ regmap_write(dev->regmap, TIM_PSC, prescaler);
+ regmap_write(dev->regmap, TIM_ARR, prd - 1);
+ regmap_update_bits(dev->regmap, TIM_CR1, TIM_CR1_ARPE, TIM_CR1_ARPE);
+
+ /* Calculate the duty cycles */
+ dty = prd * duty_ns;
+ do_div(dty, period_ns);
+
+ write_ccrx(dev, pwm, dty);
+
+ /* Configure output mode */
+ shift = (pwm->hwpwm & 0x1) * 8;
+ ccmr = (TIM_CCMR_PE | TIM_CCMR_M1) << shift;
+ mask = 0xFF << shift;
+
+ if (pwm->hwpwm & 0x2)
+ regmap_update_bits(dev->regmap, TIM_CCMR2, mask, ccmr);
+ else
+ regmap_update_bits(dev->regmap, TIM_CCMR1, mask, ccmr);
+
+ bdtr = TIM_BDTR_MOE | TIM_BDTR_AOE;
+ if (dev->have_breakinput) {
+ bdtr |= TIM_BDTR_BKE;
+ if (dev->breakinput_polarity)
+ bdtr |= TIM_BDTR_BKP;
+ }
+
+ regmap_update_bits(dev->regmap, TIM_BDTR,
+ TIM_BDTR_MOE | TIM_BDTR_AOE |
+ TIM_BDTR_BKP | TIM_BDTR_BKE,
+ bdtr);
+
+ return 0;
+}
+
+static int stm32_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
+ enum pwm_polarity polarity)
+{
+ u32 mask;
+ struct stm32_pwm_dev *dev = to_stm32_pwm_dev(chip);
+
+ mask = TIM_CCER_CC1P << (pwm->hwpwm * 4);
+ if (dev->cfg->caps & CAP_COMPLEMENTARY)
+ mask |= TIM_CCER_CC1NP << (pwm->hwpwm * 4);
+
+ regmap_update_bits(dev->regmap, TIM_CCER, mask,
+ polarity == PWM_POLARITY_NORMAL ? 0 : mask);
+
+ return 0;
+}
+
+static int stm32_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ u32 mask;
+ struct stm32_pwm_dev *dev = to_stm32_pwm_dev(chip);
+
+ clk_enable(dev->clk);
+
+ /* Enable channel */
+ mask = TIM_CCER_CC1E << (pwm->hwpwm * 4);
+ if (dev->cfg->caps & CAP_COMPLEMENTARY)
+ mask |= TIM_CCER_CC1NE << (pwm->hwpwm * 4);
+
+ regmap_update_bits(dev->regmap, TIM_CCER, mask, mask);
+
+ /* Make sure that registers are updated */
+ regmap_update_bits(dev->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG);
+
+ /* Enable controller */
+ regmap_update_bits(dev->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN);
+
+ return 0;
+}
+
+static void stm32_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ u32 mask;
+ struct stm32_pwm_dev *dev = to_stm32_pwm_dev(chip);
+
+ /* Disable channel */
+ mask = TIM_CCER_CC1E << (pwm->hwpwm * 4);
+ if (dev->cfg->caps & CAP_COMPLEMENTARY)
+ mask |= TIM_CCER_CC1NE << (pwm->hwpwm * 4);
+
+ regmap_update_bits(dev->regmap, TIM_CCER, mask, 0);
+
+ /* When all channels are disabled, we can disable the controller */
+ if (!__active_channels(dev))
+ regmap_update_bits(dev->regmap, TIM_CR1, TIM_CR1_CEN, 0);
+
+ clk_disable(dev->clk);
+}
+
+static const struct pwm_ops stm32pwm_ops = {
+ .config = stm32_pwm_config,
+ .set_polarity = stm32_pwm_set_polarity,
+ .enable = stm32_pwm_enable,
+ .disable = stm32_pwm_disable,
+};
+
+static const struct of_device_id stm32_pwm_of_match[] = {
+ {
+ .compatible = "st,stm32-pwm1",
+ .data = &f4_pwm_cfg[0],
+ },
+ {
+ .compatible = "st,stm32-pwm2",
+ .data = &f4_pwm_cfg[1],
+ },
+ {
+ .compatible = "st,stm32-pwm3",
+ .data = &f4_pwm_cfg[2],
+ },
+ {
+ .compatible = "st,stm32-pwm4",
+ .data = &f4_pwm_cfg[2],
+ },
+ {
+ .compatible = "st,stm32-pwm5",
+ .data = &f4_pwm_cfg[1],
+ },
+ {
+ .compatible = "st,stm32-pwm8",
+ .data = &f4_pwm_cfg[0],
+ },
+ {
+ .compatible = "st,stm32-pwm9",
+ .data = &f4_pwm_cfg[3],
+ },
+ {
+ .compatible = "st,stm32-pwm10",
+ .data = &f4_pwm_cfg[4],
+ },
+ {
+ .compatible = "st,stm32-pwm11",
+ .data = &f4_pwm_cfg[4],
+ },
+ {
+ .compatible = "st,stm32-pwm12",
+ .data = &f4_pwm_cfg[3],
+ },
+ {
+ .compatible = "st,stm32-pwm13",
+ .data = &f4_pwm_cfg[4],
+ },
+ {
+ .compatible = "st,stm32-pwm14",
+ .data = &f4_pwm_cfg[4],
+ },
+ {
+ /* end node */
+ },
+};
+MODULE_DEVICE_TABLE(of, stm32_pwm_of_match);
+
+static int stm32_pwm_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct stm32_mfd_timer_dev *mfd = pdev->dev.platform_data;
+ struct stm32_pwm_dev *pwm;
+ int ret;
+
+ pwm = devm_kzalloc(dev, sizeof(*pwm), GFP_KERNEL);
+ if (!pwm)
+ return -ENOMEM;
+
+ pwm->regmap = mfd->regmap;
+ pwm->clk = mfd->clk;
+
+ if (!pwm->regmap || !pwm->clk)
+ return -EINVAL;
+
+ /* populate data structure depending on compatibility */
+ if (!of_match_node(stm32_pwm_of_match, np)->data)
+ return -EINVAL;
+
+ pwm->cfg =
+ (struct stm32_pwm_cfg *)of_match_node(stm32_pwm_of_match, np)->data;
+
+ if (pwm->cfg->caps & CAP_BREAKINPUT) {
+ if (!of_property_read_u32(np, "st,breakinput-polarity",
+ &pwm->breakinput_polarity))
+ pwm->have_breakinput = true;
+ }
+
+ pwm->chip.base = -1;
+ pwm->chip.dev = dev;
+ pwm->chip.ops = &stm32pwm_ops;
+ pwm->chip.npwm = pwm->cfg->npwm;
+
+ ret = pwmchip_add(&pwm->chip);
+ if (ret < 0)
+ return ret;
+
+ platform_set_drvdata(pdev, pwm);
+
+ return 0;
+}
+
+static int stm32_pwm_remove(struct platform_device *pdev)
+{
+ struct stm32_pwm_dev *pwm = platform_get_drvdata(pdev);
+ int i;
+
+ for (i = 0; i < pwm->cfg->npwm; i++)
+ pwm_disable(&pwm->chip.pwms[i]);
+
+ pwmchip_remove(&pwm->chip);
+
+ return 0;
+}
+
+static struct platform_driver stm32_pwm_driver = {
+ .probe = stm32_pwm_probe,
+ .remove = stm32_pwm_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = stm32_pwm_of_match,
+ },
+};
+module_platform_driver(stm32_pwm_driver);
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_DESCRIPTION("STMicroelectronics STM32 PWM driver");
+MODULE_LICENSE("GPL");
--
1.9.1
^ permalink raw reply related
* [PATCH 3/7] add pwm-stm32 DT bindings
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 binding for pwm-stm32
Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
---
.../devicetree/bindings/pwm/pwm-stm32.txt | 43 ++++++++++++++++++++++
1 file changed, 43 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pwm/pwm-stm32.txt
diff --git a/Documentation/devicetree/bindings/pwm/pwm-stm32.txt b/Documentation/devicetree/bindings/pwm/pwm-stm32.txt
new file mode 100644
index 0000000..819e024
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/pwm-stm32.txt
@@ -0,0 +1,43 @@
+STMicroelectronics PWM driver bindings for STM32
+--------------------------------------
+
+Must be a child of STM32 multifunctions timer driver
+
+Required parameters:
+- compatible : "st,stm32-pwm1"
+ "st,stm32-pwm2"
+ "st,stm32-pwm3"
+ "st,stm32-pwm4"
+ "st,stm32-pwm5"
+ "st,stm32-pwm8"
+ "st,stm32-pwm9"
+ "st,stm32-pwm10"
+ "st,stm32-pwm11"
+ "st,stm32-pwm12"
+ "st,stm32-pwm13"
+ "st,stm32-pwm14"
+- pinctrl-names: Set to "default".
+- pinctrl-0: List of phandles pointing to pin configuration nodes
+ for PWM module.
+ For Pinctrl properties, please refer to [1].
+
+Optional parameters:
+- st,breakinput-polarity if set enable break input feature.
+ The value define the active polarity:
+ - 0 (active LOW)
+ - 1 (active HIGH)
+
+[1] Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
+
+Example:
+ mfd_timer1: mfdtimer1 at 40010000 {
+ compatible = "st,stm32-mfd-timer1";
+ reg = <0x40010000 0x400>;
+ clocks = <&rcc 0 160>;
+ clock-names = "mfd_timer_clk";
+ interrupts = <27>;
+
+ pwm1: pwm1 at 40010000 {
+ compatible = "st,stm32-pwm1";
+ };
+ };
--
1.9.1
^ permalink raw reply related
* [PATCH 2/7] add MFD for stm32 timer IP
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>
This hardware block could at used at same time for PWM generation
and IIO timer for other IPs like DAC, ADC or other timers.
PWM and IIO timer configuration are mixed in the same registers
so we need a MFD to be able to share those registers.
Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
---
drivers/mfd/Kconfig | 10 ++
drivers/mfd/Makefile | 2 +
drivers/mfd/stm32-mfd-timer.c | 236 ++++++++++++++++++++++++++++++++++++
include/linux/mfd/stm32-mfd-timer.h | 78 ++++++++++++
4 files changed, 326 insertions(+)
create mode 100644 drivers/mfd/stm32-mfd-timer.c
create mode 100644 include/linux/mfd/stm32-mfd-timer.h
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index c6df644..63aee36 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1607,6 +1607,15 @@ config MFD_STW481X
in various ST Microelectronics and ST-Ericsson embedded
Nomadik series.
+config MFD_STM32_TIMER
+ tristate "Support for STM32 multifunctions timer"
+ select MFD_CORE
+ select REGMAP
+ depends on ARCH_STM32
+ depends on OF
+ help
+ Select multifunction driver (pwm, IIO trigger) for stm32 timers
+
menu "Multimedia Capabilities Port drivers"
depends on ARCH_SA1100
@@ -1644,4 +1653,5 @@ config MFD_VEXPRESS_SYSREG
on the ARM Ltd. Versatile Express board.
endmenu
+
endif
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 9834e66..b348c3e 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -211,3 +211,5 @@ obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o
obj-$(CONFIG_MFD_MT6397) += mt6397-core.o
obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o
+
+obj-$(CONFIG_MFD_STM32_TIMER) += stm32-mfd-timer.o
diff --git a/drivers/mfd/stm32-mfd-timer.c b/drivers/mfd/stm32-mfd-timer.c
new file mode 100644
index 0000000..67e7db3
--- /dev/null
+++ b/drivers/mfd/stm32-mfd-timer.c
@@ -0,0 +1,236 @@
+/*
+ * stm32-timer.c
+ *
+ * Copyright (C) STMicroelectronics 2016
+ * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+#include <linux/mfd/stm32-mfd-timer.h>
+
+static const struct stm32_mfd_timer_cfg mfd_cells_cfg[] = {
+ {
+ .pwm_name = "pwm1",
+ .pwm_compatible = "st,stm32-pwm1",
+ .trigger_name = "iiotimer1",
+ .trigger_compatible = "st,stm32-iio-timer1",
+ },
+ {
+ .pwm_name = "pwm2",
+ .pwm_compatible = "st,stm32-pwm2",
+ .trigger_name = "iiotimer2",
+ .trigger_compatible = "st,stm32-iio-timer2",
+ },
+ {
+ .pwm_name = "pwm3",
+ .pwm_compatible = "st,stm32-pwm3",
+ .trigger_name = "iiotimer3",
+ .trigger_compatible = "st,stm32-iio-timer3",
+ },
+ {
+ .pwm_name = "pwm4",
+ .pwm_compatible = "st,stm32-pwm4",
+ .trigger_name = "iiotimer4",
+ .trigger_compatible = "st,stm32-iio-timer4",
+ },
+ {
+ .pwm_name = "pwm5",
+ .pwm_compatible = "st,stm32-pwm5",
+ .trigger_name = "iiotimer5",
+ .trigger_compatible = "st,stm32-iio-timer5",
+ },
+ {
+ .trigger_name = "iiotimer6",
+ .trigger_compatible = "st,stm32-iio-timer6",
+ },
+ {
+ .trigger_name = "iiotimer7",
+ .trigger_compatible = "st,stm32-iio-timer7",
+ },
+ {
+ .pwm_name = "pwm8",
+ .pwm_compatible = "st,stm32-pwm8",
+ .trigger_name = "iiotimer8",
+ .trigger_compatible = "st,stm32-iio-timer8",
+ },
+ {
+ .pwm_name = "pwm9",
+ .pwm_compatible = "st,stm32-pwm9",
+ .trigger_name = "iiotimer9",
+ .trigger_compatible = "st,stm32-iio-timer9",
+ },
+ {
+ .pwm_name = "pwm10",
+ .pwm_compatible = "st,stm32-pwm10",
+ },
+ {
+ .pwm_name = "pwm11",
+ .pwm_compatible = "st,stm32-pwm11",
+ },
+ {
+ .pwm_name = "pwm12",
+ .pwm_compatible = "st,stm32-pwm12",
+ .trigger_name = "iiotimer12",
+ .trigger_compatible = "st,stm32-iio-timer12",
+ },
+ {
+ .pwm_name = "pwm13",
+ .pwm_compatible = "st,stm32-pwm13",
+ },
+ {
+ .pwm_name = "pwm14",
+ .pwm_compatible = "st,stm32-pwm14",
+ },
+};
+
+static const struct of_device_id stm32_timer_of_match[] = {
+ {
+ .compatible = "st,stm32-mfd-timer1",
+ .data = &mfd_cells_cfg[0],
+ },
+ {
+ .compatible = "st,stm32-mfd-timer2",
+ .data = &mfd_cells_cfg[1],
+ },
+ {
+ .compatible = "st,stm32-mfd-timer3",
+ .data = &mfd_cells_cfg[2],
+ },
+ {
+ .compatible = "st,stm32-mfd-timer4",
+ .data = &mfd_cells_cfg[3],
+ },
+ {
+ .compatible = "st,stm32-mfd-timer5",
+ .data = &mfd_cells_cfg[4],
+ },
+ {
+ .compatible = "st,stm32-mfd-timer6",
+ .data = &mfd_cells_cfg[5],
+ },
+ {
+ .compatible = "st,stm32-mfd-timer7",
+ .data = &mfd_cells_cfg[6],
+ },
+ {
+ .compatible = "st,stm32-mfd-timer8",
+ .data = &mfd_cells_cfg[7],
+ },
+ {
+ .compatible = "st,stm32-mfd-timer9",
+ .data = &mfd_cells_cfg[8],
+ },
+ {
+ .compatible = "st,stm32-mfd-timer10",
+ .data = &mfd_cells_cfg[9],
+ },
+ {
+ .compatible = "st,stm32-mfd-timer11",
+ .data = &mfd_cells_cfg[10],
+ },
+ {
+ .compatible = "st,stm32-mfd-timer12",
+ .data = &mfd_cells_cfg[11],
+ },
+ {
+ .compatible = "st,stm32-mfd-timer13",
+ .data = &mfd_cells_cfg[12],
+ },
+ {
+ .compatible = "st,stm32-mfd-timer14",
+ .data = &mfd_cells_cfg[13],
+ },
+};
+
+static const struct regmap_config stm32_timer_regmap_cfg = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = sizeof(u32),
+ .max_register = 0x400,
+ .fast_io = true,
+};
+
+static int stm32_mfd_timer_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct stm32_mfd_timer_dev *mfd;
+ struct resource *res;
+ int ret, nb_cells = 0;
+ struct mfd_cell *cell = NULL;
+ void __iomem *mmio;
+
+ mfd = devm_kzalloc(dev, sizeof(*mfd), GFP_KERNEL);
+ if (!mfd)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENOMEM;
+
+ mmio = devm_ioremap_resource(dev, res);
+ if (IS_ERR(mmio))
+ return PTR_ERR(mmio);
+
+ mfd->regmap = devm_regmap_init_mmio_clk(dev, "mfd_timer_clk", mmio,
+ &stm32_timer_regmap_cfg);
+ if (IS_ERR(mfd->regmap))
+ return PTR_ERR(mfd->regmap);
+
+ mfd->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(mfd->clk))
+ return PTR_ERR(mfd->clk);
+
+ mfd->irq = platform_get_irq(pdev, 0);
+ if (mfd->irq < 0)
+ return -EINVAL;
+
+ /* populate data structure depending on compatibility */
+ if (!of_match_node(stm32_timer_of_match, np)->data)
+ return -EINVAL;
+
+ mfd->cfg =
+ (struct stm32_mfd_timer_cfg *)of_match_node(stm32_timer_of_match, np)->data;
+
+ if (mfd->cfg->pwm_name && mfd->cfg->pwm_compatible) {
+ cell = &mfd->cells[nb_cells++];
+ cell->name = mfd->cfg->pwm_name;
+ cell->of_compatible = mfd->cfg->pwm_compatible;
+ cell->platform_data = mfd;
+ cell->pdata_size = sizeof(*mfd);
+ }
+
+ if (mfd->cfg->trigger_name && mfd->cfg->trigger_compatible) {
+ cell = &mfd->cells[nb_cells++];
+ cell->name = mfd->cfg->trigger_name;
+ cell->of_compatible = mfd->cfg->trigger_compatible;
+ cell->platform_data = mfd;
+ cell->pdata_size = sizeof(*mfd);
+ }
+
+ ret = devm_mfd_add_devices(&pdev->dev, pdev->id, mfd->cells,
+ nb_cells, NULL, 0, NULL);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, mfd);
+
+ return 0;
+}
+
+static struct platform_driver stm32_mfd_timer_driver = {
+ .probe = stm32_mfd_timer_probe,
+ .driver = {
+ .name = "stm32-mfd-timer",
+ .of_match_table = stm32_timer_of_match,
+ },
+};
+module_platform_driver(stm32_mfd_timer_driver);
+
+MODULE_DESCRIPTION("STMicroelectronics STM32 Timer MFD");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/stm32-mfd-timer.h b/include/linux/mfd/stm32-mfd-timer.h
new file mode 100644
index 0000000..4a79c22
--- /dev/null
+++ b/include/linux/mfd/stm32-mfd-timer.h
@@ -0,0 +1,78 @@
+/*
+ * stm32-mfd-timer.h
+ *
+ * Copyright (C) STMicroelectronics 2016
+ * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#ifndef _LINUX_MFD_STM32_TIMER_H_
+#define _LINUX_MFD_STM32_TIMER_H_
+
+#include <linux/clk.h>
+#include <linux/mfd/core.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+#define TIM_CR1 0x00 /* Control Register 1 */
+#define TIM_CR2 0x04 /* Control Register 2 */
+#define TIM_SMCR 0x08 /* Slave mode control reg */
+#define TIM_DIER 0x0C /* DMA/interrupt register */
+#define TIM_SR 0x10 /* Status register */
+#define TIM_EGR 0x14 /* Event Generation Reg */
+#define TIM_CCMR1 0x18 /* Capt/Comp 1 Mode Reg */
+#define TIM_CCMR2 0x1C /* Capt/Comp 2 Mode Reg */
+#define TIM_CCER 0x20 /* Capt/Comp Enable Reg */
+#define TIM_PSC 0x28 /* Prescaler */
+#define TIM_ARR 0x2c /* Auto-Reload Register */
+#define TIM_CCR1 0x34 /* Capt/Comp Register 1 */
+#define TIM_CCR2 0x38 /* Capt/Comp Register 2 */
+#define TIM_CCR3 0x3C /* Capt/Comp Register 3 */
+#define TIM_CCR4 0x40 /* Capt/Comp Register 4 */
+#define TIM_BDTR 0x44 /* Break and Dead-Time Reg */
+
+#define TIM_CR1_CEN BIT(0) /* Counter Enable */
+#define TIM_CR1_ARPE BIT(7) /* Auto-reload Preload Ena */
+#define TIM_CR2_MMS (BIT(4) | BIT(5) | BIT(6)) /* Master mode selection */
+#define TIM_SMCR_SMS (BIT(0) | BIT(1) | BIT(2)) /* Slave mode selection */
+#define TIM_SMCR_TS (BIT(4) | BIT(5) | BIT(6)) /* Trigger selection */
+#define TIM_DIER_UIE BIT(0) /* Update interrupt */
+#define TIM_SR_UIF BIT(0) /* Update interrupt flag */
+#define TIM_EGR_UG BIT(0) /* Update Generation */
+#define TIM_CCMR_PE BIT(3) /* Channel Preload Enable */
+#define TIM_CCMR_M1 (BIT(6) | BIT(5)) /* Channel PWM Mode 1 */
+#define TIM_CCER_CC1E BIT(0) /* Capt/Comp 1 out Ena */
+#define TIM_CCER_CC1P BIT(1) /* Capt/Comp 1 Polarity */
+#define TIM_CCER_CC1NE BIT(2) /* Capt/Comp 1N out Ena */
+#define TIM_CCER_CC1NP BIT(3) /* Capt/Comp 1N Polarity */
+#define TIM_CCER_CCXE (BIT(0) | BIT(4) | BIT(8) | BIT(12))
+#define TIM_BDTR_BKE BIT(12) /* Break input enable */
+#define TIM_BDTR_BKP BIT(13) /* Break input polarity */
+#define TIM_BDTR_AOE BIT(14) /* Automatic Output Enable */
+#define TIM_BDTR_MOE BIT(15) /* Main Output Enable */
+
+#define STM32_TIMER_CELLS 2
+#define MAX_TIM_PSC 0xFFFF
+
+struct stm32_mfd_timer_cfg {
+ const char *pwm_name;
+ const char *pwm_compatible;
+ const char *trigger_name;
+ const char *trigger_compatible;
+};
+
+struct stm32_mfd_timer_dev {
+ /* Device data */
+ struct device *dev;
+ struct clk *clk;
+ int irq;
+
+ /* Registers mapping */
+ struct regmap *regmap;
+
+ /* Private data */
+ struct mfd_cell cells[STM32_TIMER_CELLS];
+ struct stm32_mfd_timer_cfg *cfg;
+};
+
+#endif
--
1.9.1
^ permalink raw reply related
* [PATCH 1/7] add binding for stm32 multifunctions 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>
Add bindings information for stm32 timer MFD
Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
---
.../devicetree/bindings/mfd/stm32-timer.txt | 53 ++++++++++++++++++++++
1 file changed, 53 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mfd/stm32-timer.txt
diff --git a/Documentation/devicetree/bindings/mfd/stm32-timer.txt b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
new file mode 100644
index 0000000..3cefce1
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/stm32-timer.txt
@@ -0,0 +1,53 @@
+STM32 multifunctions timer driver
+
+stm32 timer MFD allow to handle at the same time pwm and IIO timer devices
+
+Required parameters:
+- compatible: must be one of the follow value:
+ "st,stm32-mfd-timer1"
+ "st,stm32-mfd-timer2"
+ "st,stm32-mfd-timer3"
+ "st,stm32-mfd-timer4"
+ "st,stm32-mfd-timer5"
+ "st,stm32-mfd-timer6"
+ "st,stm32-mfd-timer7"
+ "st,stm32-mfd-timer8"
+ "st,stm32-mfd-timer9"
+ "st,stm32-mfd-timer10"
+ "st,stm32-mfd-timer11"
+ "st,stm32-mfd-timer12"
+ "st,stm32-mfd-timer13"
+ "st,stm32-mfd-timer14"
+
+- reg : Physical base address and length of the controller's
+ registers.
+- clock-names: Set to "mfd_timer_clk".
+- clocks: Phandle of the clock used by the timer module.
+ For Clk properties, please refer to [1].
+- interrupts : Reference to the timer interrupt
+
+Optional parameters:
+- resets : Reference to a reset controller asserting the timer
+
+Optional subnodes:
+- pwm: See Documentation/devicetree/bindings/pwm/pwm-stm32.txt
+- iiotimer: See Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Example:
+ mfd_timer1: mfdtimer1 at 40010000 {
+ compatible = "st,stm32-mfd-timer1";
+ reg = <0x40010000 0x400>;
+ clocks = <&rcc 0 160>;
+ clock-names = "mfd_timer_clk";
+ interrupts = <27>;
+
+ pwm1: pwm1 at 40010000 {
+ compatible = "st,stm32-pwm1";
+ };
+
+ iiotimer1: iiotimer1 at 40010000 {
+ compatible = "st,stm32-iio-timer1";
+ };
+ };
--
1.9.1
^ permalink raw reply related
* [PATCH 0/7] Add pwm and IIO timer drivers for stm32
From: Benjamin Gaignard @ 2016-11-22 16:13 UTC (permalink / raw)
To: linux-arm-kernel
The following patches enable pwm and IIO Timer features for stm32 platforms.
Those two features are mixed into the registers of the same hardware block
(named timer) which lead to introduce a multifunctions driver on the top to
be able to share the registers.
In stm32 14 instances of timer hardware block exist, even if they all have
the same register mapping they could have a different number of pwm channels
and/or different triggers capabilities. To keep the code as simple as possible
we use compatible and platform_data to distinguish them.
The MFD (stm32-mfd-timer.c) takes care of clock, interrupt and register mapping
by using regmap. stm32_mfd_timer_dev structure is provided to its children to
share those information.
PWM driver is implemented into pwm-stm32.c. Depending of the instance we may
have up to 4 channels, sometime with complementary outputs or 32 bits counter
instead of 16 bits. Some hardware blocks may also have a break input function
which allows to stop pwm depending of a level, defined in devicetree, on an
external pin.
IIO timer driver (stm32-iio-timer.c and stm32-iio-timers.h) define a list of
hardware triggers usable by hardware blocks like ADC, DAC or other timers.
The matrix of possible connections between blocks is quite complex so we use
trigger names and is_stm32_iio_timer_trigger() function to be sure that
triggers are valid and configure the IPs.
Timer hardware blocks can configure (through "master_mode" IIO device attribute)
which internal signal (counter enable, reset, comparison block, etc...) is
used to generate the trigger.
By using "slave_mode" IIO device attribute timer can also configure on which
event (level, rising edge) of the block is enabled.
Since we can use trigger from one hardware to control an other block, we can
use a pwm to control an other one. The following example shows how to configure
pwm1 and pwm3 to make pwm3 generate pulse only when pwm1 pulse level is high.
/sys/bus/iio/devices # ls
iio:device0 iio:device1 trigger0 trigger1
configure timer1 to use pwm1 channel 0 as output trigger
/sys/bus/iio/devices # echo 4 > iio\:device0/master_mode
configure timer3 to enable only when input is high
/sys/bus/iio/devices # echo 5 > iio\:device1/slave_mode
/sys/bus/iio/devices # cat trigger0/name
tim1_trgo
configure timer2 to use timer1 trigger is input
/sys/bus/iio/devices # echo "tim1_trgo" > iio\:device1/trigger/current_trigger
configure pwm3 channel 0 to generate a signal with a period of 100ms and a
duty cycle of 50%
/sys/devices/platform/soc/40000400.mfdtimer3/pwm3/pwm/pwmchip4 # echo 0 > export
/sys/devices/platform/soc/40000400.mfdtimer3/pwm3/pwm/pwmchip4 # echo 100000000 > pwm0/period
/sys/devices/platform/soc/40000400.mfdtimer3/pwm3/pwm/pwmchip4 # echo 50000000 > pwm0/duty_cycle
/sys/devices/platform/soc/40000400.mfdtimer3/pwm3/pwm/pwmchip4 # echo 1 > pwm0/enable
here pwm3 channel 0, as expected, doesn't start because has to be triggered by
pwm1 channel 0
configure pwm1 channel 0 to generate a signal with a period of 1s and a
duty cycle of 50%
/sys/devices/platform/soc/40010000.mfdtimer1/pwm1/pwm/pwmchip0 # echo 0 > export
/sys/devices/platform/soc/40010000.mfdtimer1/pwm1/pwm/pwmchip0 # echo 1000000000 > pwm0/period
/sys/devices/platform/soc/40010000.mfdtimer1/pwm1/pwm/pwmchip0 # echo 500000000 > pwm0/duty_cycle
/sys/devices/platform/soc/40010000.mfdtimer1/pwm1/pwm/pwmchip0 # echo 1 > pwm0/enable
finally pwm1 starts and pwm3 only generates pulse when pwm1 signal is high
An other example to use a timer as source of clock for another device.
Here timer1 is used a source clock for pwm3:
/sys/bus/iio/devices # echo 100000 > trigger0/sampling_frequency
/sys/bus/iio/devices # echo tim1_trgo > iio\:device1/trigger/current_trigger
/sys/bus/iio/devices # echo 7 > iio\:device1/slave_mode
/sys/devices/platform/soc/40000400.mfdtimer3/pwm3/pwm/pwmchip4 # echo 0 > export
/sys/devices/platform/soc/40000400.mfdtimer3/pwm3/pwm/pwmchip4 # echo 1000000 > pwm0/period
/sys/devices/platform/soc/40000400.mfdtimer3/pwm3/pwm/pwmchip4 # echo 500000 > pwm0/duty_cycle
/sys/devices/platform/soc/40000400.mfdtimer3/pwm3/pwm/pwmchip4 # echo 1 > pwm0/enable
Benjamin Gaignard (7):
add binding for stm32 multifunctions timer driver
add MFD for stm32 timer IP
add pwm-stm32 DT bindings
add pwm driver for stm32 plaftorm
add bindings for stm32 IIO timer drivers
add STM32 IIO timer driver
add stm32 multi-functions timer driver in DT
.../bindings/iio/timer/stm32-iio-timer.txt | 33 +
.../devicetree/bindings/mfd/stm32-timer.txt | 53 ++
.../devicetree/bindings/pwm/pwm-stm32.txt | 43 ++
arch/arm/boot/dts/stm32f429.dtsi | 246 +++++++
arch/arm/boot/dts/stm32f469-disco.dts | 29 +
drivers/iio/Kconfig | 2 +-
drivers/iio/Makefile | 1 +
drivers/iio/timer/Kconfig | 15 +
drivers/iio/timer/Makefile | 1 +
drivers/iio/timer/stm32-iio-timer.c | 766 +++++++++++++++++++++
drivers/iio/trigger/Kconfig | 1 -
drivers/mfd/Kconfig | 10 +
drivers/mfd/Makefile | 2 +
drivers/mfd/stm32-mfd-timer.c | 236 +++++++
drivers/pwm/Kconfig | 8 +
drivers/pwm/Makefile | 1 +
drivers/pwm/pwm-stm32.c | 358 ++++++++++
include/linux/iio/timer/stm32-iio-timers.h | 25 +
include/linux/mfd/stm32-mfd-timer.h | 78 +++
19 files changed, 1906 insertions(+), 2 deletions(-)
create mode 100644 Documentation/devicetree/bindings/iio/timer/stm32-iio-timer.txt
create mode 100644 Documentation/devicetree/bindings/mfd/stm32-timer.txt
create mode 100644 Documentation/devicetree/bindings/pwm/pwm-stm32.txt
create mode 100644 drivers/iio/timer/Kconfig
create mode 100644 drivers/iio/timer/Makefile
create mode 100644 drivers/iio/timer/stm32-iio-timer.c
create mode 100644 drivers/mfd/stm32-mfd-timer.c
create mode 100644 drivers/pwm/pwm-stm32.c
create mode 100644 include/linux/iio/timer/stm32-iio-timers.h
create mode 100644 include/linux/mfd/stm32-mfd-timer.h
--
1.9.1
^ permalink raw reply
* [PATCH net-next] net: mvneta: Only disable mvneta_bm for 64-bits
From: David Miller @ 2016-11-22 16:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161122160037.14400-1-gregory.clement@free-electrons.com>
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;
^
^ permalink raw reply
* [PATCH] net: mvneta: Only disable mvneta_bm for 64-bits
From: Gregory CLEMENT @ 2016-11-22 16:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161122153848.13071-1-gregory.clement@free-electrons.com>
Hi,
On mar., nov. 22 2016, Gregory CLEMENT <gregory.clement@free-electrons.com> wrote:
> Actually only the mvneta_bm support is not 64-bits compatible.
> The mvneta code itself can run on 64-bits architecture.
I have just realized that my topic prefix was wrong (net-next was
missing), I am send a new email with the correct prefix.
Sorry for the noise.
Gregory
>
> 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
>
--
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
^ permalink raw reply
* [PATCH net-next] net: mvneta: Only disable mvneta_bm for 64-bits
From: Gregory CLEMENT @ 2016-11-22 16:00 UTC (permalink / raw)
To: linux-arm-kernel
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
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