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 struct rockchip_pwm_data { 23 struct rockchip_pwm_regs regs; 24 unsigned int prescaler; 25 bool supports_polarity; 26 bool supports_lock; 27 bool vop_pwm; 28 u32 enable_conf; 29 u32 enable_conf_mask; 30 }; 31 32 struct rk_pwm_priv { 33 fdt_addr_t base; 34 ulong freq; 35 u32 conf_polarity; 36 bool vop_pwm_en; /* indicate voppwm mirror register state */ 37 const struct rockchip_pwm_data *data; 38 }; 39 40 static int rk_pwm_set_invert(struct udevice *dev, uint channel, bool polarity) 41 { 42 struct rk_pwm_priv *priv = dev_get_priv(dev); 43 44 if (!priv->data->supports_polarity) { 45 debug("%s: Do not support polarity\n", __func__); 46 return 0; 47 } 48 49 debug("%s: polarity=%u\n", __func__, polarity); 50 if (polarity) 51 priv->conf_polarity = PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSTIVE; 52 else 53 priv->conf_polarity = PWM_DUTY_POSTIVE | PWM_INACTIVE_NEGATIVE; 54 55 return 0; 56 } 57 58 static int rk_pwm_set_config(struct udevice *dev, uint channel, uint period_ns, 59 uint duty_ns) 60 { 61 struct rk_pwm_priv *priv = dev_get_priv(dev); 62 const struct rockchip_pwm_regs *regs = &priv->data->regs; 63 unsigned long period, duty; 64 u32 ctrl; 65 66 debug("%s: period_ns=%u, duty_ns=%u\n", __func__, period_ns, duty_ns); 67 68 ctrl = readl(priv->base + regs->ctrl); 69 if (priv->data->vop_pwm) { 70 if (priv->vop_pwm_en) 71 ctrl |= RK_PWM_ENABLE; 72 else 73 ctrl &= ~RK_PWM_ENABLE; 74 } 75 76 /* 77 * Lock the period and duty of previous configuration, then 78 * change the duty and period, that would not be effective. 79 */ 80 if (priv->data->supports_lock) { 81 ctrl |= PWM_LOCK; 82 writel(ctrl, priv->base + regs->ctrl); 83 } 84 85 period = lldiv((uint64_t)(priv->freq / 1000) * period_ns, 86 priv->data->prescaler * 1000000); 87 duty = lldiv((uint64_t)(priv->freq / 1000) * duty_ns, 88 priv->data->prescaler * 1000000); 89 90 writel(period, priv->base + regs->period); 91 writel(duty, priv->base + regs->duty); 92 93 if (priv->data->supports_polarity) { 94 ctrl &= ~(PWM_DUTY_MASK | PWM_INACTIVE_MASK); 95 ctrl |= priv->conf_polarity; 96 } 97 98 /* 99 * Unlock and set polarity at the same time, 100 * the configuration of duty, period and polarity 101 * would be effective together at next period. 102 */ 103 if (priv->data->supports_lock) 104 ctrl &= ~PWM_LOCK; 105 writel(ctrl, priv->base + regs->ctrl); 106 107 debug("%s: period=%lu, duty=%lu\n", __func__, period, duty); 108 109 return 0; 110 } 111 112 static int rk_pwm_set_enable(struct udevice *dev, uint channel, bool enable) 113 { 114 struct rk_pwm_priv *priv = dev_get_priv(dev); 115 const struct rockchip_pwm_regs *regs = &priv->data->regs; 116 u32 ctrl; 117 118 debug("%s: Enable '%s'\n", __func__, dev->name); 119 120 ctrl = readl(priv->base + regs->ctrl); 121 ctrl &= ~priv->data->enable_conf_mask; 122 123 if (enable) 124 ctrl |= priv->data->enable_conf; 125 else 126 ctrl &= ~priv->data->enable_conf; 127 128 writel(ctrl, priv->base + regs->ctrl); 129 if (priv->data->vop_pwm) 130 priv->vop_pwm_en = enable; 131 132 if (enable) 133 pinctrl_select_state(dev, "active"); 134 135 return 0; 136 } 137 138 static int rk_pwm_ofdata_to_platdata(struct udevice *dev) 139 { 140 struct rk_pwm_priv *priv = dev_get_priv(dev); 141 142 priv->base = dev_read_addr(dev); 143 144 return 0; 145 } 146 147 static int rk_pwm_probe(struct udevice *dev) 148 { 149 struct rk_pwm_priv *priv = dev_get_priv(dev); 150 struct clk clk; 151 int ret = 0; 152 153 ret = clk_get_by_index(dev, 0, &clk); 154 if (ret < 0) { 155 debug("%s get clock fail!\n", __func__); 156 return -EINVAL; 157 } 158 159 ret = clk_get_rate(&clk); 160 if (ret < 0) { 161 debug("%s pwm get clock rate fail!\n", __func__); 162 return -EINVAL; 163 } 164 priv->freq = ret; 165 priv->data = (struct rockchip_pwm_data *)dev_get_driver_data(dev); 166 167 if (priv->data->supports_polarity) 168 priv->conf_polarity = PWM_DUTY_POSTIVE | PWM_INACTIVE_POSTIVE; 169 170 return 0; 171 } 172 173 static const struct pwm_ops rk_pwm_ops = { 174 .set_invert = rk_pwm_set_invert, 175 .set_config = rk_pwm_set_config, 176 .set_enable = rk_pwm_set_enable, 177 }; 178 179 static const struct rockchip_pwm_data pwm_data_v1 = { 180 .regs = { 181 .duty = 0x04, 182 .period = 0x08, 183 .cntr = 0x00, 184 .ctrl = 0x0c, 185 }, 186 .prescaler = 2, 187 .supports_polarity = false, 188 .supports_lock = false, 189 .vop_pwm = false, 190 .enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN, 191 .enable_conf_mask = BIT(1) | BIT(3), 192 }; 193 194 static const struct rockchip_pwm_data pwm_data_v2 = { 195 .regs = { 196 .duty = 0x08, 197 .period = 0x04, 198 .cntr = 0x00, 199 .ctrl = 0x0c, 200 }, 201 .prescaler = 1, 202 .supports_polarity = true, 203 .supports_lock = false, 204 .vop_pwm = false, 205 .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | RK_PWM_ENABLE | 206 PWM_CONTINUOUS, 207 .enable_conf_mask = GENMASK(2, 0) | BIT(5) | BIT(8), 208 }; 209 210 static const struct rockchip_pwm_data pwm_data_vop = { 211 .regs = { 212 .duty = 0x08, 213 .period = 0x04, 214 .cntr = 0x0c, 215 .ctrl = 0x00, 216 }, 217 .prescaler = 1, 218 .supports_polarity = true, 219 .supports_lock = false, 220 .vop_pwm = true, 221 .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | RK_PWM_ENABLE | 222 PWM_CONTINUOUS, 223 .enable_conf_mask = GENMASK(2, 0) | BIT(5) | BIT(8), 224 }; 225 226 static const struct rockchip_pwm_data pwm_data_v3 = { 227 .regs = { 228 .duty = 0x08, 229 .period = 0x04, 230 .cntr = 0x00, 231 .ctrl = 0x0c, 232 }, 233 .prescaler = 1, 234 .supports_polarity = true, 235 .supports_lock = true, 236 .vop_pwm = false, 237 .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | RK_PWM_ENABLE | 238 PWM_CONTINUOUS, 239 .enable_conf_mask = GENMASK(2, 0) | BIT(5) | BIT(8), 240 }; 241 242 static const struct udevice_id rk_pwm_ids[] = { 243 { .compatible = "rockchip,rk2928-pwm", .data = (ulong)&pwm_data_v1}, 244 { .compatible = "rockchip,rk3288-pwm", .data = (ulong)&pwm_data_v2}, 245 { .compatible = "rockchip,rk3328-pwm", .data = (ulong)&pwm_data_v3}, 246 { .compatible = "rockchip,vop-pwm", .data = (ulong)&pwm_data_vop}, 247 { .compatible = "rockchip,rk3399-pwm", .data = (ulong)&pwm_data_v2}, 248 { } 249 }; 250 251 U_BOOT_DRIVER(rk_pwm) = { 252 .name = "rk_pwm", 253 .id = UCLASS_PWM, 254 .of_match = rk_pwm_ids, 255 .ops = &rk_pwm_ops, 256 .ofdata_to_platdata = rk_pwm_ofdata_to_platdata, 257 .probe = rk_pwm_probe, 258 .priv_auto_alloc_size = sizeof(struct rk_pwm_priv), 259 }; 260