1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2018 Emmanuel Vadot <manu@FreeBSD.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD$ 28 */ 29 30#include <sys/cdefs.h> 31__FBSDID("$FreeBSD$"); 32 33#include <sys/param.h> 34#include <sys/systm.h> 35#include <sys/bus.h> 36#include <sys/kernel.h> 37#include <sys/module.h> 38#include <sys/rman.h> 39#include <sys/resource.h> 40#include <machine/bus.h> 41 42#include <dev/ofw/ofw_bus.h> 43#include <dev/ofw/ofw_bus_subr.h> 44 45#include <dev/extres/clk/clk.h> 46 47#include "pwmbus_if.h" 48 49#define AW_PWM_CTRL 0x00 50#define AW_PWM_CTRL_PRESCALE_MASK 0xF 51#define AW_PWM_CTRL_EN (1 << 4) 52#define AW_PWM_CTRL_ACTIVE_LEVEL_HIGH (1 << 5) 53#define AW_PWM_CTRL_GATE (1 << 6) 54#define AW_PWM_CTRL_MODE_MASK 0x80 55#define AW_PWM_CTRL_PULSE_MODE (1 << 7) 56#define AW_PWM_CTRL_CYCLE_MODE (0 << 7) 57#define AW_PWM_CTRL_PULSE_START (1 << 8) 58#define AW_PWM_CTRL_CLK_BYPASS (1 << 9) 59#define AW_PWM_CTRL_PERIOD_BUSY (1 << 28) 60 61#define AW_PWM_PERIOD 0x04 62#define AW_PWM_PERIOD_TOTAL_MASK 0xFFFF 63#define AW_PWM_PERIOD_TOTAL_SHIFT 16 64#define AW_PWM_PERIOD_ACTIVE_MASK 0xFFFF 65#define AW_PWM_PERIOD_ACTIVE_SHIFT 0 66 67#define AW_PWM_MAX_FREQ 24000000 68 69#define NS_PER_SEC 1000000000 70 71static struct ofw_compat_data compat_data[] = { 72 { "allwinner,sun5i-a13-pwm", 1 }, 73 { "allwinner,sun8i-h3-pwm", 1 }, 74 { NULL, 0 } 75}; 76 77static struct resource_spec aw_pwm_spec[] = { 78 { SYS_RES_MEMORY, 0, RF_ACTIVE }, 79 { -1, 0 } 80}; 81 82struct aw_pwm_softc { 83 device_t dev; 84 device_t busdev; 85 clk_t clk; 86 struct resource *res; 87 88 uint64_t clk_freq; 89 unsigned int period; 90 unsigned int duty; 91 uint32_t flags; 92 bool enabled; 93}; 94 95static uint32_t aw_pwm_clk_prescaler[] = { 96 120, 97 180, 98 240, 99 360, 100 480, 101 0, 102 0, 103 0, 104 12000, 105 24000, 106 36000, 107 48000, 108 72000, 109 0, 110 0, 111 1, 112}; 113 114#define AW_PWM_READ(sc, reg) bus_read_4((sc)->res, (reg)) 115#define AW_PWM_WRITE(sc, reg, val) bus_write_4((sc)->res, (reg), (val)) 116 117static int aw_pwm_probe(device_t dev); 118static int aw_pwm_attach(device_t dev); 119static int aw_pwm_detach(device_t dev); 120 121static int 122aw_pwm_probe(device_t dev) 123{ 124 if (!ofw_bus_status_okay(dev)) 125 return (ENXIO); 126 127 if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) 128 return (ENXIO); 129 130 device_set_desc(dev, "Allwinner PWM"); 131 return (BUS_PROBE_DEFAULT); 132} 133 134static int 135aw_pwm_attach(device_t dev) 136{ 137 struct aw_pwm_softc *sc; 138 uint64_t clk_freq; 139 uint32_t reg; 140 phandle_t node; 141 int error; 142 143 sc = device_get_softc(dev); 144 sc->dev = dev; 145 146 error = clk_get_by_ofw_index(dev, 0, 0, &sc->clk); 147 if (error != 0) { 148 device_printf(dev, "cannot get clock\n"); 149 goto fail; 150 } 151 error = clk_enable(sc->clk); 152 if (error != 0) { 153 device_printf(dev, "cannot enable clock\n"); 154 goto fail; 155 } 156 157 error = clk_get_freq(sc->clk, &sc->clk_freq); 158 if (error != 0) { 159 device_printf(dev, "cannot get clock frequency\n"); 160 goto fail; 161 } 162 163 if (bus_alloc_resources(dev, aw_pwm_spec, &sc->res) != 0) { 164 device_printf(dev, "cannot allocate resources for device\n"); 165 error = ENXIO; 166 goto fail; 167 } 168 169 /* Read the configuration left by U-Boot */ 170 reg = AW_PWM_READ(sc, AW_PWM_CTRL); 171 if (reg & (AW_PWM_CTRL_GATE | AW_PWM_CTRL_EN)) 172 sc->enabled = true; 173 174 reg = AW_PWM_READ(sc, AW_PWM_CTRL); 175 reg &= AW_PWM_CTRL_PRESCALE_MASK; 176 if (reg > nitems(aw_pwm_clk_prescaler)) { 177 device_printf(dev, "Bad prescaler %x, cannot guess current settings\n", reg); 178 goto skipcfg; 179 } 180 clk_freq = sc->clk_freq / aw_pwm_clk_prescaler[reg]; 181 182 reg = AW_PWM_READ(sc, AW_PWM_PERIOD); 183 sc->period = NS_PER_SEC / 184 (clk_freq / ((reg >> AW_PWM_PERIOD_TOTAL_SHIFT) & AW_PWM_PERIOD_TOTAL_MASK)); 185 sc->duty = NS_PER_SEC / 186 (clk_freq / ((reg >> AW_PWM_PERIOD_ACTIVE_SHIFT) & AW_PWM_PERIOD_ACTIVE_MASK)); 187 188skipcfg: 189 /* 190 * Note that we don't check for failure to attach pwmbus -- even without 191 * it we can still service clients who connect via fdt xref data. 192 */ 193 node = ofw_bus_get_node(dev); 194 OF_device_register_xref(OF_xref_from_node(node), dev); 195 196 sc->busdev = device_add_child(dev, "pwmbus", -1); 197 198 return (bus_generic_attach(dev)); 199 200fail: 201 aw_pwm_detach(dev); 202 return (error); 203} 204 205static int 206aw_pwm_detach(device_t dev) 207{ 208 struct aw_pwm_softc *sc; 209 int error; 210 211 sc = device_get_softc(dev); 212 213 if ((error = bus_generic_detach(sc->dev)) != 0) { 214 device_printf(sc->dev, "cannot detach child devices\n"); 215 return (error); 216 } 217 218 if (sc->busdev != NULL) 219 device_delete_child(dev, sc->busdev); 220 221 if (sc->res != NULL) 222 bus_release_resources(dev, aw_pwm_spec, &sc->res); 223 224 return (0); 225} 226 227static phandle_t 228aw_pwm_get_node(device_t bus, device_t dev) 229{ 230 231 /* 232 * Share our controller node with our pwmbus child; it instantiates 233 * devices by walking the children contained within our node. 234 */ 235 return ofw_bus_get_node(bus); 236} 237 238static int 239aw_pwm_channel_count(device_t dev, u_int *nchannel) 240{ 241 242 *nchannel = 1; 243 244 return (0); 245} 246 247static int 248aw_pwm_channel_config(device_t dev, u_int channel, u_int period, u_int duty) 249{ 250 struct aw_pwm_softc *sc; 251 uint64_t period_freq, duty_freq; 252 uint64_t clk_rate, div; 253 uint32_t reg; 254 int prescaler; 255 int i; 256 257 sc = device_get_softc(dev); 258 259 period_freq = NS_PER_SEC / period; 260 if (period_freq > AW_PWM_MAX_FREQ) 261 return (EINVAL); 262 263 /* 264 * FIXME. The hardware is capable of sub-Hz frequencies, that is, 265 * periods longer than a second. But the current code cannot deal 266 * with those properly. 267 */ 268 if (period_freq == 0) 269 return (EINVAL); 270 271 /* 272 * FIXME. There is a great loss of precision when the period and the 273 * duty are near 1 second. In some cases period_freq and duty_freq can 274 * be equal even if the period and the duty are significantly different. 275 */ 276 duty_freq = NS_PER_SEC / duty; 277 if (duty_freq < period_freq) { 278 device_printf(sc->dev, "duty < period\n"); 279 return (EINVAL); 280 } 281 282 /* First test without prescaler */ 283 clk_rate = AW_PWM_MAX_FREQ; 284 prescaler = AW_PWM_CTRL_PRESCALE_MASK; 285 div = AW_PWM_MAX_FREQ / period_freq; 286 if ((div - 1) > AW_PWM_PERIOD_TOTAL_MASK) { 287 /* Test all prescaler */ 288 for (i = 0; i < nitems(aw_pwm_clk_prescaler); i++) { 289 if (aw_pwm_clk_prescaler[i] == 0) 290 continue; 291 div = AW_PWM_MAX_FREQ / aw_pwm_clk_prescaler[i] / period_freq; 292 if ((div - 1) < AW_PWM_PERIOD_TOTAL_MASK ) { 293 prescaler = i; 294 clk_rate = AW_PWM_MAX_FREQ / aw_pwm_clk_prescaler[i]; 295 break; 296 } 297 } 298 if (prescaler == AW_PWM_CTRL_PRESCALE_MASK) 299 return (EINVAL); 300 } 301 302 reg = AW_PWM_READ(sc, AW_PWM_CTRL); 303 304 /* Write the prescalar */ 305 reg &= ~AW_PWM_CTRL_PRESCALE_MASK; 306 reg |= prescaler; 307 308 reg &= ~AW_PWM_CTRL_MODE_MASK; 309 reg |= AW_PWM_CTRL_CYCLE_MODE; 310 311 reg &= ~AW_PWM_CTRL_PULSE_START; 312 reg &= ~AW_PWM_CTRL_CLK_BYPASS; 313 314 AW_PWM_WRITE(sc, AW_PWM_CTRL, reg); 315 316 /* Write the total/active cycles */ 317 reg = ((clk_rate / period_freq - 1) << AW_PWM_PERIOD_TOTAL_SHIFT) | 318 ((clk_rate / duty_freq) << AW_PWM_PERIOD_ACTIVE_SHIFT); 319 AW_PWM_WRITE(sc, AW_PWM_PERIOD, reg); 320 321 sc->period = period; 322 sc->duty = duty; 323 324 return (0); 325} 326 327static int 328aw_pwm_channel_get_config(device_t dev, u_int channel, u_int *period, u_int *duty) 329{ 330 struct aw_pwm_softc *sc; 331 332 sc = device_get_softc(dev); 333 334 *period = sc->period; 335 *duty = sc->duty; 336 337 return (0); 338} 339 340static int 341aw_pwm_channel_enable(device_t dev, u_int channel, bool enable) 342{ 343 struct aw_pwm_softc *sc; 344 uint32_t reg; 345 346 sc = device_get_softc(dev); 347 348 if (enable && sc->enabled) 349 return (0); 350 351 reg = AW_PWM_READ(sc, AW_PWM_CTRL); 352 if (enable) 353 reg |= AW_PWM_CTRL_GATE | AW_PWM_CTRL_EN; 354 else 355 reg &= ~(AW_PWM_CTRL_GATE | AW_PWM_CTRL_EN); 356 357 AW_PWM_WRITE(sc, AW_PWM_CTRL, reg); 358 359 sc->enabled = enable; 360 361 return (0); 362} 363 364static int 365aw_pwm_channel_is_enabled(device_t dev, u_int channel, bool *enabled) 366{ 367 struct aw_pwm_softc *sc; 368 369 sc = device_get_softc(dev); 370 371 *enabled = sc->enabled; 372 373 return (0); 374} 375 376static device_method_t aw_pwm_methods[] = { 377 /* Device interface */ 378 DEVMETHOD(device_probe, aw_pwm_probe), 379 DEVMETHOD(device_attach, aw_pwm_attach), 380 DEVMETHOD(device_detach, aw_pwm_detach), 381 382 /* ofw_bus interface */ 383 DEVMETHOD(ofw_bus_get_node, aw_pwm_get_node), 384 385 /* pwmbus interface */ 386 DEVMETHOD(pwmbus_channel_count, aw_pwm_channel_count), 387 DEVMETHOD(pwmbus_channel_config, aw_pwm_channel_config), 388 DEVMETHOD(pwmbus_channel_get_config, aw_pwm_channel_get_config), 389 DEVMETHOD(pwmbus_channel_enable, aw_pwm_channel_enable), 390 DEVMETHOD(pwmbus_channel_is_enabled, aw_pwm_channel_is_enabled), 391 392 DEVMETHOD_END 393}; 394 395static driver_t aw_pwm_driver = { 396 "pwm", 397 aw_pwm_methods, 398 sizeof(struct aw_pwm_softc), 399}; 400 401static devclass_t aw_pwm_devclass; 402 403DRIVER_MODULE(aw_pwm, simplebus, aw_pwm_driver, aw_pwm_devclass, 0, 0); 404MODULE_VERSION(aw_pwm, 1); 405SIMPLEBUS_PNP_INFO(compat_data); 406