Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
18c58878
Commit
18c58878
authored
May 17, 2016
by
Thierry Reding
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'for-4.7/pwm-atomic' into for-next
parents
d2a3f206
23e3523f
Changes
22
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
580 additions
and
213 deletions
+580
-213
Documentation/pwm.txt
Documentation/pwm.txt
+28
-2
arch/arm/mach-s3c24xx/mach-rx1950.c
arch/arm/mach-s3c24xx/mach-rx1950.c
+6
-0
drivers/clk/clk-pwm.c
drivers/clk/clk-pwm.c
+12
-5
drivers/gpu/drm/i915/intel_panel.c
drivers/gpu/drm/i915/intel_panel.c
+6
-0
drivers/hwmon/pwm-fan.c
drivers/hwmon/pwm-fan.c
+20
-6
drivers/input/misc/max77693-haptic.c
drivers/input/misc/max77693-haptic.c
+14
-3
drivers/input/misc/max8997_haptic.c
drivers/input/misc/max8997_haptic.c
+6
-0
drivers/input/misc/pwm-beeper.c
drivers/input/misc/pwm-beeper.c
+6
-0
drivers/leds/leds-pwm.c
drivers/leds/leds-pwm.c
+10
-1
drivers/pwm/core.c
drivers/pwm/core.c
+132
-90
drivers/pwm/pwm-crc.c
drivers/pwm/pwm-crc.c
+1
-1
drivers/pwm/pwm-lpc18xx-sct.c
drivers/pwm/pwm-lpc18xx-sct.c
+1
-1
drivers/pwm/pwm-omap-dmtimer.c
drivers/pwm/pwm-omap-dmtimer.c
+1
-1
drivers/pwm/pwm-rcar.c
drivers/pwm/pwm-rcar.c
+1
-1
drivers/pwm/pwm-sun4i.c
drivers/pwm/pwm-sun4i.c
+2
-1
drivers/pwm/sysfs.c
drivers/pwm/sysfs.c
+56
-14
drivers/video/backlight/lm3630a_bl.c
drivers/video/backlight/lm3630a_bl.c
+7
-2
drivers/video/backlight/lp855x_bl.c
drivers/video/backlight/lp855x_bl.c
+6
-0
drivers/video/backlight/lp8788_bl.c
drivers/video/backlight/lp8788_bl.c
+6
-0
drivers/video/backlight/pwm_bl.c
drivers/video/backlight/pwm_bl.c
+10
-4
drivers/video/fbdev/ssd1307fb.c
drivers/video/fbdev/ssd1307fb.c
+10
-1
include/linux/pwm.h
include/linux/pwm.h
+239
-80
No files found.
Documentation/pwm.txt
View file @
18c58878
...
...
@@ -42,9 +42,26 @@ variants of these functions, devm_pwm_get() and devm_pwm_put(), also exist.
After being requested, a PWM has to be configured using:
int pwm_
config(struct pwm_device *pwm, int duty_ns, int period_ns
);
int pwm_
apply_state(struct pwm_device *pwm, struct pwm_state *state
);
To start/stop toggling the PWM output use pwm_enable()/pwm_disable().
This API controls both the PWM period/duty_cycle config and the
enable/disable state.
The pwm_config(), pwm_enable() and pwm_disable() functions are just wrappers
around pwm_apply_state() and should not be used if the user wants to change
several parameter at once. For example, if you see pwm_config() and
pwm_{enable,disable}() calls in the same function, this probably means you
should switch to pwm_apply_state().
The PWM user API also allows one to query the PWM state with pwm_get_state().
In addition to the PWM state, the PWM API also exposes PWM arguments, which
are the reference PWM config one should use on this PWM.
PWM arguments are usually platform-specific and allows the PWM user to only
care about dutycycle relatively to the full period (like, duty = 50% of the
period). struct pwm_args contains 2 fields (period and polarity) and should
be used to set the initial PWM config (usually done in the probe function
of the PWM user). PWM arguments are retrieved with pwm_get_args().
Using PWMs with the sysfs interface
-----------------------------------
...
...
@@ -105,6 +122,15 @@ goes low for the remainder of the period. Conversely, a signal with inversed
polarity starts low for the duration of the duty cycle and goes high for the
remainder of the period.
Drivers are encouraged to implement ->apply() instead of the legacy
->enable(), ->disable() and ->config() methods. Doing that should provide
atomicity in the PWM config workflow, which is required when the PWM controls
a critical device (like a regulator).
The implementation of ->get_state() (a method used to retrieve initial PWM
state) is also encouraged for the same reason: letting the PWM user know
about the current PWM state would allow him to avoid glitches.
Locking
-------
...
...
arch/arm/mach-s3c24xx/mach-rx1950.c
View file @
18c58878
...
...
@@ -496,6 +496,12 @@ static int rx1950_backlight_init(struct device *dev)
return
PTR_ERR
(
lcd_pwm
);
}
/*
* FIXME: pwm_apply_args() should be removed when switching to
* the atomic PWM API.
*/
pwm_apply_args
(
lcd_pwm
);
rx1950_lcd_power
(
1
);
rx1950_bl_power
(
1
);
...
...
drivers/clk/clk-pwm.c
View file @
18c58878
...
...
@@ -59,6 +59,7 @@ static int clk_pwm_probe(struct platform_device *pdev)
struct
clk_init_data
init
;
struct
clk_pwm
*
clk_pwm
;
struct
pwm_device
*
pwm
;
struct
pwm_args
pargs
;
const
char
*
clk_name
;
struct
clk
*
clk
;
int
ret
;
...
...
@@ -71,22 +72,28 @@ static int clk_pwm_probe(struct platform_device *pdev)
if
(
IS_ERR
(
pwm
))
return
PTR_ERR
(
pwm
);
if
(
!
pwm
->
period
)
{
pwm_get_args
(
pwm
,
&
pargs
);
if
(
!
pargs
.
period
)
{
dev_err
(
&
pdev
->
dev
,
"invalid PWM period
\n
"
);
return
-
EINVAL
;
}
if
(
of_property_read_u32
(
node
,
"clock-frequency"
,
&
clk_pwm
->
fixed_rate
))
clk_pwm
->
fixed_rate
=
NSEC_PER_SEC
/
p
wm
->
period
;
clk_pwm
->
fixed_rate
=
NSEC_PER_SEC
/
p
args
.
period
;
if
(
p
wm
->
period
!=
NSEC_PER_SEC
/
clk_pwm
->
fixed_rate
&&
p
wm
->
period
!=
DIV_ROUND_UP
(
NSEC_PER_SEC
,
clk_pwm
->
fixed_rate
))
{
if
(
p
args
.
period
!=
NSEC_PER_SEC
/
clk_pwm
->
fixed_rate
&&
p
args
.
period
!=
DIV_ROUND_UP
(
NSEC_PER_SEC
,
clk_pwm
->
fixed_rate
))
{
dev_err
(
&
pdev
->
dev
,
"clock-frequency does not match PWM period
\n
"
);
return
-
EINVAL
;
}
ret
=
pwm_config
(
pwm
,
(
pwm
->
period
+
1
)
>>
1
,
pwm
->
period
);
/*
* FIXME: pwm_apply_args() should be removed when switching to the
* atomic PWM API.
*/
pwm_apply_args
(
pwm
);
ret
=
pwm_config
(
pwm
,
(
pargs
.
period
+
1
)
>>
1
,
pargs
.
period
);
if
(
ret
<
0
)
return
ret
;
...
...
drivers/gpu/drm/i915/intel_panel.c
View file @
18c58878
...
...
@@ -1640,6 +1640,12 @@ static int pwm_setup_backlight(struct intel_connector *connector,
return
-
ENODEV
;
}
/*
* FIXME: pwm_apply_args() should be removed when switching to
* the atomic PWM API.
*/
pwm_apply_args
(
panel
->
backlight
.
pwm
);
retval
=
pwm_config
(
panel
->
backlight
.
pwm
,
CRC_PMIC_PWM_PERIOD_NS
,
CRC_PMIC_PWM_PERIOD_NS
);
if
(
retval
<
0
)
{
...
...
drivers/hwmon/pwm-fan.c
View file @
18c58878
...
...
@@ -40,15 +40,18 @@ struct pwm_fan_ctx {
static
int
__set_pwm
(
struct
pwm_fan_ctx
*
ctx
,
unsigned
long
pwm
)
{
struct
pwm_args
pargs
;
unsigned
long
duty
;
int
ret
=
0
;
pwm_get_args
(
ctx
->
pwm
,
&
pargs
);
mutex_lock
(
&
ctx
->
lock
);
if
(
ctx
->
pwm_value
==
pwm
)
goto
exit_set_pwm_err
;
duty
=
DIV_ROUND_UP
(
pwm
*
(
ctx
->
pwm
->
period
-
1
),
MAX_PWM
);
ret
=
pwm_config
(
ctx
->
pwm
,
duty
,
ctx
->
pwm
->
period
);
duty
=
DIV_ROUND_UP
(
pwm
*
(
pargs
.
period
-
1
),
MAX_PWM
);
ret
=
pwm_config
(
ctx
->
pwm
,
duty
,
pargs
.
period
);
if
(
ret
)
goto
exit_set_pwm_err
;
...
...
@@ -215,6 +218,7 @@ static int pwm_fan_probe(struct platform_device *pdev)
{
struct
thermal_cooling_device
*
cdev
;
struct
pwm_fan_ctx
*
ctx
;
struct
pwm_args
pargs
;
struct
device
*
hwmon
;
int
duty_cycle
;
int
ret
;
...
...
@@ -233,11 +237,19 @@ static int pwm_fan_probe(struct platform_device *pdev)
platform_set_drvdata
(
pdev
,
ctx
);
/*
* FIXME: pwm_apply_args() should be removed when switching to the
* atomic PWM API.
*/
pwm_apply_args
(
ctx
->
pwm
);
/* Set duty cycle to maximum allowed */
duty_cycle
=
ctx
->
pwm
->
period
-
1
;
pwm_get_args
(
ctx
->
pwm
,
&
pargs
);
duty_cycle
=
pargs
.
period
-
1
;
ctx
->
pwm_value
=
MAX_PWM
;
ret
=
pwm_config
(
ctx
->
pwm
,
duty_cycle
,
ctx
->
pwm
->
period
);
ret
=
pwm_config
(
ctx
->
pwm
,
duty_cycle
,
pargs
.
period
);
if
(
ret
)
{
dev_err
(
&
pdev
->
dev
,
"Failed to configure PWM
\n
"
);
return
ret
;
...
...
@@ -303,14 +315,16 @@ static int pwm_fan_suspend(struct device *dev)
static
int
pwm_fan_resume
(
struct
device
*
dev
)
{
struct
pwm_fan_ctx
*
ctx
=
dev_get_drvdata
(
dev
);
struct
pwm_args
pargs
;
unsigned
long
duty
;
int
ret
;
if
(
ctx
->
pwm_value
==
0
)
return
0
;
duty
=
DIV_ROUND_UP
(
ctx
->
pwm_value
*
(
ctx
->
pwm
->
period
-
1
),
MAX_PWM
);
ret
=
pwm_config
(
ctx
->
pwm
,
duty
,
ctx
->
pwm
->
period
);
pwm_get_args
(
ctx
->
pwm
,
&
pargs
);
duty
=
DIV_ROUND_UP
(
ctx
->
pwm_value
*
(
pargs
.
period
-
1
),
MAX_PWM
);
ret
=
pwm_config
(
ctx
->
pwm
,
duty
,
pargs
.
period
);
if
(
ret
)
return
ret
;
return
pwm_enable
(
ctx
->
pwm
);
...
...
drivers/input/misc/max77693-haptic.c
View file @
18c58878
...
...
@@ -70,10 +70,13 @@ struct max77693_haptic {
static
int
max77693_haptic_set_duty_cycle
(
struct
max77693_haptic
*
haptic
)
{
int
delta
=
(
haptic
->
pwm_dev
->
period
+
haptic
->
pwm_duty
)
/
2
;
struct
pwm_args
pargs
;
int
delta
;
int
error
;
error
=
pwm_config
(
haptic
->
pwm_dev
,
delta
,
haptic
->
pwm_dev
->
period
);
pwm_get_args
(
haptic
->
pwm_dev
,
&
pargs
);
delta
=
(
pargs
.
period
+
haptic
->
pwm_duty
)
/
2
;
error
=
pwm_config
(
haptic
->
pwm_dev
,
delta
,
pargs
.
period
);
if
(
error
)
{
dev_err
(
haptic
->
dev
,
"failed to configure pwm: %d
\n
"
,
error
);
return
error
;
...
...
@@ -234,6 +237,7 @@ static int max77693_haptic_play_effect(struct input_dev *dev, void *data,
struct
ff_effect
*
effect
)
{
struct
max77693_haptic
*
haptic
=
input_get_drvdata
(
dev
);
struct
pwm_args
pargs
;
u64
period_mag_multi
;
haptic
->
magnitude
=
effect
->
u
.
rumble
.
strong_magnitude
;
...
...
@@ -245,7 +249,8 @@ static int max77693_haptic_play_effect(struct input_dev *dev, void *data,
* The formula to convert magnitude to pwm_duty as follows:
* - pwm_duty = (magnitude * pwm_period) / MAX_MAGNITUDE(0xFFFF)
*/
period_mag_multi
=
(
u64
)
haptic
->
pwm_dev
->
period
*
haptic
->
magnitude
;
pwm_get_args
(
haptic
->
pwm_dev
,
&
pargs
);
period_mag_multi
=
(
u64
)
pargs
.
period
*
haptic
->
magnitude
;
haptic
->
pwm_duty
=
(
unsigned
int
)(
period_mag_multi
>>
MAX_MAGNITUDE_SHIFT
);
...
...
@@ -329,6 +334,12 @@ static int max77693_haptic_probe(struct platform_device *pdev)
return
PTR_ERR
(
haptic
->
pwm_dev
);
}
/*
* FIXME: pwm_apply_args() should be removed when switching to the
* atomic PWM API.
*/
pwm_apply_args
(
haptic
->
pwm_dev
);
haptic
->
motor_reg
=
devm_regulator_get
(
&
pdev
->
dev
,
"haptic"
);
if
(
IS_ERR
(
haptic
->
motor_reg
))
{
dev_err
(
&
pdev
->
dev
,
"failed to get regulator
\n
"
);
...
...
drivers/input/misc/max8997_haptic.c
View file @
18c58878
...
...
@@ -304,6 +304,12 @@ static int max8997_haptic_probe(struct platform_device *pdev)
error
);
goto
err_free_mem
;
}
/*
* FIXME: pwm_apply_args() should be removed when switching to
* the atomic PWM API.
*/
pwm_apply_args
(
chip
->
pwm
);
break
;
default:
...
...
drivers/input/misc/pwm-beeper.c
View file @
18c58878
...
...
@@ -87,6 +87,12 @@ static int pwm_beeper_probe(struct platform_device *pdev)
goto
err_free
;
}
/*
* FIXME: pwm_apply_args() should be removed when switching to
* the atomic PWM API.
*/
pwm_apply_args
(
beeper
->
pwm
);
beeper
->
input
=
input_allocate_device
();
if
(
!
beeper
->
input
)
{
dev_err
(
&
pdev
->
dev
,
"Failed to allocate input device
\n
"
);
...
...
drivers/leds/leds-pwm.c
View file @
18c58878
...
...
@@ -91,6 +91,7 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
struct
led_pwm
*
led
,
struct
device_node
*
child
)
{
struct
led_pwm_data
*
led_data
=
&
priv
->
leds
[
priv
->
num_leds
];
struct
pwm_args
pargs
;
int
ret
;
led_data
->
active_low
=
led
->
active_low
;
...
...
@@ -117,7 +118,15 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
else
led_data
->
cdev
.
brightness_set_blocking
=
led_pwm_set_blocking
;
led_data
->
period
=
pwm_get_period
(
led_data
->
pwm
);
/*
* FIXME: pwm_apply_args() should be removed when switching to the
* atomic PWM API.
*/
pwm_apply_args
(
led_data
->
pwm
);
pwm_get_args
(
led_data
->
pwm
,
&
pargs
);
led_data
->
period
=
pargs
.
period
;
if
(
!
led_data
->
period
&&
(
led
->
pwm_period_ns
>
0
))
led_data
->
period
=
led
->
pwm_period_ns
;
...
...
drivers/pwm/core.c
View file @
18c58878
...
...
@@ -227,6 +227,19 @@ void *pwm_get_chip_data(struct pwm_device *pwm)
}
EXPORT_SYMBOL_GPL
(
pwm_get_chip_data
);
static
bool
pwm_ops_check
(
const
struct
pwm_ops
*
ops
)
{
/* driver supports legacy, non-atomic operation */
if
(
ops
->
config
&&
ops
->
enable
&&
ops
->
disable
)
return
true
;
/* driver supports atomic operation */
if
(
ops
->
apply
)
return
true
;
return
false
;
}
/**
* pwmchip_add_with_polarity() - register a new PWM chip
* @chip: the PWM chip to add
...
...
@@ -245,8 +258,10 @@ int pwmchip_add_with_polarity(struct pwm_chip *chip,
unsigned
int
i
;
int
ret
;
if
(
!
chip
||
!
chip
->
dev
||
!
chip
->
ops
||
!
chip
->
ops
->
config
||
!
chip
->
ops
->
enable
||
!
chip
->
ops
->
disable
||
!
chip
->
npwm
)
if
(
!
chip
||
!
chip
->
dev
||
!
chip
->
ops
||
!
chip
->
npwm
)
return
-
EINVAL
;
if
(
!
pwm_ops_check
(
chip
->
ops
))
return
-
EINVAL
;
mutex_lock
(
&
pwm_lock
);
...
...
@@ -269,8 +284,10 @@ int pwmchip_add_with_polarity(struct pwm_chip *chip,
pwm
->
chip
=
chip
;
pwm
->
pwm
=
chip
->
base
+
i
;
pwm
->
hwpwm
=
i
;
pwm
->
polarity
=
polarity
;
mutex_init
(
&
pwm
->
lock
);
pwm
->
state
.
polarity
=
polarity
;
if
(
chip
->
ops
->
get_state
)
chip
->
ops
->
get_state
(
chip
,
pwm
,
&
pwm
->
state
);
radix_tree_insert
(
&
pwm_tree
,
pwm
->
pwm
,
pwm
);
}
...
...
@@ -430,107 +447,138 @@ void pwm_free(struct pwm_device *pwm)
EXPORT_SYMBOL_GPL
(
pwm_free
);
/**
* pwm_
config() - change a PWM device configuration
* pwm_
apply_state() - atomically apply a new state to a PWM device
* @pwm: PWM device
* @duty_ns: "on" time (in nanoseconds)
* @period_ns: duration (in nanoseconds) of one cycle
*
* Returns: 0 on success or a negative error code on failure.
* @state: new state to apply. This can be adjusted by the PWM driver
* if the requested config is not achievable, for example,
* ->duty_cycle and ->period might be approximated.
*/
int
pwm_
config
(
struct
pwm_device
*
pwm
,
int
duty_ns
,
int
period_ns
)
int
pwm_
apply_state
(
struct
pwm_device
*
pwm
,
struct
pwm_state
*
state
)
{
int
err
;
if
(
!
pwm
||
duty_ns
<
0
||
period_ns
<=
0
||
duty_ns
>
period_ns
)
if
(
!
pwm
)
return
-
EINVAL
;
err
=
pwm
->
chip
->
ops
->
config
(
pwm
->
chip
,
pwm
,
duty_ns
,
period_ns
);
if
(
err
)
return
err
;
pwm
->
duty_cycle
=
duty_ns
;
pwm
->
period
=
period_ns
;
if
(
!
memcmp
(
state
,
&
pwm
->
state
,
sizeof
(
*
state
)))
return
0
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
pwm_config
);
if
(
pwm
->
chip
->
ops
->
apply
)
{
err
=
pwm
->
chip
->
ops
->
apply
(
pwm
->
chip
,
pwm
,
state
);
if
(
err
)
return
err
;
/**
* pwm_set_polarity() - configure the polarity of a PWM signal
* @pwm: PWM device
* @polarity: new polarity of the PWM signal
*
* Note that the polarity cannot be configured while the PWM device is
* enabled.
*
* Returns: 0 on success or a negative error code on failure.
*/
int
pwm_set_polarity
(
struct
pwm_device
*
pwm
,
enum
pwm_polarity
polarity
)
{
int
err
;
pwm
->
state
=
*
state
;
}
else
{
/*
* FIXME: restore the initial state in case of error.
*/
if
(
state
->
polarity
!=
pwm
->
state
.
polarity
)
{
if
(
!
pwm
->
chip
->
ops
->
set_polarity
)
return
-
ENOTSUPP
;
/*
* Changing the polarity of a running PWM is
* only allowed when the PWM driver implements
* ->apply().
*/
if
(
pwm
->
state
.
enabled
)
{
pwm
->
chip
->
ops
->
disable
(
pwm
->
chip
,
pwm
);
pwm
->
state
.
enabled
=
false
;
}
err
=
pwm
->
chip
->
ops
->
set_polarity
(
pwm
->
chip
,
pwm
,
state
->
polarity
);
if
(
err
)
return
err
;
pwm
->
state
.
polarity
=
state
->
polarity
;
}
if
(
!
pwm
||
!
pwm
->
chip
->
ops
)
return
-
EINVAL
;
if
(
state
->
period
!=
pwm
->
state
.
period
||
state
->
duty_cycle
!=
pwm
->
state
.
duty_cycle
)
{
err
=
pwm
->
chip
->
ops
->
config
(
pwm
->
chip
,
pwm
,
state
->
duty_cycle
,
state
->
period
);
if
(
err
)
return
err
;
if
(
!
pwm
->
chip
->
ops
->
set_polarity
)
return
-
ENOSYS
;
pwm
->
state
.
duty_cycle
=
state
->
duty_cycle
;
pwm
->
state
.
period
=
state
->
period
;
}
mutex_lock
(
&
pwm
->
lock
);
if
(
state
->
enabled
!=
pwm
->
state
.
enabled
)
{
if
(
state
->
enabled
)
{
err
=
pwm
->
chip
->
ops
->
enable
(
pwm
->
chip
,
pwm
);
if
(
err
)
return
err
;
}
else
{
pwm
->
chip
->
ops
->
disable
(
pwm
->
chip
,
pwm
);
}
if
(
pwm_is_enabled
(
pwm
))
{
err
=
-
EBUSY
;
goto
unlock
;
pwm
->
state
.
enabled
=
state
->
enabled
;
}
}
err
=
pwm
->
chip
->
ops
->
set_polarity
(
pwm
->
chip
,
pwm
,
polarity
);
if
(
err
)
goto
unlock
;
pwm
->
polarity
=
polarity
;
unlock:
mutex_unlock
(
&
pwm
->
lock
);
return
err
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
pwm_
set_polarity
);
EXPORT_SYMBOL_GPL
(
pwm_
apply_state
);
/**
* pwm_
enable() - start a PWM output toggling
* pwm_
adjust_config() - adjust the current PWM config to the PWM arguments
* @pwm: PWM device
*
* Returns: 0 on success or a negative error code on failure.
* This function will adjust the PWM config to the PWM arguments provided
* by the DT or PWM lookup table. This is particularly useful to adapt
* the bootloader config to the Linux one.
*/
int
pwm_
enable
(
struct
pwm_device
*
pwm
)
int
pwm_
adjust_config
(
struct
pwm_device
*
pwm
)
{
int
err
=
0
;
struct
pwm_state
state
;
struct
pwm_args
pargs
;
if
(
!
pwm
)
return
-
EINVAL
;
pwm_get_args
(
pwm
,
&
pargs
);
pwm_get_state
(
pwm
,
&
state
)
;
mutex_lock
(
&
pwm
->
lock
);
/*
* If the current period is zero it means that either the PWM driver
* does not support initial state retrieval or the PWM has not yet
* been configured.
*
* In either case, we setup the new period and polarity, and assign a
* duty cycle of 0.
*/
if
(
!
state
.
period
)
{
state
.
duty_cycle
=
0
;
state
.
period
=
pargs
.
period
;
state
.
polarity
=
pargs
.
polarity
;
if
(
!
test_and_set_bit
(
PWMF_ENABLED
,
&
pwm
->
flags
))
{
err
=
pwm
->
chip
->
ops
->
enable
(
pwm
->
chip
,
pwm
);
if
(
err
)
clear_bit
(
PWMF_ENABLED
,
&
pwm
->
flags
);
return
pwm_apply_state
(
pwm
,
&
state
);
}
mutex_unlock
(
&
pwm
->
lock
);
/*
* Adjust the PWM duty cycle/period based on the period value provided
* in PWM args.
*/
if
(
pargs
.
period
!=
state
.
period
)
{
u64
dutycycle
=
(
u64
)
state
.
duty_cycle
*
pargs
.
period
;
return
err
;
}
EXPORT_SYMBOL_GPL
(
pwm_enable
);
do_div
(
dutycycle
,
state
.
period
);
state
.
duty_cycle
=
dutycycle
;
state
.
period
=
pargs
.
period
;
}
/**
* pwm_disable() - stop a PWM output toggling
* @pwm: PWM device
*/
void
pwm_disable
(
struct
pwm_device
*
pwm
)
{
if
(
pwm
&&
test_and_clear_bit
(
PWMF_ENABLED
,
&
pwm
->
flags
))
pwm
->
chip
->
ops
->
disable
(
pwm
->
chip
,
pwm
);
/*
* If the polarity changed, we should also change the duty cycle.
*/
if
(
pargs
.
polarity
!=
state
.
polarity
)
{
state
.
polarity
=
pargs
.
polarity
;
state
.
duty_cycle
=
state
.
period
-
state
.
duty_cycle
;
}
return
pwm_apply_state
(
pwm
,
&
state
);
}
EXPORT_SYMBOL_GPL
(
pwm_
disable
);
EXPORT_SYMBOL_GPL
(
pwm_
adjust_config
);
static
struct
pwm_chip
*
of_node_to_pwmchip
(
struct
device_node
*
np
)
{
...
...
@@ -621,13 +669,6 @@ struct pwm_device *of_pwm_get(struct device_node *np, const char *con_id)
pwm
->
label
=
con_id
;
/*
* FIXME: This should be removed once all PWM users properly make use
* of struct pwm_args to initialize the PWM device. As long as this is
* here, the PWM state and hardware state can get out of sync.
*/
pwm_apply_args
(
pwm
);
put:
of_node_put
(
args
.
np
);
...
...
@@ -762,13 +803,6 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id)
pwm
->
args
.
period
=
chosen
->
period
;
pwm
->
args
.
polarity
=
chosen
->
polarity
;
/*
* FIXME: This should be removed once all PWM users properly make use
* of struct pwm_args to initialize the PWM device. As long as this is
* here, the PWM state and hardware state can get out of sync.
*/
pwm_apply_args
(
pwm
);
out:
mutex_unlock
(
&
pwm_lookup_lock
);
return
pwm
;
...
...
@@ -915,15 +949,23 @@ static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s)
for
(
i
=
0
;
i
<
chip
->
npwm
;
i
++
)
{
struct
pwm_device
*
pwm
=
&
chip
->
pwms
[
i
];
struct
pwm_state
state
;
pwm_get_state
(
pwm
,
&
state
);
seq_printf
(
s
,
" pwm-%-3d (%-20.20s):"
,
i
,
pwm
->
label
);
if
(
test_bit
(
PWMF_REQUESTED
,
&
pwm
->
flags
))
seq_puts
(
s
,
" requested"
);
if
(
pwm_is_enabled
(
pwm
)
)
if
(
state
.
enabled
)
seq_puts
(
s
,
" enabled"
);
seq_printf
(
s
,
" period: %u ns"
,
state
.
period
);
seq_printf
(
s
,
" duty: %u ns"
,
state
.
duty_cycle
);
seq_printf
(
s
,
" polarity: %s"
,
state
.
polarity
?
"inverse"
:
"normal"
);
seq_puts
(
s
,
"
\n
"
);
}
}
...
...
drivers/pwm/pwm-crc.c
View file @
18c58878
...
...
@@ -75,7 +75,7 @@ static int crc_pwm_config(struct pwm_chip *c, struct pwm_device *pwm,
return
-
EINVAL
;
}
if
(
pwm
->
period
!=
period_ns
)
{
if
(
pwm
_get_period
(
pwm
)
!=
period_ns
)
{
int
clk_div
;
/* changing the clk divisor, need to disable fisrt */
...
...
drivers/pwm/pwm-lpc18xx-sct.c
View file @
18c58878
...
...
@@ -249,7 +249,7 @@ static int lpc18xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
LPC18XX_PWM_EVSTATEMSK
(
lpc18xx_data
->
duty_event
),
LPC18XX_PWM_EVSTATEMSK_ALL
);
if
(
pwm
->
polarity
==
PWM_POLARITY_NORMAL
)
{
if
(
pwm
_get_polarity
(
pwm
)
==
PWM_POLARITY_NORMAL
)
{
set_event
=
lpc18xx_pwm
->
period_event
;
clear_event
=
lpc18xx_data
->
duty_event
;
res_action
=
LPC18XX_PWM_RES_SET
;
...
...
drivers/pwm/pwm-omap-dmtimer.c
View file @
18c58878
...
...
@@ -192,7 +192,7 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
load_value
,
load_value
,
match_value
,
match_value
);
omap
->
pdata
->
set_pwm
(
omap
->
dm_timer
,
pwm
->
polarity
==
PWM_POLARITY_INVERSED
,
pwm
_get_polarity
(
pwm
)
==
PWM_POLARITY_INVERSED
,
true
,
PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE
);
...
...
drivers/pwm/pwm-rcar.c
View file @
18c58878
...
...
@@ -157,7 +157,7 @@ static int rcar_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
return
div
;
/* Let the core driver set pwm->period if disabled and duty_ns == 0 */
if
(
!
test_bit
(
PWMF_ENABLED
,
&
pwm
->
flags
)
&&
!
duty_ns
)
if
(
!
pwm_is_enabled
(
pwm
)
&&
!
duty_ns
)
return
0
;
rcar_pwm_update
(
rp
,
RCAR_PWMCR_SYNC
,
RCAR_PWMCR_SYNC
,
RCAR_PWMCR
);
...
...
drivers/pwm/pwm-sun4i.c
View file @
18c58878
...
...
@@ -354,7 +354,8 @@ static int sun4i_pwm_probe(struct platform_device *pdev)
val
=
sun4i_pwm_readl
(
pwm
,
PWM_CTRL_REG
);
for
(
i
=
0
;
i
<
pwm
->
chip
.
npwm
;
i
++
)
if
(
!
(
val
&
BIT_CH
(
PWM_ACT_STATE
,
i
)))
pwm
->
chip
.
pwms
[
i
].
polarity
=
PWM_POLARITY_INVERSED
;
pwm_set_polarity
(
&
pwm
->
chip
.
pwms
[
i
],
PWM_POLARITY_INVERSED
);
clk_disable_unprepare
(
pwm
->
clk
);
return
0
;
...
...
drivers/pwm/sysfs.c
View file @
18c58878
...
...
@@ -26,6 +26,7 @@
struct
pwm_export
{
struct
device
child
;
struct
pwm_device
*
pwm
;
struct
mutex
lock
;
};
static
struct
pwm_export
*
child_to_pwm_export
(
struct
device
*
child
)
...
...
@@ -45,15 +46,20 @@ static ssize_t period_show(struct device *child,
char
*
buf
)
{
const
struct
pwm_device
*
pwm
=
child_to_pwm_device
(
child
);
struct
pwm_state
state
;
return
sprintf
(
buf
,
"%u
\n
"
,
pwm_get_period
(
pwm
));
pwm_get_state
(
pwm
,
&
state
);
return
sprintf
(
buf
,
"%u
\n
"
,
state
.
period
);
}
static
ssize_t
period_store
(
struct
device
*
child
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
size
)
{
struct
pwm_device
*
pwm
=
child_to_pwm_device
(
child
);
struct
pwm_export
*
export
=
child_to_pwm_export
(
child
);
struct
pwm_device
*
pwm
=
export
->
pwm
;
struct
pwm_state
state
;
unsigned
int
val
;
int
ret
;
...
...
@@ -61,7 +67,11 @@ static ssize_t period_store(struct device *child,
if
(
ret
)
return
ret
;
ret
=
pwm_config
(
pwm
,
pwm_get_duty_cycle
(
pwm
),
val
);
mutex_lock
(
&
export
->
lock
);
pwm_get_state
(
pwm
,
&
state
);
state
.
period
=
val
;
ret
=
pwm_apply_state
(
pwm
,
&
state
);
mutex_unlock
(
&
export
->
lock
);
return
ret
?
:
size
;
}
...
...
@@ -71,15 +81,20 @@ static ssize_t duty_cycle_show(struct device *child,
char
*
buf
)
{
const
struct
pwm_device
*
pwm
=
child_to_pwm_device
(
child
);
struct
pwm_state
state
;
pwm_get_state
(
pwm
,
&
state
);
return
sprintf
(
buf
,
"%u
\n
"
,
pwm_get_duty_cycle
(
pwm
)
);
return
sprintf
(
buf
,
"%u
\n
"
,
state
.
duty_cycle
);
}
static
ssize_t
duty_cycle_store
(
struct
device
*
child
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
size
)
{
struct
pwm_device
*
pwm
=
child_to_pwm_device
(
child
);
struct
pwm_export
*
export
=
child_to_pwm_export
(
child
);
struct
pwm_device
*
pwm
=
export
->
pwm
;
struct
pwm_state
state
;
unsigned
int
val
;
int
ret
;
...
...
@@ -87,7 +102,11 @@ static ssize_t duty_cycle_store(struct device *child,
if
(
ret
)
return
ret
;
ret
=
pwm_config
(
pwm
,
val
,
pwm_get_period
(
pwm
));
mutex_lock
(
&
export
->
lock
);
pwm_get_state
(
pwm
,
&
state
);
state
.
duty_cycle
=
val
;
ret
=
pwm_apply_state
(
pwm
,
&
state
);
mutex_unlock
(
&
export
->
lock
);
return
ret
?
:
size
;
}
...
...
@@ -97,33 +116,46 @@ static ssize_t enable_show(struct device *child,
char
*
buf
)
{
const
struct
pwm_device
*
pwm
=
child_to_pwm_device
(
child
);
struct
pwm_state
state
;
pwm_get_state
(
pwm
,
&
state
);
return
sprintf
(
buf
,
"%d
\n
"
,
pwm_is_enabled
(
pwm
)
);
return
sprintf
(
buf
,
"%d
\n
"
,
state
.
enabled
);
}
static
ssize_t
enable_store
(
struct
device
*
child
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
size
)
{
struct
pwm_device
*
pwm
=
child_to_pwm_device
(
child
);
struct
pwm_export
*
export
=
child_to_pwm_export
(
child
);
struct
pwm_device
*
pwm
=
export
->
pwm
;
struct
pwm_state
state
;
int
val
,
ret
;
ret
=
kstrtoint
(
buf
,
0
,
&
val
);
if
(
ret
)
return
ret
;
mutex_lock
(
&
export
->
lock
);
pwm_get_state
(
pwm
,
&
state
);
switch
(
val
)
{
case
0
:
pwm_disable
(
pwm
)
;
state
.
enabled
=
false
;
break
;
case
1
:
ret
=
pwm_enable
(
pwm
)
;
state
.
enabled
=
true
;
break
;
default:
ret
=
-
EINVAL
;
brea
k
;
goto
unloc
k
;
}
pwm_apply_state
(
pwm
,
&
state
);
unlock:
mutex_unlock
(
&
export
->
lock
);
return
ret
?
:
size
;
}
...
...
@@ -133,8 +165,11 @@ static ssize_t polarity_show(struct device *child,
{
const
struct
pwm_device
*
pwm
=
child_to_pwm_device
(
child
);
const
char
*
polarity
=
"unknown"
;
struct
pwm_state
state
;
pwm_get_state
(
pwm
,
&
state
);
switch
(
pwm_get_polarity
(
pwm
)
)
{
switch
(
state
.
polarity
)
{
case
PWM_POLARITY_NORMAL
:
polarity
=
"normal"
;
break
;
...
...
@@ -151,8 +186,10 @@ static ssize_t polarity_store(struct device *child,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
size
)
{
struct
pwm_device
*
pwm
=
child_to_pwm_device
(
child
);
struct
pwm_export
*
export
=
child_to_pwm_export
(
child
);
struct
pwm_device
*
pwm
=
export
->
pwm
;
enum
pwm_polarity
polarity
;
struct
pwm_state
state
;
int
ret
;
if
(
sysfs_streq
(
buf
,
"normal"
))
...
...
@@ -162,7 +199,11 @@ static ssize_t polarity_store(struct device *child,
else
return
-
EINVAL
;
ret
=
pwm_set_polarity
(
pwm
,
polarity
);
mutex_lock
(
&
export
->
lock
);
pwm_get_state
(
pwm
,
&
state
);
state
.
polarity
=
polarity
;
ret
=
pwm_apply_state
(
pwm
,
&
state
);
mutex_unlock
(
&
export
->
lock
);
return
ret
?
:
size
;
}
...
...
@@ -203,6 +244,7 @@ static int pwm_export_child(struct device *parent, struct pwm_device *pwm)
}
export
->
pwm
=
pwm
;
mutex_init
(
&
export
->
lock
);
export
->
child
.
release
=
pwm_export_release
;
export
->
child
.
parent
=
parent
;
...
...
drivers/video/backlight/lm3630a_bl.c
View file @
18c58878
...
...
@@ -162,7 +162,7 @@ static int lm3630a_intr_config(struct lm3630a_chip *pchip)
static
void
lm3630a_pwm_ctrl
(
struct
lm3630a_chip
*
pchip
,
int
br
,
int
br_max
)
{
unsigned
int
period
=
p
wm_get_period
(
pchip
->
pwmd
)
;
unsigned
int
period
=
p
chip
->
pdata
->
pwm_period
;
unsigned
int
duty
=
br
*
period
/
br_max
;
pwm_config
(
pchip
->
pwmd
,
duty
,
period
);
...
...
@@ -424,8 +424,13 @@ static int lm3630a_probe(struct i2c_client *client,
dev_err
(
&
client
->
dev
,
"fail : get pwm device
\n
"
);
return
PTR_ERR
(
pchip
->
pwmd
);
}
/*
* FIXME: pwm_apply_args() should be removed when switching to
* the atomic PWM API.
*/
pwm_apply_args
(
pchip
->
pwmd
);
}
pchip
->
pwmd
->
period
=
pdata
->
pwm_period
;
/* interrupt enable : irq 0 is not allowed */
pchip
->
irq
=
client
->
irq
;
...
...
drivers/video/backlight/lp855x_bl.c
View file @
18c58878
...
...
@@ -246,6 +246,12 @@ static void lp855x_pwm_ctrl(struct lp855x *lp, int br, int max_br)
return
;
lp
->
pwm
=
pwm
;
/*
* FIXME: pwm_apply_args() should be removed when switching to
* the atomic PWM API.
*/
pwm_apply_args
(
pwm
);
}
pwm_config
(
lp
->
pwm
,
duty
,
period
);
...
...
drivers/video/backlight/lp8788_bl.c
View file @
18c58878
...
...
@@ -145,6 +145,12 @@ static void lp8788_pwm_ctrl(struct lp8788_bl *bl, int br, int max_br)
}
bl
->
pwm
=
pwm
;
/*
* FIXME: pwm_apply_args() should be removed when switching to
* the atomic PWM API.
*/
pwm_apply_args
(
pwm
);
}
pwm_config
(
bl
->
pwm
,
duty
,
period
);
...
...
drivers/video/backlight/pwm_bl.c
View file @
18c58878
...
...
@@ -201,6 +201,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
struct
device_node
*
node
=
pdev
->
dev
.
of_node
;
struct
pwm_bl_data
*
pb
;
int
initial_blank
=
FB_BLANK_UNBLANK
;
struct
pwm_args
pargs
;
int
ret
;
if
(
!
data
)
{
...
...
@@ -306,17 +307,22 @@ static int pwm_backlight_probe(struct platform_device *pdev)
dev_dbg
(
&
pdev
->
dev
,
"got pwm for backlight
\n
"
);
/*
* FIXME: pwm_apply_args() should be removed when switching to
* the atomic PWM API.
*/
pwm_apply_args
(
pb
->
pwm
);
/*
* The DT case will set the pwm_period_ns field to 0 and store the
* period, parsed from the DT, in the PWM device. For the non-DT case,
* set the period from platform data if it has not already been set
* via the PWM lookup table.
*/
pb
->
period
=
pwm_get_period
(
pb
->
pwm
);
if
(
!
pb
->
period
&&
(
data
->
pwm_period_ns
>
0
))
{
pwm_get_args
(
pb
->
pwm
,
&
pargs
);
pb
->
period
=
pargs
.
period
;
if
(
!
pb
->
period
&&
(
data
->
pwm_period_ns
>
0
))
pb
->
period
=
data
->
pwm_period_ns
;
pwm_set_period
(
pb
->
pwm
,
data
->
pwm_period_ns
);
}
pb
->
lth_brightness
=
data
->
lth_brightness
*
(
pb
->
period
/
pb
->
scale
);
...
...
drivers/video/fbdev/ssd1307fb.c
View file @
18c58878
...
...
@@ -286,6 +286,7 @@ static int ssd1307fb_init(struct ssd1307fb_par *par)
{
int
ret
;
u32
precharge
,
dclk
,
com_invdir
,
compins
;
struct
pwm_args
pargs
;
if
(
par
->
device_info
->
need_pwm
)
{
par
->
pwm
=
pwm_get
(
&
par
->
client
->
dev
,
NULL
);
...
...
@@ -294,7 +295,15 @@ static int ssd1307fb_init(struct ssd1307fb_par *par)
return
PTR_ERR
(
par
->
pwm
);
}
par
->
pwm_period
=
pwm_get_period
(
par
->
pwm
);
/*
* FIXME: pwm_apply_args() should be removed when switching to
* the atomic PWM API.
*/
pwm_apply_args
(
par
->
pwm
);
pwm_get_args
(
par
->
pwm
,
&
pargs
);
par
->
pwm_period
=
pargs
.
period
;
/* Enable the PWM */
pwm_config
(
par
->
pwm
,
par
->
pwm_period
/
2
,
par
->
pwm_period
);
pwm_enable
(
par
->
pwm
);
...
...
include/linux/pwm.h
View file @
18c58878
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment