Patch "pwm: img: Impose upper and lower timebase steps value" has been added to the 4.0-stable tree
Subsystems (2)
This is a note to let you know that I've just added the patch titled
pwm: img: Impose upper and lower timebase steps value
to the 4.0-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
pwm-img-impose-upper-and-lower-timebase-steps-value.patch
and it can be found in the queue-4.0 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
1e70897d0e20f988abedcf73b33684ecd2be9511Mon Sep 17 00:00:00 2001
From: Naidu Tellapati <[email protected]>
Date: Fri, 8 May 2015 18:47:31 -0300
Subject: pwm: img: Impose upper and lower timebase steps value
From: Naidu Tellapati <[email protected]>
commit 1e70897d0e20f988abedcf73b33684ecd2be9511 upstream.
The PWM hardware on Pistachio platform has a maximum timebase steps value to 255. To fix it, let's introduce a compatible-specific data structure to contain the SoC-specific details and use it to specify a maximum timebase.
Also, let's limit the minimum timebase to 16 steps, to allow a sane range of duty cycle steps.
--- drivers/pwm/pwm-img.c | 76 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 64 insertions(+), 12 deletions(-)
drivers/pwm/pwm-img.c +64 -12
@@ -16,6 +16,7 @@#include <linux/mfd/syscon.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/pwm.h> #include <linux/regmap.h>
@@ -38,7 +39,22 @@#define PERIP_PWM_PDM_CONTROL_CH_MASK 0x1#define PERIP_PWM_PDM_CONTROL_CH_SHIFT (ch) ((ch) * 4) -#define MAX_TMBASE_STEPS 65536 +/* +* PWM period is specified with a timebase register, +* in number of step periods. The PWM duty cycle is also +* specified in step periods, in the [0, $timebase] range. +* In other words, the timebase imposes the duty cycle +* resolution. Therefore, let's constraint the timebase to +* a minimum value to allow a sane range of duty cycle values. +* Imposing a minimum timebase, will impose a maximum PWM frequency. +* +* The value chosen is completely arbitrary. +*/ +#define MIN_TMBASE_STEPS 16 + +struct img_pwm_soc_data { +u32 max_timebase; +};struct img_pwm_chip {struct device *dev;
@@ -47,6 +63,9 @@ struct img_pwm_chip {struct clk *sys_clk;void __iomem *base;struct regmap *periph_regs; +int max_period_ns; +int min_period_ns; +const struct img_pwm_soc_data *data; };static inline struct img_pwm_chip *to_img_pwm_chip (struct pwm_chip *chip)
@@ -72,24 +91,31 @@ static int img_pwm_config(struct pwm_chiu32 val, div, duty, timebase;unsigned long mul, output_clk_hz, input_clk_hz;struct img_pwm_chip *pwm_chip =to_img_pwm_chip (chip); +unsigned int max_timebase = pwm_chip->data->max_timebase; + +if (period_ns < pwm_chip->min_period_ns || + period_ns > pwm_chip->max_period_ns) { +dev_err (chip->dev,"configured period not in range\n" ); +return -ERANGE ; + } input_clk_hz =clk_get_rate (pwm_chip->pwm_clk); output_clk_hz =DIV_ROUND_UP (NSEC_PER_SEC , period_ns); mul =DIV_ROUND_UP (input_clk_hz, output_clk_hz); -if (mul <=MAX_TMBASE_STEPS ) { +if (mul <= max_timebase) { div =PWM_CTRL_CFG_NO_SUB_DIV ; timebase =DIV_ROUND_UP (mul,1 ); - }else if (mul <=MAX_TMBASE_STEPS *8 ) { + }else if (mul <= max_timebase *8 ) { div =PWM_CTRL_CFG_SUB_DIV0 ; timebase =DIV_ROUND_UP (mul,8 ); - }else if (mul <=MAX_TMBASE_STEPS *64 ) { + }else if (mul <= max_timebase *64 ) { div =PWM_CTRL_CFG_SUB_DIV1 ; timebase =DIV_ROUND_UP (mul,64 ); - }else if (mul <=MAX_TMBASE_STEPS *512 ) { + }else if (mul <= max_timebase *512 ) { div =PWM_CTRL_CFG_SUB_DIV0_DIV1 ; timebase =DIV_ROUND_UP (mul,512 ); - }else if (mul >MAX_TMBASE_STEPS *512 ) { + }else if (mul > max_timebase *512 ) {dev_err (chip->dev,"failed to configure timebase steps/divider value\n" );return -EINVAL ;
@@ -143,11 +169,27 @@ static const struct pwm_ops img_pwm_ops .owner = THIS_MODULE, }; +static const struct img_pwm_soc_data pistachio_pwm = { + .max_timebase =255 , +}; + +static const struct of_device_id img_pwm_of_match[] = { + { + .compatible ="img,pistachio-pwm" , + .data = &pistachio_pwm, + }, + { } +}; +MODULE_DEVICE_TABLE (of, img_pwm_of_match); +static int img_pwm_probe (struct platform_device *pdev) {int ret; +u64 val; +unsigned long clk_rate;struct resource *res;struct img_pwm_chip *pwm; +const struct of_device_id *of_dev_id; pwm =devm_kzalloc (&pdev->dev,sizeof (*pwm),GFP_KERNEL );if (!pwm)
@@ -160,6 +202,11 @@ static int img_pwm_probe(struct platformif (IS_ERR (pwm->base))return PTR_ERR (pwm->base); + of_dev_id =of_match_device (img_pwm_of_match, &pdev->dev); +if (!of_dev_id) +return -ENODEV ; + pwm->data = of_dev_id->data; + pwm->periph_regs =syscon_regmap_lookup_by_phandle (pdev->dev.of_node,"img,cr-periph" );if (IS_ERR (pwm->periph_regs))
@@ -189,6 +236,17 @@ static int img_pwm_probe(struct platform goto disable_sysclk; } + clk_rate =clk_get_rate (pwm->pwm_clk); + +/* The maximum input clock divider is 512 */ + val = (u64 )NSEC_PER_SEC *512 * pwm->data->max_timebase; +do_div (val, clk_rate); + pwm->max_period_ns = val; + + val = (u64 )NSEC_PER_SEC *MIN_TMBASE_STEPS ; +do_div (val, clk_rate); + pwm->min_period_ns = val; + pwm->chip.dev = &pdev->dev; pwm->chip.ops = &img_pwm_ops; pwm->chip.base =-1 ;
@@ -228,12 +286,6 @@ static int img_pwm_remove(struct platforreturn pwmchip_remove (&pwm_chip->chip); } -static const struct of_device_id img_pwm_of_match[] = { - { .compatible ="img,pistachio-pwm" , }, - { } -}; -MODULE_DEVICE_TABLE (of, img_pwm_of_match); -static struct platform_driver img_pwm_driver = { .driver = { .name ="img-pwm" ,
Patches currently in stable-queue which might be from [email protected] are
queue-4.0/pwm-img-impose-upper-and-lower-timebase-steps-value.patch queue-4.0/iio-adc-cc10001-fix-the-channel-number-mapping.patch queue-4.0/iio-adc-cc10001-fix-regulator_get_voltage-return-value-check.patch queue-4.0/iio-adc-cc10001-add-delay-before-setting-start-bit.patch queue-4.0/iio-adc-cc10001-fix-incorrect-use-of-power-up-power-down-register.patch