1 /* 2 * Copyright (c) 2016 Google, Inc 3 * Written by Simon Glass <sjg@chromium.org> 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <common.h> 9 #include <clk.h> 10 #include <div64.h> 11 #include <dm.h> 12 #include <dm/pinctrl.h> 13 #include <pwm.h> 14 #include <regmap.h> 15 #include <syscon.h> 16 #include <asm/io.h> 17 #include <asm/arch/pwm.h> 18 #include <power/regulator.h> 19 20 DECLARE_GLOBAL_DATA_PTR; 21 22 /* 23 * regs for pwm v4 24 */ 25 #define HIWORD_UPDATE(v, l, h) (((v) << (l)) | (GENMASK(h, l) << 16)) 26 27 /* VERSION_ID */ 28 #define VERSION_ID 0x0 29 #define CHANNEL_NUM_SUPPORT_SHIFT 0 30 #define CHANNEL_NUM_SUPPORT_MASK (0xf << CHANNEL_NUM_SUPPORT_SHIFT) 31 #define CHANNLE_INDEX_SHIFT 4 32 #define CHANNLE_INDEX_MASK (0xf << CHANNLE_INDEX_SHIFT) 33 /* ENABLE */ 34 #define ENABLE 0x4 35 #define PWM_ENABLE_V4 (0x3 << 0) 36 #define PWM_CLK_EN(v) HIWORD_UPDATE(v, 0, 0) 37 #define PWM_EN(v) HIWORD_UPDATE(v, 1, 1) 38 #define PWM_CTRL_UPDATE_EN(v) HIWORD_UPDATE(v, 2, 2) 39 #define PWM_GLOBAL_JOIN_EN(v) HIWORD_UPDATE(v, 4, 4) 40 /* CLK_CTRL */ 41 #define CLK_CTRL 0x8 42 #define CLK_PRESCALE(v) HIWORD_UPDATE(v, 0, 2) 43 #define CLK_SCALE(v) HIWORD_UPDATE(v, 4, 12) 44 #define CLK_SRC_SEL(v) HIWORD_UPDATE(v, 13, 14) 45 #define CLK_GLOBAL_SEL(v) HIWORD_UPDATE(v, 15, 15) 46 /* CTRL */ 47 #define CTRL_V4 0xc 48 #define PWM_MODE(v) HIWORD_UPDATE(v, 0, 1) 49 #define ONESHOT_MODE 0 50 #define CONTINUOUS_MODE 1 51 #define CAPTURE_MODE 2 52 #define PWM_POLARITY(v) HIWORD_UPDATE(v, 2, 3) 53 #define DUTY_NEGATIVE (0 << 0) 54 #define DUTY_POSITIVE (1 << 0) 55 #define INACTIVE_NEGATIVE (0 << 1) 56 #define INACTIVE_POSITIVE (1 << 1) 57 #define PWM_ALIGNED_INVALID(v) HIWORD_UPDATE(v, 5, 5) 58 #define PWM_IN_SEL(v) HIWORD_UPDATE(v, 6, 8) 59 /* PERIOD */ 60 #define PERIOD 0x10 61 /* DUTY */ 62 #define DUTY 0x14 63 64 struct rk_pwm_priv { 65 fdt_addr_t base; 66 ulong freq; 67 u32 conf_polarity; 68 bool vop_pwm_en; /* indicate voppwm mirror register state */ 69 const struct rockchip_pwm_data *data; 70 }; 71 72 struct rockchip_pwm_funcs { 73 int (*set_invert)(struct udevice *dev, uint channel, bool polarity); 74 int (*set_config)(struct udevice *dev, uint channel, 75 uint period_ns, uint duty_ns); 76 int (*set_enable)(struct udevice *dev, uint channel, bool enable); 77 }; 78 79 struct rockchip_pwm_data { 80 struct rockchip_pwm_regs regs; 81 struct rockchip_pwm_funcs funcs; 82 unsigned int prescaler; 83 bool supports_polarity; 84 bool supports_lock; 85 bool vop_pwm; 86 u8 main_version; 87 u32 enable_conf; 88 u32 enable_conf_mask; 89 }; 90 91 static int rk_pwm_set_invert_v4(struct udevice *dev, uint channel, bool polarity) 92 { 93 struct rk_pwm_priv *priv = dev_get_priv(dev); 94 95 debug("%s: polarity=%u\n", __func__, polarity); 96 if (polarity) 97 priv->conf_polarity = DUTY_NEGATIVE | INACTIVE_POSITIVE; 98 else 99 priv->conf_polarity = DUTY_POSITIVE | INACTIVE_NEGATIVE; 100 101 return 0; 102 } 103 104 static int rk_pwm_set_invert_v1(struct udevice *dev, uint channel, bool polarity) 105 { 106 struct rk_pwm_priv *priv = dev_get_priv(dev); 107 108 debug("%s: polarity=%u\n", __func__, polarity); 109 if (polarity) 110 priv->conf_polarity = PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSTIVE; 111 else 112 priv->conf_polarity = PWM_DUTY_POSTIVE | PWM_INACTIVE_NEGATIVE; 113 114 return 0; 115 } 116 117 static int rk_pwm_set_invert(struct udevice *dev, uint channel, bool polarity) 118 { 119 struct rk_pwm_priv *priv = dev_get_priv(dev); 120 121 if (!priv->data->supports_polarity) { 122 debug("%s: Do not support polarity\n", __func__); 123 return 0; 124 } 125 126 return priv->data->funcs.set_invert(dev, channel, polarity); 127 } 128 129 static int rk_pwm_set_config_v4(struct udevice *dev, uint channel, 130 uint period_ns, uint duty_ns) 131 { 132 struct rk_pwm_priv *priv = dev_get_priv(dev); 133 unsigned long period, duty; 134 135 period = lldiv((uint64_t)(priv->freq / 1000) * period_ns, 136 priv->data->prescaler * 1000000); 137 duty = lldiv((uint64_t)(priv->freq / 1000) * duty_ns, 138 priv->data->prescaler * 1000000); 139 140 writel(period, priv->base + PERIOD); 141 writel(duty, priv->base + DUTY); 142 143 if (priv->data->supports_polarity) 144 writel(PWM_POLARITY(priv->conf_polarity), priv->base + CTRL_V4); 145 146 writel(PWM_MODE(CONTINUOUS_MODE) | PWM_ALIGNED_INVALID(false), 147 priv->base + CTRL_V4); 148 149 writel(PWM_CTRL_UPDATE_EN(true), priv->base + ENABLE); 150 151 debug("%s: period=%lu, duty=%lu\n", __func__, period, duty); 152 153 return 0; 154 } 155 156 static int rk_pwm_set_config_v1(struct udevice *dev, uint channel, 157 uint period_ns, uint duty_ns) 158 { 159 struct rk_pwm_priv *priv = dev_get_priv(dev); 160 const struct rockchip_pwm_regs *regs = &priv->data->regs; 161 unsigned long period, duty; 162 u32 ctrl; 163 164 debug("%s: period_ns=%u, duty_ns=%u\n", __func__, period_ns, duty_ns); 165 166 ctrl = readl(priv->base + regs->ctrl); 167 if (priv->data->vop_pwm) { 168 if (priv->vop_pwm_en) 169 ctrl |= RK_PWM_ENABLE; 170 else 171 ctrl &= ~RK_PWM_ENABLE; 172 } 173 174 /* 175 * Lock the period and duty of previous configuration, then 176 * change the duty and period, that would not be effective. 177 */ 178 if (priv->data->supports_lock) { 179 ctrl |= PWM_LOCK; 180 writel(ctrl, priv->base + regs->ctrl); 181 } 182 183 period = lldiv((uint64_t)(priv->freq / 1000) * period_ns, 184 priv->data->prescaler * 1000000); 185 duty = lldiv((uint64_t)(priv->freq / 1000) * duty_ns, 186 priv->data->prescaler * 1000000); 187 188 writel(period, priv->base + regs->period); 189 writel(duty, priv->base + regs->duty); 190 191 if (priv->data->supports_polarity) { 192 ctrl &= ~(PWM_DUTY_MASK | PWM_INACTIVE_MASK); 193 ctrl |= priv->conf_polarity; 194 } 195 196 /* 197 * Unlock and set polarity at the same time, 198 * the configuration of duty, period and polarity 199 * would be effective together at next period. 200 */ 201 if (priv->data->supports_lock) 202 ctrl &= ~PWM_LOCK; 203 writel(ctrl, priv->base + regs->ctrl); 204 205 debug("%s: period=%lu, duty=%lu\n", __func__, period, duty); 206 207 return 0; 208 } 209 210 static int rk_pwm_set_config(struct udevice *dev, uint channel, 211 uint period_ns, uint duty_ns) 212 { 213 struct rk_pwm_priv *priv = dev_get_priv(dev); 214 215 return priv->data->funcs.set_config(dev, channel, period_ns, duty_ns); 216 } 217 218 static int rk_pwm_set_enable_v4(struct udevice *dev, uint channel, bool enable) 219 { 220 struct rk_pwm_priv *priv = dev_get_priv(dev); 221 222 debug("%s: Enable '%s'\n", __func__, dev->name); 223 224 writel(PWM_EN(enable) | PWM_CLK_EN(enable), priv->base + ENABLE); 225 226 if (enable) 227 pinctrl_select_state(dev, "active"); 228 229 return 0; 230 } 231 232 static int rk_pwm_set_enable_v1(struct udevice *dev, uint channel, bool enable) 233 { 234 struct rk_pwm_priv *priv = dev_get_priv(dev); 235 const struct rockchip_pwm_regs *regs = &priv->data->regs; 236 u32 ctrl; 237 238 debug("%s: Enable '%s'\n", __func__, dev->name); 239 240 ctrl = readl(priv->base + regs->ctrl); 241 ctrl &= ~priv->data->enable_conf_mask; 242 243 if (enable) 244 ctrl |= priv->data->enable_conf; 245 else 246 ctrl &= ~priv->data->enable_conf; 247 248 writel(ctrl, priv->base + regs->ctrl); 249 if (priv->data->vop_pwm) 250 priv->vop_pwm_en = enable; 251 252 if (enable) 253 pinctrl_select_state(dev, "active"); 254 255 return 0; 256 } 257 258 static int rk_pwm_set_enable(struct udevice *dev, uint channel, bool enable) 259 { 260 struct rk_pwm_priv *priv = dev_get_priv(dev); 261 262 return priv->data->funcs.set_enable(dev, channel, enable); 263 } 264 265 static int rk_pwm_ofdata_to_platdata(struct udevice *dev) 266 { 267 struct rk_pwm_priv *priv = dev_get_priv(dev); 268 269 priv->base = dev_read_addr(dev); 270 271 return 0; 272 } 273 274 #if defined(CONFIG_MOS_SUPPORT) && !defined(CONFIG_SPL_BUILD) 275 static int rk_pwm_clk_init(struct udevice *dev) 276 { 277 struct clk_bulk clks = { 0 }; 278 int ret = 0; 279 280 ret = clk_get_bulk(dev, &clks); 281 if (ret == -ENOSYS || ret == -ENOENT) 282 return 0; 283 if (ret) { 284 dev_err(dev, "failed to get clk: %d\n", ret); 285 return ret; 286 } 287 288 ret = clk_enable_bulk(&clks); 289 if (ret) { 290 dev_err(dev, "failed to enable clk: %d\n", ret); 291 clk_release_bulk(&clks); 292 return ret; 293 } 294 295 return 0; 296 } 297 #endif 298 299 static int rk_pwm_probe(struct udevice *dev) 300 { 301 struct rk_pwm_priv *priv = dev_get_priv(dev); 302 struct clk clk; 303 int ret = 0; 304 305 ret = clk_get_by_index(dev, 0, &clk); 306 if (ret < 0) { 307 debug("%s get clock fail!\n", __func__); 308 return -EINVAL; 309 } 310 311 ret = clk_get_rate(&clk); 312 if (ret < 0) { 313 debug("%s pwm get clock rate fail!\n", __func__); 314 return -EINVAL; 315 } 316 priv->freq = ret; 317 priv->data = (struct rockchip_pwm_data *)dev_get_driver_data(dev); 318 319 if (priv->data->supports_polarity) { 320 if (priv->data->main_version >= 4) { 321 priv->conf_polarity = DUTY_POSITIVE | INACTIVE_NEGATIVE; 322 } else { 323 priv->conf_polarity = PWM_DUTY_POSTIVE | PWM_INACTIVE_POSTIVE; 324 } 325 } 326 327 #if defined(CONFIG_MOS_SUPPORT) && !defined(CONFIG_SPL_BUILD) 328 ret = rk_pwm_clk_init(dev); 329 if (ret) 330 return ret; 331 #endif 332 333 return 0; 334 } 335 336 static const struct pwm_ops rk_pwm_ops = { 337 .set_invert = rk_pwm_set_invert, 338 .set_config = rk_pwm_set_config, 339 .set_enable = rk_pwm_set_enable, 340 }; 341 342 static const struct rockchip_pwm_data pwm_data_v1 = { 343 .main_version = 0x01, 344 .regs = { 345 .version = 0x5c, 346 .duty = 0x04, 347 .period = 0x08, 348 .ctrl = 0x0c, 349 }, 350 .prescaler = 2, 351 .supports_polarity = false, 352 .supports_lock = false, 353 .vop_pwm = false, 354 .enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN, 355 .enable_conf_mask = BIT(1) | BIT(3), 356 .funcs = { 357 .set_invert = rk_pwm_set_invert_v1, 358 .set_config = rk_pwm_set_config_v1, 359 .set_enable = rk_pwm_set_enable_v1, 360 }, 361 }; 362 363 static const struct rockchip_pwm_data pwm_data_v2 = { 364 .main_version = 0x02, 365 .regs = { 366 .version = 0x5c, 367 .duty = 0x08, 368 .period = 0x04, 369 .ctrl = 0x0c, 370 }, 371 .prescaler = 1, 372 .supports_polarity = true, 373 .supports_lock = false, 374 .vop_pwm = false, 375 .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | RK_PWM_ENABLE | 376 PWM_CONTINUOUS, 377 .enable_conf_mask = GENMASK(2, 0) | BIT(5) | BIT(8), 378 .funcs = { 379 .set_invert = rk_pwm_set_invert_v1, 380 .set_config = rk_pwm_set_config_v1, 381 .set_enable = rk_pwm_set_enable_v1, 382 }, 383 }; 384 385 static const struct rockchip_pwm_data pwm_data_vop = { 386 .main_version = 0x02, 387 .regs = { 388 .version = 0x5c, 389 .duty = 0x08, 390 .period = 0x04, 391 .ctrl = 0x00, 392 }, 393 .prescaler = 1, 394 .supports_polarity = true, 395 .supports_lock = false, 396 .vop_pwm = true, 397 .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | RK_PWM_ENABLE | 398 PWM_CONTINUOUS, 399 .enable_conf_mask = GENMASK(2, 0) | BIT(5) | BIT(8), 400 .funcs = { 401 .set_invert = rk_pwm_set_invert_v1, 402 .set_config = rk_pwm_set_config_v1, 403 .set_enable = rk_pwm_set_enable_v1, 404 }, 405 }; 406 407 static const struct rockchip_pwm_data pwm_data_v3 = { 408 .main_version = 0x03, 409 .regs = { 410 .version = 0x5c, 411 .duty = 0x08, 412 .period = 0x04, 413 .ctrl = 0x0c, 414 }, 415 .prescaler = 1, 416 .supports_polarity = true, 417 .supports_lock = true, 418 .vop_pwm = false, 419 .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | RK_PWM_ENABLE | 420 PWM_CONTINUOUS, 421 .enable_conf_mask = GENMASK(2, 0) | BIT(5) | BIT(8), 422 .funcs = { 423 .set_invert = rk_pwm_set_invert_v1, 424 .set_config = rk_pwm_set_config_v1, 425 .set_enable = rk_pwm_set_enable_v1, 426 }, 427 }; 428 429 static const struct rockchip_pwm_data pwm_data_v4 = { 430 .main_version = 0x04, 431 .regs = { 432 .version = 0x0, 433 .enable = 0x4, 434 .ctrl = 0xc, 435 .period = 0x10, 436 .duty = 0x14, 437 }, 438 .prescaler = 1, 439 .supports_polarity = true, 440 .supports_lock = true, 441 .vop_pwm = false, 442 .enable_conf = PWM_ENABLE_V4, 443 .funcs = { 444 .set_invert = rk_pwm_set_invert_v4, 445 .set_config = rk_pwm_set_config_v4, 446 .set_enable = rk_pwm_set_enable_v4, 447 }, 448 }; 449 450 static const struct udevice_id rk_pwm_ids[] = { 451 { .compatible = "rockchip,rk2928-pwm", .data = (ulong)&pwm_data_v1}, 452 { .compatible = "rockchip,rk3288-pwm", .data = (ulong)&pwm_data_v2}, 453 { .compatible = "rockchip,rk3328-pwm", .data = (ulong)&pwm_data_v3}, 454 { .compatible = "rockchip,vop-pwm", .data = (ulong)&pwm_data_vop}, 455 { .compatible = "rockchip,rk3399-pwm", .data = (ulong)&pwm_data_v2}, 456 { .compatible = "rockchip,rk3576-pwm", .data = (ulong)&pwm_data_v4}, 457 { } 458 }; 459 460 U_BOOT_DRIVER(rk_pwm) = { 461 .name = "rk_pwm", 462 .id = UCLASS_PWM, 463 .of_match = rk_pwm_ids, 464 .ops = &rk_pwm_ops, 465 .ofdata_to_platdata = rk_pwm_ofdata_to_platdata, 466 .probe = rk_pwm_probe, 467 .priv_auto_alloc_size = sizeof(struct rk_pwm_priv), 468 }; 469