aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pwm/pwm-lpss.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pwm/pwm-lpss.c')
-rw-r--r--drivers/pwm/pwm-lpss.c132
1 files changed, 67 insertions, 65 deletions
diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
index 72c0bce5a75c..689d2c1cbead 100644
--- a/drivers/pwm/pwm-lpss.c
+++ b/drivers/pwm/pwm-lpss.c
@@ -15,6 +15,7 @@
15 15
16#include <linux/delay.h> 16#include <linux/delay.h>
17#include <linux/io.h> 17#include <linux/io.h>
18#include <linux/iopoll.h>
18#include <linux/kernel.h> 19#include <linux/kernel.h>
19#include <linux/module.h> 20#include <linux/module.h>
20#include <linux/pm_runtime.h> 21#include <linux/pm_runtime.h>
@@ -37,30 +38,6 @@ struct pwm_lpss_chip {
37 const struct pwm_lpss_boardinfo *info; 38 const struct pwm_lpss_boardinfo *info;
38}; 39};
39 40
40/* BayTrail */
41const struct pwm_lpss_boardinfo pwm_lpss_byt_info = {
42 .clk_rate = 25000000,
43 .npwm = 1,
44 .base_unit_bits = 16,
45};
46EXPORT_SYMBOL_GPL(pwm_lpss_byt_info);
47
48/* Braswell */
49const struct pwm_lpss_boardinfo pwm_lpss_bsw_info = {
50 .clk_rate = 19200000,
51 .npwm = 1,
52 .base_unit_bits = 16,
53};
54EXPORT_SYMBOL_GPL(pwm_lpss_bsw_info);
55
56/* Broxton */
57const struct pwm_lpss_boardinfo pwm_lpss_bxt_info = {
58 .clk_rate = 19200000,
59 .npwm = 4,
60 .base_unit_bits = 22,
61};
62EXPORT_SYMBOL_GPL(pwm_lpss_bxt_info);
63
64static inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip) 41static inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip)
65{ 42{
66 return container_of(chip, struct pwm_lpss_chip, chip); 43 return container_of(chip, struct pwm_lpss_chip, chip);
@@ -80,17 +57,42 @@ static inline void pwm_lpss_write(const struct pwm_device *pwm, u32 value)
80 writel(value, lpwm->regs + pwm->hwpwm * PWM_SIZE + PWM); 57 writel(value, lpwm->regs + pwm->hwpwm * PWM_SIZE + PWM);
81} 58}
82 59
83static void pwm_lpss_update(struct pwm_device *pwm) 60static int pwm_lpss_update(struct pwm_device *pwm)
84{ 61{
62 struct pwm_lpss_chip *lpwm = to_lpwm(pwm->chip);
63 const void __iomem *addr = lpwm->regs + pwm->hwpwm * PWM_SIZE + PWM;
64 const unsigned int ms = 500 * USEC_PER_MSEC;
65 u32 val;
66 int err;
67
85 pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_SW_UPDATE); 68 pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_SW_UPDATE);
86 /* Give it some time to propagate */ 69
87 usleep_range(10, 50); 70 /*
71 * PWM Configuration register has SW_UPDATE bit that is set when a new
72 * configuration is written to the register. The bit is automatically
73 * cleared at the start of the next output cycle by the IP block.
74 *
75 * If one writes a new configuration to the register while it still has
76 * the bit enabled, PWM may freeze. That is, while one can still write
77 * to the register, it won't have an effect. Thus, we try to sleep long
78 * enough that the bit gets cleared and make sure the bit is not
79 * enabled while we update the configuration.
80 */
81 err = readl_poll_timeout(addr, val, !(val & PWM_SW_UPDATE), 40, ms);
82 if (err)
83 dev_err(pwm->chip->dev, "PWM_SW_UPDATE was not cleared\n");
84
85 return err;
88} 86}
89 87
90static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm, 88static inline int pwm_lpss_is_updating(struct pwm_device *pwm)
91 int duty_ns, int period_ns) 89{
90 return (pwm_lpss_read(pwm) & PWM_SW_UPDATE) ? -EBUSY : 0;
91}
92
93static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, struct pwm_device *pwm,
94 int duty_ns, int period_ns)
92{ 95{
93 struct pwm_lpss_chip *lpwm = to_lpwm(chip);
94 unsigned long long on_time_div; 96 unsigned long long on_time_div;
95 unsigned long c = lpwm->info->clk_rate, base_unit_range; 97 unsigned long c = lpwm->info->clk_rate, base_unit_range;
96 unsigned long long base_unit, freq = NSEC_PER_SEC; 98 unsigned long long base_unit, freq = NSEC_PER_SEC;
@@ -102,62 +104,62 @@ static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm,
102 * The equation is: 104 * The equation is:
103 * base_unit = round(base_unit_range * freq / c) 105 * base_unit = round(base_unit_range * freq / c)
104 */ 106 */
105 base_unit_range = BIT(lpwm->info->base_unit_bits); 107 base_unit_range = BIT(lpwm->info->base_unit_bits) - 1;
106 freq *= base_unit_range; 108 freq *= base_unit_range;
107 109
108 base_unit = DIV_ROUND_CLOSEST_ULL(freq, c); 110 base_unit = DIV_ROUND_CLOSEST_ULL(freq, c);
109 111
110 if (duty_ns <= 0)
111 duty_ns = 1;
112 on_time_div = 255ULL * duty_ns; 112 on_time_div = 255ULL * duty_ns;
113 do_div(on_time_div, period_ns); 113 do_div(on_time_div, period_ns);
114 on_time_div = 255ULL - on_time_div; 114 on_time_div = 255ULL - on_time_div;
115 115
116 pm_runtime_get_sync(chip->dev);
117
118 ctrl = pwm_lpss_read(pwm); 116 ctrl = pwm_lpss_read(pwm);
119 ctrl &= ~PWM_ON_TIME_DIV_MASK; 117 ctrl &= ~PWM_ON_TIME_DIV_MASK;
120 ctrl &= ~((base_unit_range - 1) << PWM_BASE_UNIT_SHIFT); 118 ctrl &= ~(base_unit_range << PWM_BASE_UNIT_SHIFT);
121 base_unit &= (base_unit_range - 1); 119 base_unit &= base_unit_range;
122 ctrl |= (u32) base_unit << PWM_BASE_UNIT_SHIFT; 120 ctrl |= (u32) base_unit << PWM_BASE_UNIT_SHIFT;
123 ctrl |= on_time_div; 121 ctrl |= on_time_div;
124 pwm_lpss_write(pwm, ctrl); 122 pwm_lpss_write(pwm, ctrl);
125
126 /*
127 * If the PWM is already enabled we need to notify the hardware
128 * about the change by setting PWM_SW_UPDATE.
129 */
130 if (pwm_is_enabled(pwm))
131 pwm_lpss_update(pwm);
132
133 pm_runtime_put(chip->dev);
134
135 return 0;
136} 123}
137 124
138static int pwm_lpss_enable(struct pwm_chip *chip, struct pwm_device *pwm) 125static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm,
126 struct pwm_state *state)
139{ 127{
140 pm_runtime_get_sync(chip->dev); 128 struct pwm_lpss_chip *lpwm = to_lpwm(chip);
129 int ret;
141 130
142 /* 131 if (state->enabled) {
143 * Hardware must first see PWM_SW_UPDATE before the PWM can be 132 if (!pwm_is_enabled(pwm)) {
144 * enabled. 133 pm_runtime_get_sync(chip->dev);
145 */ 134 ret = pwm_lpss_is_updating(pwm);
146 pwm_lpss_update(pwm); 135 if (ret) {
147 pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_ENABLE); 136 pm_runtime_put(chip->dev);
148 return 0; 137 return ret;
149} 138 }
139 pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period);
140 ret = pwm_lpss_update(pwm);
141 if (ret) {
142 pm_runtime_put(chip->dev);
143 return ret;
144 }
145 pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_ENABLE);
146 } else {
147 ret = pwm_lpss_is_updating(pwm);
148 if (ret)
149 return ret;
150 pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period);
151 return pwm_lpss_update(pwm);
152 }
153 } else if (pwm_is_enabled(pwm)) {
154 pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE);
155 pm_runtime_put(chip->dev);
156 }
150 157
151static void pwm_lpss_disable(struct pwm_chip *chip, struct pwm_device *pwm) 158 return 0;
152{
153 pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE);
154 pm_runtime_put(chip->dev);
155} 159}
156 160
157static const struct pwm_ops pwm_lpss_ops = { 161static const struct pwm_ops pwm_lpss_ops = {
158 .config = pwm_lpss_config, 162 .apply = pwm_lpss_apply,
159 .enable = pwm_lpss_enable,
160 .disable = pwm_lpss_disable,
161 .owner = THIS_MODULE, 163 .owner = THIS_MODULE,
162}; 164};
163 165