1*2e3507c2SEmmanuel Vadot /*- 2*2e3507c2SEmmanuel Vadot * SPDX-License-Identifier: BSD-2-Clause 3*2e3507c2SEmmanuel Vadot * 4*2e3507c2SEmmanuel Vadot * Copyright (c) 2018 Emmanuel Vadot <manu@FreeBSD.org> 5*2e3507c2SEmmanuel Vadot * Copyright (c) 2019 Brandon Bergren <git@bdragon.rtk0.net> 6*2e3507c2SEmmanuel Vadot * 7*2e3507c2SEmmanuel Vadot * Redistribution and use in source and binary forms, with or without 8*2e3507c2SEmmanuel Vadot * modification, are permitted provided that the following conditions 9*2e3507c2SEmmanuel Vadot * are met: 10*2e3507c2SEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright 11*2e3507c2SEmmanuel Vadot * notice, this list of conditions and the following disclaimer. 12*2e3507c2SEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright 13*2e3507c2SEmmanuel Vadot * notice, this list of conditions and the following disclaimer in the 14*2e3507c2SEmmanuel Vadot * documentation and/or other materials provided with the distribution. 15*2e3507c2SEmmanuel Vadot * 16*2e3507c2SEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17*2e3507c2SEmmanuel Vadot * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18*2e3507c2SEmmanuel Vadot * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19*2e3507c2SEmmanuel Vadot * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20*2e3507c2SEmmanuel Vadot * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21*2e3507c2SEmmanuel Vadot * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22*2e3507c2SEmmanuel Vadot * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23*2e3507c2SEmmanuel Vadot * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24*2e3507c2SEmmanuel Vadot * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25*2e3507c2SEmmanuel Vadot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26*2e3507c2SEmmanuel Vadot * SUCH DAMAGE. 27*2e3507c2SEmmanuel Vadot */ 28*2e3507c2SEmmanuel Vadot 29*2e3507c2SEmmanuel Vadot #include <sys/param.h> 30*2e3507c2SEmmanuel Vadot #include <sys/systm.h> 31*2e3507c2SEmmanuel Vadot #include <sys/bus.h> 32*2e3507c2SEmmanuel Vadot #include <sys/kernel.h> 33*2e3507c2SEmmanuel Vadot #include <sys/module.h> 34*2e3507c2SEmmanuel Vadot #include <sys/rman.h> 35*2e3507c2SEmmanuel Vadot #include <sys/resource.h> 36*2e3507c2SEmmanuel Vadot #include <machine/bus.h> 37*2e3507c2SEmmanuel Vadot 38*2e3507c2SEmmanuel Vadot #include <dev/ofw/ofw_bus.h> 39*2e3507c2SEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h> 40*2e3507c2SEmmanuel Vadot 41*2e3507c2SEmmanuel Vadot #include <dev/extres/clk/clk.h> 42*2e3507c2SEmmanuel Vadot 43*2e3507c2SEmmanuel Vadot #include "pwmbus_if.h" 44*2e3507c2SEmmanuel Vadot 45*2e3507c2SEmmanuel Vadot /* Register offsets. */ 46*2e3507c2SEmmanuel Vadot #define RK_PWM_COUNTER 0x00 47*2e3507c2SEmmanuel Vadot #define RK_PWM_PERIOD 0x04 48*2e3507c2SEmmanuel Vadot #define RK_PWM_DUTY 0x08 49*2e3507c2SEmmanuel Vadot #define RK_PWM_CTRL 0x0c 50*2e3507c2SEmmanuel Vadot 51*2e3507c2SEmmanuel Vadot #define SET(reg,mask,val) reg = ((reg & ~mask) | val) 52*2e3507c2SEmmanuel Vadot 53*2e3507c2SEmmanuel Vadot #define RK_PWM_CTRL_ENABLE_MASK (1 << 0) 54*2e3507c2SEmmanuel Vadot #define RK_PWM_CTRL_ENABLED (1 << 0) 55*2e3507c2SEmmanuel Vadot #define RK_PWM_CTRL_DISABLED (0) 56*2e3507c2SEmmanuel Vadot 57*2e3507c2SEmmanuel Vadot #define RK_PWM_CTRL_MODE_MASK (3 << 1) 58*2e3507c2SEmmanuel Vadot #define RK_PWM_CTRL_MODE_ONESHOT (0) 59*2e3507c2SEmmanuel Vadot #define RK_PWM_CTRL_MODE_CONTINUOUS (1 << 1) 60*2e3507c2SEmmanuel Vadot #define RK_PWM_CTRL_MODE_CAPTURE (1 << 2) 61*2e3507c2SEmmanuel Vadot 62*2e3507c2SEmmanuel Vadot #define RK_PWM_CTRL_DUTY_MASK (1 << 3) 63*2e3507c2SEmmanuel Vadot #define RK_PWM_CTRL_DUTY_POSITIVE (1 << 3) 64*2e3507c2SEmmanuel Vadot #define RK_PWM_CTRL_DUTY_NEGATIVE (0) 65*2e3507c2SEmmanuel Vadot 66*2e3507c2SEmmanuel Vadot #define RK_PWM_CTRL_INACTIVE_MASK (1 << 4) 67*2e3507c2SEmmanuel Vadot #define RK_PWM_CTRL_INACTIVE_POSITIVE (1 << 4) 68*2e3507c2SEmmanuel Vadot #define RK_PWM_CTRL_INACTIVE_NEGATIVE (0) 69*2e3507c2SEmmanuel Vadot 70*2e3507c2SEmmanuel Vadot /* PWM Output Alignment */ 71*2e3507c2SEmmanuel Vadot #define RK_PWM_CTRL_ALIGN_MASK (1 << 5) 72*2e3507c2SEmmanuel Vadot #define RK_PWM_CTRL_ALIGN_CENTER (1 << 5) 73*2e3507c2SEmmanuel Vadot #define RK_PWM_CTRL_ALIGN_LEFT (0) 74*2e3507c2SEmmanuel Vadot 75*2e3507c2SEmmanuel Vadot /* Low power mode: disable prescaler when inactive */ 76*2e3507c2SEmmanuel Vadot #define RK_PWM_CTRL_LP_MASK (1 << 8) 77*2e3507c2SEmmanuel Vadot #define RK_PWM_CTRL_LP_ENABLE (1 << 8) 78*2e3507c2SEmmanuel Vadot #define RK_PWM_CTRL_LP_DISABLE (0) 79*2e3507c2SEmmanuel Vadot 80*2e3507c2SEmmanuel Vadot /* Clock source: bypass the scaler or not */ 81*2e3507c2SEmmanuel Vadot #define RK_PWM_CTRL_CLOCKSRC_MASK (1 << 9) 82*2e3507c2SEmmanuel Vadot #define RK_PWM_CTRL_CLOCKSRC_NONSCALED (0) 83*2e3507c2SEmmanuel Vadot #define RK_PWM_CTRL_CLOCKSRC_SCALED (1 << 9) 84*2e3507c2SEmmanuel Vadot 85*2e3507c2SEmmanuel Vadot #define RK_PWM_CTRL_PRESCALE_MASK (7 << 12) 86*2e3507c2SEmmanuel Vadot #define RK_PWM_CTRL_PRESCALE_SHIFT 12 87*2e3507c2SEmmanuel Vadot 88*2e3507c2SEmmanuel Vadot #define RK_PWM_CTRL_SCALE_MASK (0xFF << 16) 89*2e3507c2SEmmanuel Vadot #define RK_PWM_CTRL_SCALE_SHIFT 16 90*2e3507c2SEmmanuel Vadot 91*2e3507c2SEmmanuel Vadot #define RK_PWM_CTRL_REPEAT_MASK (0xFF << 24) 92*2e3507c2SEmmanuel Vadot #define RK_PWM_CTRL_REPEAT_SHIFT 24 93*2e3507c2SEmmanuel Vadot 94*2e3507c2SEmmanuel Vadot #define NS_PER_SEC 1000000000 95*2e3507c2SEmmanuel Vadot 96*2e3507c2SEmmanuel Vadot static struct ofw_compat_data compat_data[] = { 97*2e3507c2SEmmanuel Vadot { "rockchip,rk3288-pwm", 1 }, 98*2e3507c2SEmmanuel Vadot { "rockchip,rk3399-pwm", 1 }, 99*2e3507c2SEmmanuel Vadot { NULL, 0 } 100*2e3507c2SEmmanuel Vadot }; 101*2e3507c2SEmmanuel Vadot 102*2e3507c2SEmmanuel Vadot static struct resource_spec rk_pwm_spec[] = { 103*2e3507c2SEmmanuel Vadot { SYS_RES_MEMORY, 0, RF_ACTIVE }, 104*2e3507c2SEmmanuel Vadot { -1, 0 } 105*2e3507c2SEmmanuel Vadot }; 106*2e3507c2SEmmanuel Vadot 107*2e3507c2SEmmanuel Vadot struct rk_pwm_softc { 108*2e3507c2SEmmanuel Vadot device_t dev; 109*2e3507c2SEmmanuel Vadot device_t busdev; 110*2e3507c2SEmmanuel Vadot clk_t clk; 111*2e3507c2SEmmanuel Vadot struct resource *res; 112*2e3507c2SEmmanuel Vadot 113*2e3507c2SEmmanuel Vadot uint64_t clk_freq; 114*2e3507c2SEmmanuel Vadot unsigned int period; 115*2e3507c2SEmmanuel Vadot unsigned int duty; 116*2e3507c2SEmmanuel Vadot uint32_t flags; 117*2e3507c2SEmmanuel Vadot uint8_t prescaler; 118*2e3507c2SEmmanuel Vadot uint8_t scaler; 119*2e3507c2SEmmanuel Vadot bool using_scaler; 120*2e3507c2SEmmanuel Vadot bool enabled; 121*2e3507c2SEmmanuel Vadot }; 122*2e3507c2SEmmanuel Vadot 123*2e3507c2SEmmanuel Vadot #define RK_PWM_READ(sc, reg) bus_read_4((sc)->res, (reg)) 124*2e3507c2SEmmanuel Vadot #define RK_PWM_WRITE(sc, reg, val) bus_write_4((sc)->res, (reg), (val)) 125*2e3507c2SEmmanuel Vadot 126*2e3507c2SEmmanuel Vadot static int rk_pwm_probe(device_t dev); 127*2e3507c2SEmmanuel Vadot static int rk_pwm_attach(device_t dev); 128*2e3507c2SEmmanuel Vadot static int rk_pwm_detach(device_t dev); 129*2e3507c2SEmmanuel Vadot 130*2e3507c2SEmmanuel Vadot static int 131*2e3507c2SEmmanuel Vadot rk_pwm_probe(device_t dev) 132*2e3507c2SEmmanuel Vadot { 133*2e3507c2SEmmanuel Vadot if (!ofw_bus_status_okay(dev)) 134*2e3507c2SEmmanuel Vadot return (ENXIO); 135*2e3507c2SEmmanuel Vadot 136*2e3507c2SEmmanuel Vadot if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) 137*2e3507c2SEmmanuel Vadot return (ENXIO); 138*2e3507c2SEmmanuel Vadot 139*2e3507c2SEmmanuel Vadot device_set_desc(dev, "Rockchip PWM"); 140*2e3507c2SEmmanuel Vadot return (BUS_PROBE_DEFAULT); 141*2e3507c2SEmmanuel Vadot } 142*2e3507c2SEmmanuel Vadot 143*2e3507c2SEmmanuel Vadot static int 144*2e3507c2SEmmanuel Vadot rk_pwm_attach(device_t dev) 145*2e3507c2SEmmanuel Vadot { 146*2e3507c2SEmmanuel Vadot struct rk_pwm_softc *sc; 147*2e3507c2SEmmanuel Vadot phandle_t node; 148*2e3507c2SEmmanuel Vadot uint64_t clk_freq; 149*2e3507c2SEmmanuel Vadot uint32_t reg; 150*2e3507c2SEmmanuel Vadot int error; 151*2e3507c2SEmmanuel Vadot 152*2e3507c2SEmmanuel Vadot sc = device_get_softc(dev); 153*2e3507c2SEmmanuel Vadot sc->dev = dev; 154*2e3507c2SEmmanuel Vadot 155*2e3507c2SEmmanuel Vadot error = clk_get_by_ofw_index(dev, 0, 0, &sc->clk); 156*2e3507c2SEmmanuel Vadot if (error != 0) { 157*2e3507c2SEmmanuel Vadot device_printf(dev, "cannot get clock\n"); 158*2e3507c2SEmmanuel Vadot goto fail; 159*2e3507c2SEmmanuel Vadot } 160*2e3507c2SEmmanuel Vadot error = clk_enable(sc->clk); 161*2e3507c2SEmmanuel Vadot if (error != 0) { 162*2e3507c2SEmmanuel Vadot device_printf(dev, "cannot enable clock\n"); 163*2e3507c2SEmmanuel Vadot goto fail; 164*2e3507c2SEmmanuel Vadot } 165*2e3507c2SEmmanuel Vadot error = clk_get_freq(sc->clk, &sc->clk_freq); 166*2e3507c2SEmmanuel Vadot if (error != 0) { 167*2e3507c2SEmmanuel Vadot device_printf(dev, "cannot get base frequency\n"); 168*2e3507c2SEmmanuel Vadot goto fail; 169*2e3507c2SEmmanuel Vadot } 170*2e3507c2SEmmanuel Vadot 171*2e3507c2SEmmanuel Vadot if (bus_alloc_resources(dev, rk_pwm_spec, &sc->res) != 0) { 172*2e3507c2SEmmanuel Vadot device_printf(dev, "cannot allocate resources for device\n"); 173*2e3507c2SEmmanuel Vadot error = ENXIO; 174*2e3507c2SEmmanuel Vadot goto fail; 175*2e3507c2SEmmanuel Vadot } 176*2e3507c2SEmmanuel Vadot 177*2e3507c2SEmmanuel Vadot /* Read the configuration left by U-Boot */ 178*2e3507c2SEmmanuel Vadot reg = RK_PWM_READ(sc, RK_PWM_CTRL); 179*2e3507c2SEmmanuel Vadot if ((reg & RK_PWM_CTRL_ENABLE_MASK) == RK_PWM_CTRL_ENABLED) 180*2e3507c2SEmmanuel Vadot sc->enabled = true; 181*2e3507c2SEmmanuel Vadot 182*2e3507c2SEmmanuel Vadot reg = RK_PWM_READ(sc, RK_PWM_CTRL); 183*2e3507c2SEmmanuel Vadot reg &= RK_PWM_CTRL_PRESCALE_MASK; 184*2e3507c2SEmmanuel Vadot sc->prescaler = reg >> RK_PWM_CTRL_PRESCALE_SHIFT; 185*2e3507c2SEmmanuel Vadot 186*2e3507c2SEmmanuel Vadot reg = RK_PWM_READ(sc, RK_PWM_CTRL); 187*2e3507c2SEmmanuel Vadot reg &= RK_PWM_CTRL_SCALE_MASK; 188*2e3507c2SEmmanuel Vadot sc->scaler = reg >> RK_PWM_CTRL_SCALE_SHIFT; 189*2e3507c2SEmmanuel Vadot 190*2e3507c2SEmmanuel Vadot reg = RK_PWM_READ(sc, RK_PWM_CTRL); 191*2e3507c2SEmmanuel Vadot if ((reg & RK_PWM_CTRL_CLOCKSRC_MASK) == RK_PWM_CTRL_CLOCKSRC_SCALED) 192*2e3507c2SEmmanuel Vadot sc->using_scaler = true; 193*2e3507c2SEmmanuel Vadot else 194*2e3507c2SEmmanuel Vadot sc->using_scaler = false; 195*2e3507c2SEmmanuel Vadot 196*2e3507c2SEmmanuel Vadot clk_freq = sc->clk_freq / (2 ^ sc->prescaler); 197*2e3507c2SEmmanuel Vadot 198*2e3507c2SEmmanuel Vadot if (sc->using_scaler) { 199*2e3507c2SEmmanuel Vadot if (sc->scaler == 0) 200*2e3507c2SEmmanuel Vadot clk_freq /= 512; 201*2e3507c2SEmmanuel Vadot else 202*2e3507c2SEmmanuel Vadot clk_freq /= (sc->scaler * 2); 203*2e3507c2SEmmanuel Vadot } 204*2e3507c2SEmmanuel Vadot 205*2e3507c2SEmmanuel Vadot reg = RK_PWM_READ(sc, RK_PWM_PERIOD); 206*2e3507c2SEmmanuel Vadot sc->period = NS_PER_SEC / 207*2e3507c2SEmmanuel Vadot (clk_freq / reg); 208*2e3507c2SEmmanuel Vadot reg = RK_PWM_READ(sc, RK_PWM_DUTY); 209*2e3507c2SEmmanuel Vadot sc->duty = NS_PER_SEC / 210*2e3507c2SEmmanuel Vadot (clk_freq / reg); 211*2e3507c2SEmmanuel Vadot 212*2e3507c2SEmmanuel Vadot node = ofw_bus_get_node(dev); 213*2e3507c2SEmmanuel Vadot OF_device_register_xref(OF_xref_from_node(node), dev); 214*2e3507c2SEmmanuel Vadot 215*2e3507c2SEmmanuel Vadot sc->busdev = device_add_child(dev, "pwmbus", -1); 216*2e3507c2SEmmanuel Vadot 217*2e3507c2SEmmanuel Vadot return (bus_generic_attach(dev)); 218*2e3507c2SEmmanuel Vadot 219*2e3507c2SEmmanuel Vadot fail: 220*2e3507c2SEmmanuel Vadot rk_pwm_detach(dev); 221*2e3507c2SEmmanuel Vadot return (error); 222*2e3507c2SEmmanuel Vadot } 223*2e3507c2SEmmanuel Vadot 224*2e3507c2SEmmanuel Vadot static int 225*2e3507c2SEmmanuel Vadot rk_pwm_detach(device_t dev) 226*2e3507c2SEmmanuel Vadot { 227*2e3507c2SEmmanuel Vadot struct rk_pwm_softc *sc; 228*2e3507c2SEmmanuel Vadot 229*2e3507c2SEmmanuel Vadot sc = device_get_softc(dev); 230*2e3507c2SEmmanuel Vadot 231*2e3507c2SEmmanuel Vadot bus_generic_detach(sc->dev); 232*2e3507c2SEmmanuel Vadot 233*2e3507c2SEmmanuel Vadot bus_release_resources(dev, rk_pwm_spec, &sc->res); 234*2e3507c2SEmmanuel Vadot 235*2e3507c2SEmmanuel Vadot return (0); 236*2e3507c2SEmmanuel Vadot } 237*2e3507c2SEmmanuel Vadot 238*2e3507c2SEmmanuel Vadot static phandle_t 239*2e3507c2SEmmanuel Vadot aw_pwm_get_node(device_t bus, device_t dev) 240*2e3507c2SEmmanuel Vadot { 241*2e3507c2SEmmanuel Vadot 242*2e3507c2SEmmanuel Vadot /* 243*2e3507c2SEmmanuel Vadot * Share our controller node with our pwmbus child; it instantiates 244*2e3507c2SEmmanuel Vadot * devices by walking the children contained within our node. 245*2e3507c2SEmmanuel Vadot */ 246*2e3507c2SEmmanuel Vadot return ofw_bus_get_node(bus); 247*2e3507c2SEmmanuel Vadot } 248*2e3507c2SEmmanuel Vadot 249*2e3507c2SEmmanuel Vadot static int 250*2e3507c2SEmmanuel Vadot rk_pwm_channel_count(device_t dev, u_int *nchannel) 251*2e3507c2SEmmanuel Vadot { 252*2e3507c2SEmmanuel Vadot /* The device supports 4 channels, but attaches multiple times in the 253*2e3507c2SEmmanuel Vadot * device tree. This interferes with advanced usage though, as 254*2e3507c2SEmmanuel Vadot * the interrupt capability and channel 3 FIFO register offsets 255*2e3507c2SEmmanuel Vadot * don't work right in this situation. 256*2e3507c2SEmmanuel Vadot * But since we don't support those yet, pretend we are singlechannel. 257*2e3507c2SEmmanuel Vadot */ 258*2e3507c2SEmmanuel Vadot *nchannel = 1; 259*2e3507c2SEmmanuel Vadot 260*2e3507c2SEmmanuel Vadot return (0); 261*2e3507c2SEmmanuel Vadot } 262*2e3507c2SEmmanuel Vadot 263*2e3507c2SEmmanuel Vadot static int 264*2e3507c2SEmmanuel Vadot rk_pwm_channel_config(device_t dev, u_int channel, u_int period, u_int duty) 265*2e3507c2SEmmanuel Vadot { 266*2e3507c2SEmmanuel Vadot struct rk_pwm_softc *sc; 267*2e3507c2SEmmanuel Vadot uint64_t period_freq, duty_freq; 268*2e3507c2SEmmanuel Vadot uint32_t reg; 269*2e3507c2SEmmanuel Vadot uint32_t period_out; 270*2e3507c2SEmmanuel Vadot uint32_t duty_out; 271*2e3507c2SEmmanuel Vadot uint8_t prescaler; 272*2e3507c2SEmmanuel Vadot uint8_t scaler; 273*2e3507c2SEmmanuel Vadot bool using_scaler; 274*2e3507c2SEmmanuel Vadot 275*2e3507c2SEmmanuel Vadot sc = device_get_softc(dev); 276*2e3507c2SEmmanuel Vadot 277*2e3507c2SEmmanuel Vadot period_freq = NS_PER_SEC / period; 278*2e3507c2SEmmanuel Vadot /* Datasheet doesn't define, so use Nyquist frequency. */ 279*2e3507c2SEmmanuel Vadot if (period_freq > (sc->clk_freq / 2)) 280*2e3507c2SEmmanuel Vadot return (EINVAL); 281*2e3507c2SEmmanuel Vadot duty_freq = NS_PER_SEC / duty; 282*2e3507c2SEmmanuel Vadot if (duty_freq < period_freq) { 283*2e3507c2SEmmanuel Vadot device_printf(sc->dev, "duty < period\n"); 284*2e3507c2SEmmanuel Vadot return (EINVAL); 285*2e3507c2SEmmanuel Vadot } 286*2e3507c2SEmmanuel Vadot 287*2e3507c2SEmmanuel Vadot /* Assuming 24 MHz reference, we should never actually have 288*2e3507c2SEmmanuel Vadot to use the divider due to pwm API limitations. */ 289*2e3507c2SEmmanuel Vadot prescaler = 0; 290*2e3507c2SEmmanuel Vadot scaler = 0; 291*2e3507c2SEmmanuel Vadot using_scaler = false; 292*2e3507c2SEmmanuel Vadot 293*2e3507c2SEmmanuel Vadot /* XXX Expand API to allow for 64 bit period/duty. */ 294*2e3507c2SEmmanuel Vadot period_out = (sc->clk_freq * period) / NS_PER_SEC; 295*2e3507c2SEmmanuel Vadot duty_out = (sc->clk_freq * duty) / NS_PER_SEC; 296*2e3507c2SEmmanuel Vadot 297*2e3507c2SEmmanuel Vadot reg = RK_PWM_READ(sc, RK_PWM_CTRL); 298*2e3507c2SEmmanuel Vadot 299*2e3507c2SEmmanuel Vadot if ((reg & RK_PWM_CTRL_MODE_MASK) != RK_PWM_CTRL_MODE_CONTINUOUS) { 300*2e3507c2SEmmanuel Vadot /* Switching modes, disable just in case. */ 301*2e3507c2SEmmanuel Vadot SET(reg, RK_PWM_CTRL_ENABLE_MASK, RK_PWM_CTRL_DISABLED); 302*2e3507c2SEmmanuel Vadot RK_PWM_WRITE(sc, RK_PWM_CTRL, reg); 303*2e3507c2SEmmanuel Vadot } 304*2e3507c2SEmmanuel Vadot 305*2e3507c2SEmmanuel Vadot RK_PWM_WRITE(sc, RK_PWM_PERIOD, period_out); 306*2e3507c2SEmmanuel Vadot RK_PWM_WRITE(sc, RK_PWM_DUTY, duty_out); 307*2e3507c2SEmmanuel Vadot 308*2e3507c2SEmmanuel Vadot SET(reg, RK_PWM_CTRL_ENABLE_MASK, RK_PWM_CTRL_ENABLED); 309*2e3507c2SEmmanuel Vadot SET(reg, RK_PWM_CTRL_MODE_MASK, RK_PWM_CTRL_MODE_CONTINUOUS); 310*2e3507c2SEmmanuel Vadot SET(reg, RK_PWM_CTRL_ALIGN_MASK, RK_PWM_CTRL_ALIGN_LEFT); 311*2e3507c2SEmmanuel Vadot SET(reg, RK_PWM_CTRL_CLOCKSRC_MASK, using_scaler); 312*2e3507c2SEmmanuel Vadot SET(reg, RK_PWM_CTRL_PRESCALE_MASK, 313*2e3507c2SEmmanuel Vadot prescaler << RK_PWM_CTRL_PRESCALE_SHIFT); 314*2e3507c2SEmmanuel Vadot SET(reg, RK_PWM_CTRL_SCALE_MASK, 315*2e3507c2SEmmanuel Vadot scaler << RK_PWM_CTRL_SCALE_SHIFT); 316*2e3507c2SEmmanuel Vadot 317*2e3507c2SEmmanuel Vadot RK_PWM_WRITE(sc, RK_PWM_CTRL, reg); 318*2e3507c2SEmmanuel Vadot 319*2e3507c2SEmmanuel Vadot sc->period = period; 320*2e3507c2SEmmanuel Vadot sc->duty = duty; 321*2e3507c2SEmmanuel Vadot 322*2e3507c2SEmmanuel Vadot return (0); 323*2e3507c2SEmmanuel Vadot } 324*2e3507c2SEmmanuel Vadot 325*2e3507c2SEmmanuel Vadot static int 326*2e3507c2SEmmanuel Vadot rk_pwm_channel_get_config(device_t dev, u_int channel, u_int *period, u_int *duty) 327*2e3507c2SEmmanuel Vadot { 328*2e3507c2SEmmanuel Vadot struct rk_pwm_softc *sc; 329*2e3507c2SEmmanuel Vadot 330*2e3507c2SEmmanuel Vadot sc = device_get_softc(dev); 331*2e3507c2SEmmanuel Vadot 332*2e3507c2SEmmanuel Vadot *period = sc->period; 333*2e3507c2SEmmanuel Vadot *duty = sc->duty; 334*2e3507c2SEmmanuel Vadot 335*2e3507c2SEmmanuel Vadot return (0); 336*2e3507c2SEmmanuel Vadot } 337*2e3507c2SEmmanuel Vadot 338*2e3507c2SEmmanuel Vadot static int 339*2e3507c2SEmmanuel Vadot rk_pwm_channel_enable(device_t dev, u_int channel, bool enable) 340*2e3507c2SEmmanuel Vadot { 341*2e3507c2SEmmanuel Vadot struct rk_pwm_softc *sc; 342*2e3507c2SEmmanuel Vadot uint32_t reg; 343*2e3507c2SEmmanuel Vadot 344*2e3507c2SEmmanuel Vadot sc = device_get_softc(dev); 345*2e3507c2SEmmanuel Vadot 346*2e3507c2SEmmanuel Vadot if (enable && sc->enabled) 347*2e3507c2SEmmanuel Vadot return (0); 348*2e3507c2SEmmanuel Vadot 349*2e3507c2SEmmanuel Vadot reg = RK_PWM_READ(sc, RK_PWM_CTRL); 350*2e3507c2SEmmanuel Vadot SET(reg, RK_PWM_CTRL_ENABLE_MASK, enable); 351*2e3507c2SEmmanuel Vadot 352*2e3507c2SEmmanuel Vadot RK_PWM_WRITE(sc, RK_PWM_CTRL, reg); 353*2e3507c2SEmmanuel Vadot 354*2e3507c2SEmmanuel Vadot sc->enabled = enable; 355*2e3507c2SEmmanuel Vadot 356*2e3507c2SEmmanuel Vadot return (0); 357*2e3507c2SEmmanuel Vadot } 358*2e3507c2SEmmanuel Vadot 359*2e3507c2SEmmanuel Vadot static int 360*2e3507c2SEmmanuel Vadot rk_pwm_channel_is_enabled(device_t dev, u_int channel, bool *enabled) 361*2e3507c2SEmmanuel Vadot { 362*2e3507c2SEmmanuel Vadot struct rk_pwm_softc *sc; 363*2e3507c2SEmmanuel Vadot 364*2e3507c2SEmmanuel Vadot sc = device_get_softc(dev); 365*2e3507c2SEmmanuel Vadot 366*2e3507c2SEmmanuel Vadot *enabled = sc->enabled; 367*2e3507c2SEmmanuel Vadot 368*2e3507c2SEmmanuel Vadot return (0); 369*2e3507c2SEmmanuel Vadot } 370*2e3507c2SEmmanuel Vadot 371*2e3507c2SEmmanuel Vadot static device_method_t rk_pwm_methods[] = { 372*2e3507c2SEmmanuel Vadot /* Device interface */ 373*2e3507c2SEmmanuel Vadot DEVMETHOD(device_probe, rk_pwm_probe), 374*2e3507c2SEmmanuel Vadot DEVMETHOD(device_attach, rk_pwm_attach), 375*2e3507c2SEmmanuel Vadot DEVMETHOD(device_detach, rk_pwm_detach), 376*2e3507c2SEmmanuel Vadot 377*2e3507c2SEmmanuel Vadot /* ofw_bus interface */ 378*2e3507c2SEmmanuel Vadot DEVMETHOD(ofw_bus_get_node, aw_pwm_get_node), 379*2e3507c2SEmmanuel Vadot 380*2e3507c2SEmmanuel Vadot /* pwm interface */ 381*2e3507c2SEmmanuel Vadot DEVMETHOD(pwmbus_channel_count, rk_pwm_channel_count), 382*2e3507c2SEmmanuel Vadot DEVMETHOD(pwmbus_channel_config, rk_pwm_channel_config), 383*2e3507c2SEmmanuel Vadot DEVMETHOD(pwmbus_channel_get_config, rk_pwm_channel_get_config), 384*2e3507c2SEmmanuel Vadot DEVMETHOD(pwmbus_channel_enable, rk_pwm_channel_enable), 385*2e3507c2SEmmanuel Vadot DEVMETHOD(pwmbus_channel_is_enabled, rk_pwm_channel_is_enabled), 386*2e3507c2SEmmanuel Vadot 387*2e3507c2SEmmanuel Vadot DEVMETHOD_END 388*2e3507c2SEmmanuel Vadot }; 389*2e3507c2SEmmanuel Vadot 390*2e3507c2SEmmanuel Vadot static driver_t rk_pwm_driver = { 391*2e3507c2SEmmanuel Vadot "pwm", 392*2e3507c2SEmmanuel Vadot rk_pwm_methods, 393*2e3507c2SEmmanuel Vadot sizeof(struct rk_pwm_softc), 394*2e3507c2SEmmanuel Vadot }; 395*2e3507c2SEmmanuel Vadot 396*2e3507c2SEmmanuel Vadot DRIVER_MODULE(rk_pwm, simplebus, rk_pwm_driver, 0, 0); 397*2e3507c2SEmmanuel Vadot SIMPLEBUS_PNP_INFO(compat_data); 398