Your comments are welcome on all of them ;-) 2016-11-22 17:41 GMT+01:00 Lee Jones <lee.jones@xxxxxxxxxx>: > 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@xxxxxx> >> > --- >> > 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@xxxxxx> 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@xxxxxx> 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 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html