diff options
author | Boris Brezillon <boris.brezillon@free-electrons.com> | 2016-06-14 05:13:12 -0400 |
---|---|---|
committer | Thierry Reding <thierry.reding@gmail.com> | 2016-07-11 06:49:27 -0400 |
commit | 1ebb74cf3537135f157beddf1a4366070155edda (patch) | |
tree | 847bd545aabb5459217c9bddf9be2cbf25e49e20 /drivers/pwm/pwm-rockchip.c | |
parent | 12f9ce4a519845070d338253ab9528b5d7e2df34 (diff) |
pwm: rockchip: Add support for hardware readout
Implement the ->get_state() function to expose initial state.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Reviewed-by: Brian Norris <briannorris@chromium.org>
Tested-by: Brian Norris <briannorris@chromium.org>
Tested-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
Diffstat (limited to 'drivers/pwm/pwm-rockchip.c')
-rw-r--r-- | drivers/pwm/pwm-rockchip.c | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c index 68d72ce8fba5..c72b4192c7bf 100644 --- a/drivers/pwm/pwm-rockchip.c +++ b/drivers/pwm/pwm-rockchip.c | |||
@@ -51,6 +51,8 @@ struct rockchip_pwm_data { | |||
51 | 51 | ||
52 | void (*set_enable)(struct pwm_chip *chip, | 52 | void (*set_enable)(struct pwm_chip *chip, |
53 | struct pwm_device *pwm, bool enable); | 53 | struct pwm_device *pwm, bool enable); |
54 | void (*get_state)(struct pwm_chip *chip, struct pwm_device *pwm, | ||
55 | struct pwm_state *state); | ||
54 | }; | 56 | }; |
55 | 57 | ||
56 | static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *c) | 58 | static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *c) |
@@ -75,6 +77,19 @@ static void rockchip_pwm_set_enable_v1(struct pwm_chip *chip, | |||
75 | writel_relaxed(val, pc->base + pc->data->regs.ctrl); | 77 | writel_relaxed(val, pc->base + pc->data->regs.ctrl); |
76 | } | 78 | } |
77 | 79 | ||
80 | static void rockchip_pwm_get_state_v1(struct pwm_chip *chip, | ||
81 | struct pwm_device *pwm, | ||
82 | struct pwm_state *state) | ||
83 | { | ||
84 | struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip); | ||
85 | u32 enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN; | ||
86 | u32 val; | ||
87 | |||
88 | val = readl_relaxed(pc->base + pc->data->regs.ctrl); | ||
89 | if ((val & enable_conf) == enable_conf) | ||
90 | state->enabled = true; | ||
91 | } | ||
92 | |||
78 | static void rockchip_pwm_set_enable_v2(struct pwm_chip *chip, | 93 | static void rockchip_pwm_set_enable_v2(struct pwm_chip *chip, |
79 | struct pwm_device *pwm, bool enable) | 94 | struct pwm_device *pwm, bool enable) |
80 | { | 95 | { |
@@ -98,6 +113,53 @@ static void rockchip_pwm_set_enable_v2(struct pwm_chip *chip, | |||
98 | writel_relaxed(val, pc->base + pc->data->regs.ctrl); | 113 | writel_relaxed(val, pc->base + pc->data->regs.ctrl); |
99 | } | 114 | } |
100 | 115 | ||
116 | static void rockchip_pwm_get_state_v2(struct pwm_chip *chip, | ||
117 | struct pwm_device *pwm, | ||
118 | struct pwm_state *state) | ||
119 | { | ||
120 | struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip); | ||
121 | u32 enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE | | ||
122 | PWM_CONTINUOUS; | ||
123 | u32 val; | ||
124 | |||
125 | val = readl_relaxed(pc->base + pc->data->regs.ctrl); | ||
126 | if ((val & enable_conf) != enable_conf) | ||
127 | return; | ||
128 | |||
129 | state->enabled = true; | ||
130 | |||
131 | if (!(val & PWM_DUTY_POSITIVE)) | ||
132 | state->polarity = PWM_POLARITY_INVERSED; | ||
133 | } | ||
134 | |||
135 | static void rockchip_pwm_get_state(struct pwm_chip *chip, | ||
136 | struct pwm_device *pwm, | ||
137 | struct pwm_state *state) | ||
138 | { | ||
139 | struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip); | ||
140 | unsigned long clk_rate; | ||
141 | u64 tmp; | ||
142 | int ret; | ||
143 | |||
144 | ret = clk_enable(pc->clk); | ||
145 | if (ret) | ||
146 | return; | ||
147 | |||
148 | clk_rate = clk_get_rate(pc->clk); | ||
149 | |||
150 | tmp = readl_relaxed(pc->base + pc->data->regs.period); | ||
151 | tmp *= pc->data->prescaler * NSEC_PER_SEC; | ||
152 | state->period = DIV_ROUND_CLOSEST_ULL(tmp, clk_rate); | ||
153 | |||
154 | tmp = readl_relaxed(pc->base + pc->data->regs.duty); | ||
155 | tmp *= pc->data->prescaler * NSEC_PER_SEC; | ||
156 | state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, clk_rate); | ||
157 | |||
158 | pc->data->get_state(chip, pwm, state); | ||
159 | |||
160 | clk_disable(pc->clk); | ||
161 | } | ||
162 | |||
101 | static int rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | 163 | static int rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, |
102 | int duty_ns, int period_ns) | 164 | int duty_ns, int period_ns) |
103 | { | 165 | { |
@@ -170,6 +232,7 @@ static void rockchip_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | |||
170 | } | 232 | } |
171 | 233 | ||
172 | static const struct pwm_ops rockchip_pwm_ops_v1 = { | 234 | static const struct pwm_ops rockchip_pwm_ops_v1 = { |
235 | .get_state = rockchip_pwm_get_state, | ||
173 | .config = rockchip_pwm_config, | 236 | .config = rockchip_pwm_config, |
174 | .enable = rockchip_pwm_enable, | 237 | .enable = rockchip_pwm_enable, |
175 | .disable = rockchip_pwm_disable, | 238 | .disable = rockchip_pwm_disable, |
@@ -177,6 +240,7 @@ static const struct pwm_ops rockchip_pwm_ops_v1 = { | |||
177 | }; | 240 | }; |
178 | 241 | ||
179 | static const struct pwm_ops rockchip_pwm_ops_v2 = { | 242 | static const struct pwm_ops rockchip_pwm_ops_v2 = { |
243 | .get_state = rockchip_pwm_get_state, | ||
180 | .config = rockchip_pwm_config, | 244 | .config = rockchip_pwm_config, |
181 | .set_polarity = rockchip_pwm_set_polarity, | 245 | .set_polarity = rockchip_pwm_set_polarity, |
182 | .enable = rockchip_pwm_enable, | 246 | .enable = rockchip_pwm_enable, |
@@ -194,6 +258,7 @@ static const struct rockchip_pwm_data pwm_data_v1 = { | |||
194 | .prescaler = 2, | 258 | .prescaler = 2, |
195 | .ops = &rockchip_pwm_ops_v1, | 259 | .ops = &rockchip_pwm_ops_v1, |
196 | .set_enable = rockchip_pwm_set_enable_v1, | 260 | .set_enable = rockchip_pwm_set_enable_v1, |
261 | .get_state = rockchip_pwm_get_state_v1, | ||
197 | }; | 262 | }; |
198 | 263 | ||
199 | static const struct rockchip_pwm_data pwm_data_v2 = { | 264 | static const struct rockchip_pwm_data pwm_data_v2 = { |
@@ -206,6 +271,7 @@ static const struct rockchip_pwm_data pwm_data_v2 = { | |||
206 | .prescaler = 1, | 271 | .prescaler = 1, |
207 | .ops = &rockchip_pwm_ops_v2, | 272 | .ops = &rockchip_pwm_ops_v2, |
208 | .set_enable = rockchip_pwm_set_enable_v2, | 273 | .set_enable = rockchip_pwm_set_enable_v2, |
274 | .get_state = rockchip_pwm_get_state_v2, | ||
209 | }; | 275 | }; |
210 | 276 | ||
211 | static const struct rockchip_pwm_data pwm_data_vop = { | 277 | static const struct rockchip_pwm_data pwm_data_vop = { |
@@ -218,6 +284,7 @@ static const struct rockchip_pwm_data pwm_data_vop = { | |||
218 | .prescaler = 1, | 284 | .prescaler = 1, |
219 | .ops = &rockchip_pwm_ops_v2, | 285 | .ops = &rockchip_pwm_ops_v2, |
220 | .set_enable = rockchip_pwm_set_enable_v2, | 286 | .set_enable = rockchip_pwm_set_enable_v2, |
287 | .get_state = rockchip_pwm_get_state_v2, | ||
221 | }; | 288 | }; |
222 | 289 | ||
223 | static const struct of_device_id rockchip_pwm_dt_ids[] = { | 290 | static const struct of_device_id rockchip_pwm_dt_ids[] = { |