aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/pwm/pwm-rockchip.txt4
-rw-r--r--drivers/pwm/pwm-rockchip.c57
2 files changed, 50 insertions, 11 deletions
diff --git a/Documentation/devicetree/bindings/pwm/pwm-rockchip.txt b/Documentation/devicetree/bindings/pwm/pwm-rockchip.txt
index d47d15a6a298..b8be3d09ee26 100644
--- a/Documentation/devicetree/bindings/pwm/pwm-rockchip.txt
+++ b/Documentation/devicetree/bindings/pwm/pwm-rockchip.txt
@@ -7,8 +7,8 @@ Required properties:
7 "rockchip,vop-pwm": found integrated in VOP on RK3288 SoC 7 "rockchip,vop-pwm": found integrated in VOP on RK3288 SoC
8 - reg: physical base address and length of the controller's registers 8 - reg: physical base address and length of the controller's registers
9 - clocks: phandle and clock specifier of the PWM reference clock 9 - clocks: phandle and clock specifier of the PWM reference clock
10 - #pwm-cells: should be 2. See pwm.txt in this directory for a 10 - #pwm-cells: must be 2 (rk2928) or 3 (rk3288). See pwm.txt in this directory
11 description of the cell format. 11 for a description of the cell format.
12 12
13Example: 13Example:
14 14
diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c
index bdd8644c01cf..9442df244101 100644
--- a/drivers/pwm/pwm-rockchip.c
+++ b/drivers/pwm/pwm-rockchip.c
@@ -24,7 +24,9 @@
24#define PWM_ENABLE (1 << 0) 24#define PWM_ENABLE (1 << 0)
25#define PWM_CONTINUOUS (1 << 1) 25#define PWM_CONTINUOUS (1 << 1)
26#define PWM_DUTY_POSITIVE (1 << 3) 26#define PWM_DUTY_POSITIVE (1 << 3)
27#define PWM_DUTY_NEGATIVE (0 << 3)
27#define PWM_INACTIVE_NEGATIVE (0 << 4) 28#define PWM_INACTIVE_NEGATIVE (0 << 4)
29#define PWM_INACTIVE_POSITIVE (1 << 4)
28#define PWM_OUTPUT_LEFT (0 << 5) 30#define PWM_OUTPUT_LEFT (0 << 5)
29#define PWM_LP_DISABLE (0 << 8) 31#define PWM_LP_DISABLE (0 << 8)
30 32
@@ -45,8 +47,10 @@ struct rockchip_pwm_regs {
45struct rockchip_pwm_data { 47struct rockchip_pwm_data {
46 struct rockchip_pwm_regs regs; 48 struct rockchip_pwm_regs regs;
47 unsigned int prescaler; 49 unsigned int prescaler;
50 const struct pwm_ops *ops;
48 51
49 void (*set_enable)(struct pwm_chip *chip, bool enable); 52 void (*set_enable)(struct pwm_chip *chip,
53 struct pwm_device *pwm, bool enable);
50}; 54};
51 55
52static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *c) 56static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *c)
@@ -54,7 +58,8 @@ static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *c)
54 return container_of(c, struct rockchip_pwm_chip, chip); 58 return container_of(c, struct rockchip_pwm_chip, chip);
55} 59}
56 60
57static void rockchip_pwm_set_enable_v1(struct pwm_chip *chip, bool enable) 61static void rockchip_pwm_set_enable_v1(struct pwm_chip *chip,
62 struct pwm_device *pwm, bool enable)
58{ 63{
59 struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip); 64 struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
60 u32 enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN; 65 u32 enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN;
@@ -70,14 +75,19 @@ static void rockchip_pwm_set_enable_v1(struct pwm_chip *chip, bool enable)
70 writel_relaxed(val, pc->base + pc->data->regs.ctrl); 75 writel_relaxed(val, pc->base + pc->data->regs.ctrl);
71} 76}
72 77
73static void rockchip_pwm_set_enable_v2(struct pwm_chip *chip, bool enable) 78static void rockchip_pwm_set_enable_v2(struct pwm_chip *chip,
79 struct pwm_device *pwm, bool enable)
74{ 80{
75 struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip); 81 struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
76 u32 enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE | 82 u32 enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE |
77 PWM_CONTINUOUS | PWM_DUTY_POSITIVE | 83 PWM_CONTINUOUS;
78 PWM_INACTIVE_NEGATIVE;
79 u32 val; 84 u32 val;
80 85
86 if (pwm->polarity == PWM_POLARITY_INVERSED)
87 enable_conf |= PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSITIVE;
88 else
89 enable_conf |= PWM_DUTY_POSITIVE | PWM_INACTIVE_NEGATIVE;
90
81 val = readl_relaxed(pc->base + pc->data->regs.ctrl); 91 val = readl_relaxed(pc->base + pc->data->regs.ctrl);
82 92
83 if (enable) 93 if (enable)
@@ -124,6 +134,19 @@ static int rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
124 return 0; 134 return 0;
125} 135}
126 136
137static int rockchip_pwm_set_polarity(struct pwm_chip *chip,
138 struct pwm_device *pwm,
139 enum pwm_polarity polarity)
140{
141 /*
142 * No action needed here because pwm->polarity will be set by the core
143 * and the core will only change polarity when the PWM is not enabled.
144 * We'll handle things in set_enable().
145 */
146
147 return 0;
148}
149
127static int rockchip_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) 150static int rockchip_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
128{ 151{
129 struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip); 152 struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
@@ -133,7 +156,7 @@ static int rockchip_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
133 if (ret) 156 if (ret)
134 return ret; 157 return ret;
135 158
136 pc->data->set_enable(chip, true); 159 pc->data->set_enable(chip, pwm, true);
137 160
138 return 0; 161 return 0;
139} 162}
@@ -142,18 +165,26 @@ static void rockchip_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
142{ 165{
143 struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip); 166 struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
144 167
145 pc->data->set_enable(chip, false); 168 pc->data->set_enable(chip, pwm, false);
146 169
147 clk_disable(pc->clk); 170 clk_disable(pc->clk);
148} 171}
149 172
150static const struct pwm_ops rockchip_pwm_ops = { 173static const struct pwm_ops rockchip_pwm_ops_v1 = {
151 .config = rockchip_pwm_config, 174 .config = rockchip_pwm_config,
152 .enable = rockchip_pwm_enable, 175 .enable = rockchip_pwm_enable,
153 .disable = rockchip_pwm_disable, 176 .disable = rockchip_pwm_disable,
154 .owner = THIS_MODULE, 177 .owner = THIS_MODULE,
155}; 178};
156 179
180static const struct pwm_ops rockchip_pwm_ops_v2 = {
181 .config = rockchip_pwm_config,
182 .set_polarity = rockchip_pwm_set_polarity,
183 .enable = rockchip_pwm_enable,
184 .disable = rockchip_pwm_disable,
185 .owner = THIS_MODULE,
186};
187
157static const struct rockchip_pwm_data pwm_data_v1 = { 188static const struct rockchip_pwm_data pwm_data_v1 = {
158 .regs = { 189 .regs = {
159 .duty = 0x04, 190 .duty = 0x04,
@@ -162,6 +193,7 @@ static const struct rockchip_pwm_data pwm_data_v1 = {
162 .ctrl = 0x0c, 193 .ctrl = 0x0c,
163 }, 194 },
164 .prescaler = 2, 195 .prescaler = 2,
196 .ops = &rockchip_pwm_ops_v1,
165 .set_enable = rockchip_pwm_set_enable_v1, 197 .set_enable = rockchip_pwm_set_enable_v1,
166}; 198};
167 199
@@ -173,6 +205,7 @@ static const struct rockchip_pwm_data pwm_data_v2 = {
173 .ctrl = 0x0c, 205 .ctrl = 0x0c,
174 }, 206 },
175 .prescaler = 1, 207 .prescaler = 1,
208 .ops = &rockchip_pwm_ops_v2,
176 .set_enable = rockchip_pwm_set_enable_v2, 209 .set_enable = rockchip_pwm_set_enable_v2,
177}; 210};
178 211
@@ -184,6 +217,7 @@ static const struct rockchip_pwm_data pwm_data_vop = {
184 .ctrl = 0x00, 217 .ctrl = 0x00,
185 }, 218 },
186 .prescaler = 1, 219 .prescaler = 1,
220 .ops = &rockchip_pwm_ops_v2,
187 .set_enable = rockchip_pwm_set_enable_v2, 221 .set_enable = rockchip_pwm_set_enable_v2,
188}; 222};
189 223
@@ -227,10 +261,15 @@ static int rockchip_pwm_probe(struct platform_device *pdev)
227 261
228 pc->data = id->data; 262 pc->data = id->data;
229 pc->chip.dev = &pdev->dev; 263 pc->chip.dev = &pdev->dev;
230 pc->chip.ops = &rockchip_pwm_ops; 264 pc->chip.ops = pc->data->ops;
231 pc->chip.base = -1; 265 pc->chip.base = -1;
232 pc->chip.npwm = 1; 266 pc->chip.npwm = 1;
233 267
268 if (pc->data->ops->set_polarity) {
269 pc->chip.of_xlate = of_pwm_xlate_with_flags;
270 pc->chip.of_pwm_n_cells = 3;
271 }
272
234 ret = pwmchip_add(&pc->chip); 273 ret = pwmchip_add(&pc->chip);
235 if (ret < 0) { 274 if (ret < 0) {
236 clk_unprepare(pc->clk); 275 clk_unprepare(pc->clk);