Immutable branch between MFD, IIO and PWM due for the v4.11 merge window

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJYiNNFAAoJEFGvii+H/HdhqSEP/jNBWmiCKvci3hR0T6ujyqoR
 A7GM5soFkw25ZWi0hRPYUewA4KOn+laFnHJsHfx6h2fTeZHk3Phx/9f6uBhVENG5
 gSmAkSTsRaFGUyDU1Enq6hH9CIhdUuJh2ybIc2Fq8T1Z8hg3sGjcDfBC8T3uT/fM
 y1fdlhNzlSB1DnRO9niHQJMCGXRx7V6C4jH9epxXY2Tf5WjcFgQTpf7XrXyz7gxy
 8Zn1oLHt6nT6H70AHb3hbV48IVcVVpIN/qVHMDAXd8kvTTFh7OTi7zJIGqQKzOFr
 y83mv5fBF6V67WOLsRcd0diNgOUSFLxxp4D2j8EAjSB386V+9wfm42A04z9HNXE5
 XD2gmaVpm0H3OH3YjOHo+s/lbWAYvzb3NJ0pOHXis8dcKGW/3MH33cWHsUBe+ytv
 SOfd9u+OYbe0o2xKPUVIF6m/HXrLqWBM5+wT2F/5Z0nbIXlhXK96km4T16JD5L+A
 QWyilHmP/shDCuZ4ORl7sf0V/FY7BicOzPBpHZKOGjX+3RmCn1fo++WgdFIyVkCG
 tvIUtSONxeidaDUJ8J1tn2OR8DtdyMag7pagzypZF4JSpjfJ+IMj/6wFftgTzZgh
 yDtkfUYk9sJsBy3Bp1pfcVrcnERlIq7FND9HySQTbRFRX0+5ARx7ZXzjqidKHy6l
 yvFfnhxy1vcy8RdEh21e
 =tG0h
 -----END PGP SIGNATURE-----

Merge tag 'ib-mfd-iio-pwm-4.11' into test

Immutable branch between MFD, IIO and PWM due for the v4.11 merge window

Pulled into IIO to allow follow up series of triggered capture for the
STM32 ADCs.
This commit is contained in:
Jonathan Cameron 2017-01-28 18:21:49 +00:00
Родитель 1dc2af8787 93fbe91b55
Коммит 6db0f7ccc9
15 изменённых файлов: 1118 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,29 @@
What: /sys/bus/iio/devices/triggerX/master_mode_available
KernelVersion: 4.11
Contact: benjamin.gaignard@st.com
Description:
Reading returns the list possible master modes which are:
- "reset" : The UG bit from the TIMx_EGR register is used as trigger output (TRGO).
- "enable" : The Counter Enable signal CNT_EN is used as trigger output.
- "update" : The update event is selected as trigger output.
For instance a master timer can then be used as a prescaler for a slave timer.
- "compare_pulse" : The trigger output send a positive pulse when the CC1IF flag is to be set.
- "OC1REF" : OC1REF signal is used as trigger output.
- "OC2REF" : OC2REF signal is used as trigger output.
- "OC3REF" : OC3REF signal is used as trigger output.
- "OC4REF" : OC4REF signal is used as trigger output.
What: /sys/bus/iio/devices/triggerX/master_mode
KernelVersion: 4.11
Contact: benjamin.gaignard@st.com
Description:
Reading returns the current master modes.
Writing set the master mode
What: /sys/bus/iio/devices/triggerX/sampling_frequency
KernelVersion: 4.11
Contact: benjamin.gaignard@st.com
Description:
Reading returns the current sampling frequency.
Writing an value different of 0 set and start sampling.
Writing 0 stop sampling.

Просмотреть файл

@ -0,0 +1,23 @@
STMicroelectronics STM32 Timers IIO timer bindings
Must be a sub-node of an STM32 Timers device tree node.
See ../mfd/stm32-timers.txt for details about the parent node.
Required parameters:
- compatible: Must be "st,stm32-timer-trigger".
- reg: Identify trigger hardware block.
Example:
timers@40010000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "st,stm32-timers";
reg = <0x40010000 0x400>;
clocks = <&rcc 0 160>;
clock-names = "clk_int";
timer@0 {
compatible = "st,stm32-timer-trigger";
reg = <0>;
};
};

Просмотреть файл

@ -0,0 +1,46 @@
STM32 Timers driver bindings
This IP provides 3 types of timer along with PWM functionality:
- advanced-control timers consist of a 16-bit auto-reload counter driven by a programmable
prescaler, break input feature, PWM outputs and complementary PWM ouputs channels.
- general-purpose timers consist of a 16-bit or 32-bit auto-reload counter driven by a
programmable prescaler and PWM outputs.
- basic timers consist of a 16-bit auto-reload counter driven by a programmable prescaler.
Required parameters:
- compatible: must be "st,stm32-timers"
- reg: Physical base address and length of the controller's
registers.
- clock-names: Set to "int".
- clocks: Phandle to the clock used by the timer module.
For Clk properties, please refer to ../clock/clock-bindings.txt
Optional parameters:
- resets: Phandle to the parent reset controller.
See ../reset/st,stm32-rcc.txt
Optional subnodes:
- pwm: See ../pwm/pwm-stm32.txt
- timer: See ../iio/timer/stm32-timer-trigger.txt
Example:
timers@40010000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "st,stm32-timers";
reg = <0x40010000 0x400>;
clocks = <&rcc 0 160>;
clock-names = "clk_int";
pwm {
compatible = "st,stm32-pwm";
pinctrl-0 = <&pwm1_pins>;
pinctrl-names = "default";
};
timer@0 {
compatible = "st,stm32-timer-trigger";
reg = <0>;
};
};

Просмотреть файл

@ -0,0 +1,35 @@
STMicroelectronics STM32 Timers PWM bindings
Must be a sub-node of an STM32 Timers device tree node.
See ../mfd/stm32-timers.txt for details about the parent node.
Required parameters:
- compatible: Must be "st,stm32-pwm".
- pinctrl-names: Set to "default".
- pinctrl-0: List of phandles pointing to pin configuration nodes for PWM module.
For Pinctrl properties see ../pinctrl/pinctrl-bindings.txt
Optional parameters:
- st,breakinput: One or two <index level filter> to describe break input configurations.
"index" indicates on which break input (0 or 1) the configuration
should be applied.
"level" gives the active level (0=low or 1=high) of the input signal
for this configuration.
"filter" gives the filtering value to be applied.
Example:
timers@40010000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "st,stm32-timers";
reg = <0x40010000 0x400>;
clocks = <&rcc 0 160>;
clock-names = "clk_int";
pwm {
compatible = "st,stm32-pwm";
pinctrl-0 = <&pwm1_pins>;
pinctrl-names = "default";
st,breakinput = <0 1 5>;
};
};

Просмотреть файл

@ -24,6 +24,15 @@ config IIO_INTERRUPT_TRIGGER
To compile this driver as a module, choose M here: the
module will be called iio-trig-interrupt.
config IIO_STM32_TIMER_TRIGGER
tristate "STM32 Timer Trigger"
depends on (ARCH_STM32 && OF && MFD_STM32_TIMERS) || COMPILE_TEST
help
Select this option to enable STM32 Timer Trigger
To compile this driver as a module, choose M here: the
module will be called stm32-timer-trigger.
config IIO_TIGHTLOOP_TRIGGER
tristate "A kthread based hammering loop trigger"
depends on IIO_SW_TRIGGER

Просмотреть файл

@ -6,5 +6,6 @@
obj-$(CONFIG_IIO_HRTIMER_TRIGGER) += iio-trig-hrtimer.o
obj-$(CONFIG_IIO_INTERRUPT_TRIGGER) += iio-trig-interrupt.o
obj-$(CONFIG_IIO_STM32_TIMER_TRIGGER) += stm32-timer-trigger.o
obj-$(CONFIG_IIO_SYSFS_TRIGGER) += iio-trig-sysfs.o
obj-$(CONFIG_IIO_TIGHTLOOP_TRIGGER) += iio-trig-loop.o

Просмотреть файл

@ -0,0 +1,342 @@
/*
* Copyright (C) STMicroelectronics 2016
*
* Author: Benjamin Gaignard <benjamin.gaignard@st.com>
*
* License terms: GNU General Public License (GPL), version 2
*/
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/timer/stm32-timer-trigger.h>
#include <linux/iio/trigger.h>
#include <linux/mfd/stm32-timers.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#define MAX_TRIGGERS 6
/* List the triggers created by each timer */
static const void *triggers_table[][MAX_TRIGGERS] = {
{ TIM1_TRGO, TIM1_CH1, TIM1_CH2, TIM1_CH3, TIM1_CH4,},
{ TIM2_TRGO, TIM2_CH1, TIM2_CH2, TIM2_CH3, TIM2_CH4,},
{ TIM3_TRGO, TIM3_CH1, TIM3_CH2, TIM3_CH3, TIM3_CH4,},
{ TIM4_TRGO, TIM4_CH1, TIM4_CH2, TIM4_CH3, TIM4_CH4,},
{ TIM5_TRGO, TIM5_CH1, TIM5_CH2, TIM5_CH3, TIM5_CH4,},
{ TIM6_TRGO,},
{ TIM7_TRGO,},
{ TIM8_TRGO, TIM8_CH1, TIM8_CH2, TIM8_CH3, TIM8_CH4,},
{ TIM9_TRGO, TIM9_CH1, TIM9_CH2,},
{ }, /* timer 10 */
{ }, /* timer 11 */
{ TIM12_TRGO, TIM12_CH1, TIM12_CH2,},
};
struct stm32_timer_trigger {
struct device *dev;
struct regmap *regmap;
struct clk *clk;
u32 max_arr;
const void *triggers;
};
static int stm32_timer_start(struct stm32_timer_trigger *priv,
unsigned int frequency)
{
unsigned long long prd, div;
int prescaler = 0;
u32 ccer, cr1;
/* Period and prescaler values depends of clock rate */
div = (unsigned long long)clk_get_rate(priv->clk);
do_div(div, frequency);
prd = div;
/*
* Increase prescaler value until we get a result that fit
* with auto reload register maximum value.
*/
while (div > priv->max_arr) {
prescaler++;
div = prd;
do_div(div, (prescaler + 1));
}
prd = div;
if (prescaler > MAX_TIM_PSC) {
dev_err(priv->dev, "prescaler exceeds the maximum value\n");
return -EINVAL;
}
/* Check if nobody else use the timer */
regmap_read(priv->regmap, TIM_CCER, &ccer);
if (ccer & TIM_CCER_CCXE)
return -EBUSY;
regmap_read(priv->regmap, TIM_CR1, &cr1);
if (!(cr1 & TIM_CR1_CEN))
clk_enable(priv->clk);
regmap_write(priv->regmap, TIM_PSC, prescaler);
regmap_write(priv->regmap, TIM_ARR, prd - 1);
regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, TIM_CR1_ARPE);
/* Force master mode to update mode */
regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS, 0x20);
/* Make sure that registers are updated */
regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG);
/* Enable controller */
regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN);
return 0;
}
static void stm32_timer_stop(struct stm32_timer_trigger *priv)
{
u32 ccer, cr1;
regmap_read(priv->regmap, TIM_CCER, &ccer);
if (ccer & TIM_CCER_CCXE)
return;
regmap_read(priv->regmap, TIM_CR1, &cr1);
if (cr1 & TIM_CR1_CEN)
clk_disable(priv->clk);
/* Stop timer */
regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
regmap_write(priv->regmap, TIM_PSC, 0);
regmap_write(priv->regmap, TIM_ARR, 0);
/* Make sure that registers are updated */
regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG);
}
static ssize_t stm32_tt_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_timer_trigger *priv = iio_trigger_get_drvdata(trig);
unsigned int freq;
int ret;
ret = kstrtouint(buf, 10, &freq);
if (ret)
return ret;
if (freq == 0) {
stm32_timer_stop(priv);
} else {
ret = stm32_timer_start(priv, freq);
if (ret)
return ret;
}
return len;
}
static ssize_t stm32_tt_read_frequency(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct iio_trigger *trig = to_iio_trigger(dev);
struct stm32_timer_trigger *priv = iio_trigger_get_drvdata(trig);
u32 psc, arr, cr1;
unsigned long long freq = 0;
regmap_read(priv->regmap, TIM_CR1, &cr1);
regmap_read(priv->regmap, TIM_PSC, &psc);
regmap_read(priv->regmap, TIM_ARR, &arr);
if (psc && arr && (cr1 & TIM_CR1_CEN)) {
freq = (unsigned long long)clk_get_rate(priv->clk);
do_div(freq, psc);
do_div(freq, arr);
}
return sprintf(buf, "%d\n", (unsigned int)freq);
}
static IIO_DEV_ATTR_SAMP_FREQ(0660,
stm32_tt_read_frequency,
stm32_tt_store_frequency);
static char *master_mode_table[] = {
"reset",
"enable",
"update",
"compare_pulse",
"OC1REF",
"OC2REF",
"OC3REF",
"OC4REF"
};
static ssize_t stm32_tt_show_master_mode(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct stm32_timer_trigger *priv = iio_priv(indio_dev);
u32 cr2;
regmap_read(priv->regmap, TIM_CR2, &cr2);
cr2 = (cr2 & TIM_CR2_MMS) >> TIM_CR2_MMS_SHIFT;
return snprintf(buf, PAGE_SIZE, "%s\n", master_mode_table[cr2]);
}
static ssize_t stm32_tt_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_timer_trigger *priv = iio_priv(indio_dev);
int i;
for (i = 0; i < ARRAY_SIZE(master_mode_table); i++) {
if (!strncmp(master_mode_table[i], buf,
strlen(master_mode_table[i]))) {
regmap_update_bits(priv->regmap, TIM_CR2,
TIM_CR2_MMS, i << TIM_CR2_MMS_SHIFT);
/* Make sure that registers are updated */
regmap_update_bits(priv->regmap, TIM_EGR,
TIM_EGR_UG, TIM_EGR_UG);
return len;
}
}
return -EINVAL;
}
static IIO_CONST_ATTR(master_mode_available,
"reset enable update compare_pulse OC1REF OC2REF OC3REF OC4REF");
static IIO_DEVICE_ATTR(master_mode, 0660,
stm32_tt_show_master_mode,
stm32_tt_store_master_mode,
0);
static struct attribute *stm32_trigger_attrs[] = {
&iio_dev_attr_sampling_frequency.dev_attr.attr,
&iio_dev_attr_master_mode.dev_attr.attr,
&iio_const_attr_master_mode_available.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 const struct iio_trigger_ops timer_trigger_ops = {
.owner = THIS_MODULE,
};
static int stm32_setup_iio_triggers(struct stm32_timer_trigger *priv)
{
int ret;
const char * const *cur = priv->triggers;
while (cur && *cur) {
struct iio_trigger *trig;
trig = devm_iio_trigger_alloc(priv->dev, "%s", *cur);
if (!trig)
return -ENOMEM;
trig->dev.parent = priv->dev->parent;
trig->ops = &timer_trigger_ops;
/*
* sampling frequency and master mode attributes
* should only be available on trgo trigger which
* is always the first in the list.
*/
if (cur == priv->triggers)
trig->dev.groups = stm32_trigger_attr_groups;
iio_trigger_set_drvdata(trig, priv);
ret = devm_iio_trigger_register(priv->dev, trig);
if (ret)
return ret;
cur++;
}
return 0;
}
/**
* is_stm32_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_timer_trigger(struct iio_trigger *trig)
{
return (trig->ops == &timer_trigger_ops);
}
EXPORT_SYMBOL(is_stm32_timer_trigger);
static int stm32_timer_trigger_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct stm32_timer_trigger *priv;
struct stm32_timers *ddata = dev_get_drvdata(pdev->dev.parent);
unsigned int index;
int ret;
if (of_property_read_u32(dev->of_node, "reg", &index))
return -EINVAL;
if (index >= ARRAY_SIZE(triggers_table))
return -EINVAL;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->dev = dev;
priv->regmap = ddata->regmap;
priv->clk = ddata->clk;
priv->max_arr = ddata->max_arr;
priv->triggers = triggers_table[index];
ret = stm32_setup_iio_triggers(priv);
if (ret)
return ret;
platform_set_drvdata(pdev, priv);
return 0;
}
static const struct of_device_id stm32_trig_of_match[] = {
{ .compatible = "st,stm32-timer-trigger", },
{ /* end node */ },
};
MODULE_DEVICE_TABLE(of, stm32_trig_of_match);
static struct platform_driver stm32_timer_trigger_driver = {
.probe = stm32_timer_trigger_probe,
.driver = {
.name = "stm32-timer-trigger",
.of_match_table = stm32_trig_of_match,
},
};
module_platform_driver(stm32_timer_trigger_driver);
MODULE_ALIAS("platform: stm32-timer-trigger");
MODULE_DESCRIPTION("STMicroelectronics STM32 Timer Trigger driver");
MODULE_LICENSE("GPL v2");

Просмотреть файл

@ -1621,6 +1621,17 @@ config MFD_STW481X
in various ST Microelectronics and ST-Ericsson embedded
Nomadik series.
config MFD_STM32_TIMERS
tristate "Support for STM32 Timers"
depends on (ARCH_STM32 && OF) || COMPILE_TEST
select MFD_CORE
select REGMAP
select REGMAP_MMIO
help
Select this option to enable STM32 timers driver used
for PWM and IIO Timer. This driver allow to share the
registers between the others drivers.
menu "Multimedia Capabilities Port drivers"
depends on ARCH_SA1100

Просмотреть файл

@ -212,3 +212,5 @@ obj-$(CONFIG_MFD_MT6397) += mt6397-core.o
obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o
obj-$(CONFIG_MFD_SUN4I_GPADC) += sun4i-gpadc.o
obj-$(CONFIG_MFD_STM32_TIMERS) += stm32-timers.o

Просмотреть файл

@ -0,0 +1,80 @@
/*
* Copyright (C) STMicroelectronics 2016
*
* Author: Benjamin Gaignard <benjamin.gaignard@st.com>
*
* License terms: GNU General Public License (GPL), version 2
*/
#include <linux/mfd/stm32-timers.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/reset.h>
static const struct regmap_config stm32_timers_regmap_cfg = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = sizeof(u32),
.max_register = 0x400,
};
static void stm32_timers_get_arr_size(struct stm32_timers *ddata)
{
/*
* Only the available bits will be written so when readback
* we get the maximum value of auto reload register
*/
regmap_write(ddata->regmap, TIM_ARR, ~0L);
regmap_read(ddata->regmap, TIM_ARR, &ddata->max_arr);
regmap_write(ddata->regmap, TIM_ARR, 0x0);
}
static int stm32_timers_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct stm32_timers *ddata;
struct resource *res;
void __iomem *mmio;
ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
if (!ddata)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
mmio = devm_ioremap_resource(dev, res);
if (IS_ERR(mmio))
return PTR_ERR(mmio);
ddata->regmap = devm_regmap_init_mmio_clk(dev, "int", mmio,
&stm32_timers_regmap_cfg);
if (IS_ERR(ddata->regmap))
return PTR_ERR(ddata->regmap);
ddata->clk = devm_clk_get(dev, NULL);
if (IS_ERR(ddata->clk))
return PTR_ERR(ddata->clk);
stm32_timers_get_arr_size(ddata);
platform_set_drvdata(pdev, ddata);
return of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
}
static const struct of_device_id stm32_timers_of_match[] = {
{ .compatible = "st,stm32-timers", },
{ /* end node */ },
};
MODULE_DEVICE_TABLE(of, stm32_timers_of_match);
static struct platform_driver stm32_timers_driver = {
.probe = stm32_timers_probe,
.driver = {
.name = "stm32-timers",
.of_match_table = stm32_timers_of_match,
},
};
module_platform_driver(stm32_timers_driver);
MODULE_DESCRIPTION("STMicroelectronics STM32 Timers");
MODULE_LICENSE("GPL v2");

Просмотреть файл

@ -397,6 +397,15 @@ config PWM_STI
To compile this driver as a module, choose M here: the module
will be called pwm-sti.
config PWM_STM32
tristate "STMicroelectronics STM32 PWM"
depends on MFD_STM32_TIMERS || COMPILE_TEST
help
Generic PWM framework driver for STM32 SoCs.
To compile this driver as a module, choose M here: the module
will be called pwm-stm32.
config PWM_STMPE
bool "STMPE expander PWM export"
depends on MFD_STMPE

Просмотреть файл

@ -38,6 +38,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

397
drivers/pwm/pwm-stm32.c Normal file
Просмотреть файл

@ -0,0 +1,397 @@
/*
* 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/mfd/stm32-timers.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pwm.h>
#define CCMR_CHANNEL_SHIFT 8
#define CCMR_CHANNEL_MASK 0xFF
#define MAX_BREAKINPUT 2
struct stm32_pwm {
struct pwm_chip chip;
struct device *dev;
struct clk *clk;
struct regmap *regmap;
u32 max_arr;
bool have_complementary_output;
};
struct stm32_breakinput {
u32 index;
u32 level;
u32 filter;
};
static inline struct stm32_pwm *to_stm32_pwm_dev(struct pwm_chip *chip)
{
return container_of(chip, struct stm32_pwm, chip);
}
static u32 active_channels(struct stm32_pwm *dev)
{
u32 ccer;
regmap_read(dev->regmap, TIM_CCER, &ccer);
return ccer & TIM_CCER_CCXE;
}
static int write_ccrx(struct stm32_pwm *dev, int ch, u32 value)
{
switch (ch) {
case 0:
return regmap_write(dev->regmap, TIM_CCR1, value);
case 1:
return regmap_write(dev->regmap, TIM_CCR2, value);
case 2:
return regmap_write(dev->regmap, TIM_CCR3, value);
case 3:
return regmap_write(dev->regmap, TIM_CCR4, value);
}
return -EINVAL;
}
static int stm32_pwm_config(struct stm32_pwm *priv, int ch,
int duty_ns, int period_ns)
{
unsigned long long prd, div, dty;
unsigned int prescaler = 0;
u32 ccmr, mask, shift;
/* Period and prescaler values depends on clock rate */
div = (unsigned long long)clk_get_rate(priv->clk) * period_ns;
do_div(div, NSEC_PER_SEC);
prd = div;
while (div > priv->max_arr) {
prescaler++;
div = prd;
do_div(div, prescaler + 1);
}
prd = div;
if (prescaler > MAX_TIM_PSC)
return -EINVAL;
/*
* All channels share the same prescaler and counter so when two
* channels are active at the same time we can't change them
*/
if (active_channels(priv) & ~(1 << ch * 4)) {
u32 psc, arr;
regmap_read(priv->regmap, TIM_PSC, &psc);
regmap_read(priv->regmap, TIM_ARR, &arr);
if ((psc != prescaler) || (arr != prd - 1))
return -EBUSY;
}
regmap_write(priv->regmap, TIM_PSC, prescaler);
regmap_write(priv->regmap, TIM_ARR, prd - 1);
regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, TIM_CR1_ARPE);
/* Calculate the duty cycles */
dty = prd * duty_ns;
do_div(dty, period_ns);
write_ccrx(priv, ch, dty);
/* Configure output mode */
shift = (ch & 0x1) * CCMR_CHANNEL_SHIFT;
ccmr = (TIM_CCMR_PE | TIM_CCMR_M1) << shift;
mask = CCMR_CHANNEL_MASK << shift;
if (ch < 2)
regmap_update_bits(priv->regmap, TIM_CCMR1, mask, ccmr);
else
regmap_update_bits(priv->regmap, TIM_CCMR2, mask, ccmr);
regmap_update_bits(priv->regmap, TIM_BDTR,
TIM_BDTR_MOE | TIM_BDTR_AOE,
TIM_BDTR_MOE | TIM_BDTR_AOE);
return 0;
}
static int stm32_pwm_set_polarity(struct stm32_pwm *priv, int ch,
enum pwm_polarity polarity)
{
u32 mask;
mask = TIM_CCER_CC1P << (ch * 4);
if (priv->have_complementary_output)
mask |= TIM_CCER_CC1NP << (ch * 4);
regmap_update_bits(priv->regmap, TIM_CCER, mask,
polarity == PWM_POLARITY_NORMAL ? 0 : mask);
return 0;
}
static int stm32_pwm_enable(struct stm32_pwm *priv, int ch)
{
u32 mask;
int ret;
ret = clk_enable(priv->clk);
if (ret)
return ret;
/* Enable channel */
mask = TIM_CCER_CC1E << (ch * 4);
if (priv->have_complementary_output)
mask |= TIM_CCER_CC1NE << (ch * 4);
regmap_update_bits(priv->regmap, TIM_CCER, mask, mask);
/* Make sure that registers are updated */
regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG);
/* Enable controller */
regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN);
return 0;
}
static void stm32_pwm_disable(struct stm32_pwm *priv, int ch)
{
u32 mask;
/* Disable channel */
mask = TIM_CCER_CC1E << (ch * 4);
if (priv->have_complementary_output)
mask |= TIM_CCER_CC1NE << (ch * 4);
regmap_update_bits(priv->regmap, TIM_CCER, mask, 0);
/* When all channels are disabled, we can disable the controller */
if (!active_channels(priv))
regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
clk_disable(priv->clk);
}
static int stm32_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
struct pwm_state *state)
{
bool enabled;
struct stm32_pwm *priv = to_stm32_pwm_dev(chip);
int ret;
enabled = pwm->state.enabled;
if (enabled && !state->enabled) {
stm32_pwm_disable(priv, pwm->hwpwm);
return 0;
}
if (state->polarity != pwm->state.polarity)
stm32_pwm_set_polarity(priv, pwm->hwpwm, state->polarity);
ret = stm32_pwm_config(priv, pwm->hwpwm,
state->duty_cycle, state->period);
if (ret)
return ret;
if (!enabled && state->enabled)
ret = stm32_pwm_enable(priv, pwm->hwpwm);
return ret;
}
static const struct pwm_ops stm32pwm_ops = {
.owner = THIS_MODULE,
.apply = stm32_pwm_apply,
};
static int stm32_pwm_set_breakinput(struct stm32_pwm *priv,
int index, int level, int filter)
{
u32 bke = (index == 0) ? TIM_BDTR_BKE : TIM_BDTR_BK2E;
int shift = (index == 0) ? TIM_BDTR_BKF_SHIFT : TIM_BDTR_BK2F_SHIFT;
u32 mask = (index == 0) ? TIM_BDTR_BKE | TIM_BDTR_BKP | TIM_BDTR_BKF
: TIM_BDTR_BK2E | TIM_BDTR_BK2P | TIM_BDTR_BK2F;
u32 bdtr = bke;
/*
* The both bits could be set since only one will be wrote
* due to mask value.
*/
if (level)
bdtr |= TIM_BDTR_BKP | TIM_BDTR_BK2P;
bdtr |= (filter & TIM_BDTR_BKF_MASK) << shift;
regmap_update_bits(priv->regmap, TIM_BDTR, mask, bdtr);
regmap_read(priv->regmap, TIM_BDTR, &bdtr);
return (bdtr & bke) ? 0 : -EINVAL;
}
static int stm32_pwm_apply_breakinputs(struct stm32_pwm *priv,
struct device_node *np)
{
struct stm32_breakinput breakinput[MAX_BREAKINPUT];
int nb, ret, i, array_size;
nb = of_property_count_elems_of_size(np, "st,breakinput",
sizeof(struct stm32_breakinput));
/*
* Because "st,breakinput" parameter is optional do not make probe
* failed if it doesn't exist.
*/
if (nb <= 0)
return 0;
if (nb > MAX_BREAKINPUT)
return -EINVAL;
array_size = nb * sizeof(struct stm32_breakinput) / sizeof(u32);
ret = of_property_read_u32_array(np, "st,breakinput",
(u32 *)breakinput, array_size);
if (ret)
return ret;
for (i = 0; i < nb && !ret; i++) {
ret = stm32_pwm_set_breakinput(priv,
breakinput[i].index,
breakinput[i].level,
breakinput[i].filter);
}
return ret;
}
static void stm32_pwm_detect_complementary(struct stm32_pwm *priv)
{
u32 ccer;
/*
* If complementary bit doesn't exist writing 1 will have no
* effect so we can detect it.
*/
regmap_update_bits(priv->regmap,
TIM_CCER, TIM_CCER_CC1NE, TIM_CCER_CC1NE);
regmap_read(priv->regmap, TIM_CCER, &ccer);
regmap_update_bits(priv->regmap, TIM_CCER, TIM_CCER_CC1NE, 0);
priv->have_complementary_output = (ccer != 0);
}
static int stm32_pwm_detect_channels(struct stm32_pwm *priv)
{
u32 ccer;
int npwm = 0;
/*
* If channels enable bits don't exist writing 1 will have no
* effect so we can detect and count them.
*/
regmap_update_bits(priv->regmap,
TIM_CCER, TIM_CCER_CCXE, TIM_CCER_CCXE);
regmap_read(priv->regmap, TIM_CCER, &ccer);
regmap_update_bits(priv->regmap, TIM_CCER, TIM_CCER_CCXE, 0);
if (ccer & TIM_CCER_CC1E)
npwm++;
if (ccer & TIM_CCER_CC2E)
npwm++;
if (ccer & TIM_CCER_CC3E)
npwm++;
if (ccer & TIM_CCER_CC4E)
npwm++;
return npwm;
}
static int stm32_pwm_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct stm32_timers *ddata = dev_get_drvdata(pdev->dev.parent);
struct stm32_pwm *priv;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->regmap = ddata->regmap;
priv->clk = ddata->clk;
priv->max_arr = ddata->max_arr;
if (!priv->regmap || !priv->clk)
return -EINVAL;
ret = stm32_pwm_apply_breakinputs(priv, np);
if (ret)
return ret;
stm32_pwm_detect_complementary(priv);
priv->chip.base = -1;
priv->chip.dev = dev;
priv->chip.ops = &stm32pwm_ops;
priv->chip.npwm = stm32_pwm_detect_channels(priv);
ret = pwmchip_add(&priv->chip);
if (ret < 0)
return ret;
platform_set_drvdata(pdev, priv);
return 0;
}
static int stm32_pwm_remove(struct platform_device *pdev)
{
struct stm32_pwm *priv = platform_get_drvdata(pdev);
unsigned int i;
for (i = 0; i < priv->chip.npwm; i++)
pwm_disable(&priv->chip.pwms[i]);
pwmchip_remove(&priv->chip);
return 0;
}
static const struct of_device_id stm32_pwm_of_match[] = {
{ .compatible = "st,stm32-pwm", },
{ /* end node */ },
};
MODULE_DEVICE_TABLE(of, stm32_pwm_of_match);
static struct platform_driver stm32_pwm_driver = {
.probe = stm32_pwm_probe,
.remove = stm32_pwm_remove,
.driver = {
.name = "stm32-pwm",
.of_match_table = stm32_pwm_of_match,
},
};
module_platform_driver(stm32_pwm_driver);
MODULE_ALIAS("platform:stm32-pwm");
MODULE_DESCRIPTION("STMicroelectronics STM32 PWM driver");
MODULE_LICENSE("GPL v2");

Просмотреть файл

@ -0,0 +1,62 @@
/*
* Copyright (C) STMicroelectronics 2016
*
* Author: Benjamin Gaignard <benjamin.gaignard@st.com>
*
* License terms: GNU General Public License (GPL), version 2
*/
#ifndef _STM32_TIMER_TRIGGER_H_
#define _STM32_TIMER_TRIGGER_H_
#define TIM1_TRGO "tim1_trgo"
#define TIM1_CH1 "tim1_ch1"
#define TIM1_CH2 "tim1_ch2"
#define TIM1_CH3 "tim1_ch3"
#define TIM1_CH4 "tim1_ch4"
#define TIM2_TRGO "tim2_trgo"
#define TIM2_CH1 "tim2_ch1"
#define TIM2_CH2 "tim2_ch2"
#define TIM2_CH3 "tim2_ch3"
#define TIM2_CH4 "tim2_ch4"
#define TIM3_TRGO "tim3_trgo"
#define TIM3_CH1 "tim3_ch1"
#define TIM3_CH2 "tim3_ch2"
#define TIM3_CH3 "tim3_ch3"
#define TIM3_CH4 "tim3_ch4"
#define TIM4_TRGO "tim4_trgo"
#define TIM4_CH1 "tim4_ch1"
#define TIM4_CH2 "tim4_ch2"
#define TIM4_CH3 "tim4_ch3"
#define TIM4_CH4 "tim4_ch4"
#define TIM5_TRGO "tim5_trgo"
#define TIM5_CH1 "tim5_ch1"
#define TIM5_CH2 "tim5_ch2"
#define TIM5_CH3 "tim5_ch3"
#define TIM5_CH4 "tim5_ch4"
#define TIM6_TRGO "tim6_trgo"
#define TIM7_TRGO "tim7_trgo"
#define TIM8_TRGO "tim8_trgo"
#define TIM8_CH1 "tim8_ch1"
#define TIM8_CH2 "tim8_ch2"
#define TIM8_CH3 "tim8_ch3"
#define TIM8_CH4 "tim8_ch4"
#define TIM9_TRGO "tim9_trgo"
#define TIM9_CH1 "tim9_ch1"
#define TIM9_CH2 "tim9_ch2"
#define TIM12_TRGO "tim12_trgo"
#define TIM12_CH1 "tim12_ch1"
#define TIM12_CH2 "tim12_ch2"
bool is_stm32_timer_trigger(struct iio_trigger *trig);
#endif

Просмотреть файл

@ -0,0 +1,71 @@
/*
* Copyright (C) STMicroelectronics 2016
*
* Author: Benjamin Gaignard <benjamin.gaignard@st.com>
*
* License terms: GNU General Public License (GPL), version 2
*/
#ifndef _LINUX_STM32_GPTIMER_H_
#define _LINUX_STM32_GPTIMER_H_
#include <linux/clk.h>
#include <linux/regmap.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_CC2E BIT(4) /* Capt/Comp 2 out Ena */
#define TIM_CCER_CC3E BIT(8) /* Capt/Comp 3 out Ena */
#define TIM_CCER_CC4E BIT(12) /* Capt/Comp 4 out Ena */
#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 TIM_BDTR_BKF (BIT(16) | BIT(17) | BIT(18) | BIT(19))
#define TIM_BDTR_BK2F (BIT(20) | BIT(21) | BIT(22) | BIT(23))
#define TIM_BDTR_BK2E BIT(24) /* Break 2 input enable */
#define TIM_BDTR_BK2P BIT(25) /* Break 2 input polarity */
#define MAX_TIM_PSC 0xFFFF
#define TIM_CR2_MMS_SHIFT 4
#define TIM_SMCR_TS_SHIFT 4
#define TIM_BDTR_BKF_MASK 0xF
#define TIM_BDTR_BKF_SHIFT 16
#define TIM_BDTR_BK2F_SHIFT 20
struct stm32_timers {
struct clk *clk;
struct regmap *regmap;
u32 max_arr;
};
#endif