Index: head/sys/arm/allwinner/aw_pwm.c =================================================================== --- head/sys/arm/allwinner/aw_pwm.c (revision 349087) +++ head/sys/arm/allwinner/aw_pwm.c (revision 349088) @@ -1,375 +1,375 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Emmanuel Vadot * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include "pwmbus_if.h" #define AW_PWM_CTRL 0x00 #define AW_PWM_CTRL_PRESCALE_MASK 0xF #define AW_PWM_CTRL_EN (1 << 4) #define AW_PWM_CTRL_ACTIVE_LEVEL_HIGH (1 << 5) #define AW_PWM_CTRL_GATE (1 << 6) #define AW_PWM_CTRL_MODE_MASK 0x80 #define AW_PWM_CTRL_PULSE_MODE (1 << 7) #define AW_PWM_CTRL_CYCLE_MODE (0 << 7) #define AW_PWM_CTRL_PULSE_START (1 << 8) #define AW_PWM_CTRL_CLK_BYPASS (1 << 9) #define AW_PWM_CTRL_PERIOD_BUSY (1 << 28) #define AW_PWM_PERIOD 0x04 #define AW_PWM_PERIOD_TOTAL_MASK 0xFFFF #define AW_PWM_PERIOD_TOTAL_SHIFT 16 #define AW_PWM_PERIOD_ACTIVE_MASK 0xFFFF #define AW_PWM_PERIOD_ACTIVE_SHIFT 0 #define AW_PWM_MAX_FREQ 24000000 #define NS_PER_SEC 1000000000 static struct ofw_compat_data compat_data[] = { { "allwinner,sun5i-a13-pwm", 1 }, { NULL, 0 } }; static struct resource_spec aw_pwm_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, { -1, 0 } }; struct aw_pwm_softc { device_t dev; device_t busdev; clk_t clk; struct resource *res; uint64_t clk_freq; unsigned int period; unsigned int duty; uint32_t flags; bool enabled; }; static uint32_t aw_pwm_clk_prescaler[] = { 120, 180, 240, 360, 480, 0, 0, 0, 12000, 24000, 36000, 48000, 72000, 0, 0, 1, }; #define AW_PWM_READ(sc, reg) bus_read_4((sc)->res, (reg)) #define AW_PWM_WRITE(sc, reg, val) bus_write_4((sc)->res, (reg), (val)) static int aw_pwm_probe(device_t dev); static int aw_pwm_attach(device_t dev); static int aw_pwm_detach(device_t dev); static int aw_pwm_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) return (ENXIO); device_set_desc(dev, "Allwinner PWM"); return (BUS_PROBE_DEFAULT); } static int aw_pwm_attach(device_t dev) { struct aw_pwm_softc *sc; uint64_t clk_freq; uint32_t reg; phandle_t node; int error; sc = device_get_softc(dev); sc->dev = dev; error = clk_get_by_ofw_index(dev, 0, 0, &sc->clk); if (error != 0) { device_printf(dev, "cannot get clock\n"); goto fail; } error = clk_enable(sc->clk); if (error != 0) { device_printf(dev, "cannot enable clock\n"); goto fail; } error = clk_get_freq(sc->clk, &sc->clk_freq); if (error != 0) { device_printf(dev, "cannot get clock frequency\n"); goto fail; } if (bus_alloc_resources(dev, aw_pwm_spec, &sc->res) != 0) { device_printf(dev, "cannot allocate resources for device\n"); error = ENXIO; goto fail; } /* Read the configuration left by U-Boot */ reg = AW_PWM_READ(sc, AW_PWM_CTRL); if (reg & (AW_PWM_CTRL_GATE | AW_PWM_CTRL_EN)) sc->enabled = true; reg = AW_PWM_READ(sc, AW_PWM_CTRL); reg &= AW_PWM_CTRL_PRESCALE_MASK; if (reg > nitems(aw_pwm_clk_prescaler)) { device_printf(dev, "Bad prescaler %x, cannot guess current settings\n", reg); goto skipcfg; } clk_freq = sc->clk_freq / aw_pwm_clk_prescaler[reg]; reg = AW_PWM_READ(sc, AW_PWM_PERIOD); sc->period = NS_PER_SEC / (clk_freq / ((reg >> AW_PWM_PERIOD_TOTAL_SHIFT) & AW_PWM_PERIOD_TOTAL_MASK)); sc->duty = NS_PER_SEC / (clk_freq / ((reg >> AW_PWM_PERIOD_ACTIVE_SHIFT) & AW_PWM_PERIOD_ACTIVE_MASK)); skipcfg: /* * Note that we don't check for failure to attach pwmbus -- even without * it we can still service clients who connect via fdt xref data. */ node = ofw_bus_get_node(dev); OF_device_register_xref(OF_xref_from_node(node), dev); sc->busdev = device_add_child(dev, "pwmbus", -1); return (bus_generic_attach(dev)); fail: aw_pwm_detach(dev); return (error); } static int aw_pwm_detach(device_t dev) { struct aw_pwm_softc *sc; int error; sc = device_get_softc(dev); if ((error = bus_generic_detach(sc->dev)) != 0) { device_printf(sc->dev, "cannot detach child devices\n"); return (error); } if (sc->busdev != NULL) device_delete_child(dev, sc->busdev); if (sc->res != NULL) bus_release_resources(dev, aw_pwm_spec, &sc->res); return (0); } static int -aw_pwm_channel_count(device_t dev, int *nchannel) +aw_pwm_channel_count(device_t dev, u_int *nchannel) { *nchannel = 1; return (0); } static int -aw_pwm_channel_config(device_t dev, int channel, unsigned int period, unsigned int duty) +aw_pwm_channel_config(device_t dev, u_int channel, u_int period, u_int duty) { struct aw_pwm_softc *sc; uint64_t period_freq, duty_freq; uint64_t clk_rate, div; uint32_t reg; int prescaler; int i; sc = device_get_softc(dev); period_freq = NS_PER_SEC / period; if (period_freq > AW_PWM_MAX_FREQ) return (EINVAL); duty_freq = NS_PER_SEC / duty; if (duty_freq < period_freq) { device_printf(sc->dev, "duty < period\n"); return (EINVAL); } /* First test without prescaler */ clk_rate = AW_PWM_MAX_FREQ; prescaler = AW_PWM_CTRL_PRESCALE_MASK; div = AW_PWM_MAX_FREQ / period_freq; if ((div - 1) > AW_PWM_PERIOD_TOTAL_MASK) { /* Test all prescaler */ for (i = 0; i < nitems(aw_pwm_clk_prescaler); i++) { if (aw_pwm_clk_prescaler[i] == 0) continue; div = (AW_PWM_MAX_FREQ * aw_pwm_clk_prescaler[i]) / period_freq; if ((div - 1) < AW_PWM_PERIOD_TOTAL_MASK ) { prescaler = i; clk_rate = AW_PWM_MAX_FREQ / aw_pwm_clk_prescaler[i]; break; } } if (prescaler == AW_PWM_CTRL_PRESCALE_MASK) return (EINVAL); } reg = AW_PWM_READ(sc, AW_PWM_CTRL); if (reg & AW_PWM_CTRL_PERIOD_BUSY) { device_printf(sc->dev, "pwm busy\n"); return (EBUSY); } /* Write the prescalar */ reg &= ~AW_PWM_CTRL_PRESCALE_MASK; reg |= prescaler; AW_PWM_WRITE(sc, AW_PWM_CTRL, reg); /* Write the total/active cycles */ reg = ((clk_rate / period_freq) << AW_PWM_PERIOD_TOTAL_SHIFT) | ((clk_rate / duty_freq) << AW_PWM_PERIOD_ACTIVE_SHIFT); AW_PWM_WRITE(sc, AW_PWM_PERIOD, reg); sc->period = period; sc->duty = duty; return (0); } static int -aw_pwm_channel_get_config(device_t dev, int channel, unsigned int *period, unsigned int *duty) +aw_pwm_channel_get_config(device_t dev, u_int channel, u_int *period, u_int *duty) { struct aw_pwm_softc *sc; sc = device_get_softc(dev); *period = sc->period; *duty = sc->duty; return (0); } static int -aw_pwm_channel_enable(device_t dev, int channel, bool enable) +aw_pwm_channel_enable(device_t dev, u_int channel, bool enable) { struct aw_pwm_softc *sc; uint32_t reg; sc = device_get_softc(dev); if (enable && sc->enabled) return (0); reg = AW_PWM_READ(sc, AW_PWM_CTRL); if (enable) reg |= AW_PWM_CTRL_GATE | AW_PWM_CTRL_EN; else reg &= ~(AW_PWM_CTRL_GATE | AW_PWM_CTRL_EN); AW_PWM_WRITE(sc, AW_PWM_CTRL, reg); sc->enabled = enable; return (0); } static int -aw_pwm_channel_is_enabled(device_t dev, int channel, bool *enabled) +aw_pwm_channel_is_enabled(device_t dev, u_int channel, bool *enabled) { struct aw_pwm_softc *sc; sc = device_get_softc(dev); *enabled = sc->enabled; return (0); } static device_method_t aw_pwm_methods[] = { /* Device interface */ DEVMETHOD(device_probe, aw_pwm_probe), DEVMETHOD(device_attach, aw_pwm_attach), DEVMETHOD(device_detach, aw_pwm_detach), /* pwmbus interface */ DEVMETHOD(pwmbus_channel_count, aw_pwm_channel_count), DEVMETHOD(pwmbus_channel_config, aw_pwm_channel_config), DEVMETHOD(pwmbus_channel_get_config, aw_pwm_channel_get_config), DEVMETHOD(pwmbus_channel_enable, aw_pwm_channel_enable), DEVMETHOD(pwmbus_channel_is_enabled, aw_pwm_channel_is_enabled), DEVMETHOD_END }; static driver_t aw_pwm_driver = { "pwm", aw_pwm_methods, sizeof(struct aw_pwm_softc), }; static devclass_t aw_pwm_devclass; DRIVER_MODULE(aw_pwm, simplebus, aw_pwm_driver, aw_pwm_devclass, 0, 0); MODULE_VERSION(aw_pwm, 1); SIMPLEBUS_PNP_INFO(compat_data); Index: head/sys/dev/pwm/pwmbus.c =================================================================== --- head/sys/dev/pwm/pwmbus.c (revision 349087) +++ head/sys/dev/pwm/pwmbus.c (revision 349088) @@ -1,174 +1,174 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Emmanuel Vadot * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_platform.h" #include #include #include #include #include #include #include #include #include #include #include #include "pwmbus_if.h" struct pwmbus_channel_data { int reserved; char *name; }; struct pwmbus_softc { device_t dev; device_t parent; - int nchannels; + u_int nchannels; }; static int pwmbus_probe(device_t dev) { device_set_desc(dev, "PWM bus"); return (BUS_PROBE_GENERIC); } static int pwmbus_attach(device_t dev) { struct pwmbus_softc *sc; sc = device_get_softc(dev); sc->dev = dev; sc->parent = device_get_parent(dev); if (PWMBUS_CHANNEL_COUNT(sc->parent, &sc->nchannels) != 0 || sc->nchannels == 0) { device_printf(sc->dev, "No channels on parent %s\n", device_get_nameunit(sc->parent)); return (ENXIO); } device_add_child(sc->dev, "pwmc", -1); bus_generic_probe(dev); return (bus_generic_attach(dev)); } static int pwmbus_detach(device_t dev) { int rv; if ((rv = bus_generic_detach(dev)) == 0) rv = device_delete_children(dev); return (rv); } static int -pwmbus_channel_config(device_t dev, int chan, u_int period, u_int duty) +pwmbus_channel_config(device_t dev, u_int chan, u_int period, u_int duty) { return (PWMBUS_CHANNEL_CONFIG(device_get_parent(dev), chan, period, duty)); } static int -pwmbus_channel_get_config(device_t dev, int chan, u_int *period, u_int *duty) +pwmbus_channel_get_config(device_t dev, u_int chan, u_int *period, u_int *duty) { return (PWMBUS_CHANNEL_GET_CONFIG(device_get_parent(dev), chan, period, duty)); } static int -pwmbus_channel_get_flags(device_t dev, int chan, uint32_t *flags) +pwmbus_channel_get_flags(device_t dev, u_int chan, uint32_t *flags) { return (PWMBUS_CHANNEL_GET_FLAGS(device_get_parent(dev), chan, flags)); } static int -pwmbus_channel_enable(device_t dev, int chan, bool enable) +pwmbus_channel_enable(device_t dev, u_int chan, bool enable) { return (PWMBUS_CHANNEL_ENABLE(device_get_parent(dev), chan, enable)); } static int -pwmbus_channel_set_flags(device_t dev, int chan, uint32_t flags) +pwmbus_channel_set_flags(device_t dev, u_int chan, uint32_t flags) { return (PWMBUS_CHANNEL_SET_FLAGS(device_get_parent(dev), chan, flags)); } static int -pwmbus_channel_is_enabled(device_t dev, int chan, bool *enable) +pwmbus_channel_is_enabled(device_t dev, u_int chan, bool *enable) { return (PWMBUS_CHANNEL_IS_ENABLED(device_get_parent(dev), chan, enable)); } static int -pwmbus_channel_count(device_t dev, int *nchannel) +pwmbus_channel_count(device_t dev, u_int *nchannel) { return (PWMBUS_CHANNEL_COUNT(device_get_parent(dev), nchannel)); } static device_method_t pwmbus_methods[] = { /* device_if */ DEVMETHOD(device_probe, pwmbus_probe), DEVMETHOD(device_attach, pwmbus_attach), DEVMETHOD(device_detach, pwmbus_detach), /* pwmbus_if */ DEVMETHOD(pwmbus_channel_count, pwmbus_channel_count), DEVMETHOD(pwmbus_channel_config, pwmbus_channel_config), DEVMETHOD(pwmbus_channel_get_config, pwmbus_channel_get_config), DEVMETHOD(pwmbus_channel_set_flags, pwmbus_channel_set_flags), DEVMETHOD(pwmbus_channel_get_flags, pwmbus_channel_get_flags), DEVMETHOD(pwmbus_channel_enable, pwmbus_channel_enable), DEVMETHOD(pwmbus_channel_is_enabled, pwmbus_channel_is_enabled), DEVMETHOD_END }; static driver_t pwmbus_driver = { "pwmbus", pwmbus_methods, sizeof(struct pwmbus_softc), }; static devclass_t pwmbus_devclass; EARLY_DRIVER_MODULE(pwmbus, pwm, pwmbus_driver, pwmbus_devclass, 0, 0, BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_MIDDLE); MODULE_VERSION(pwmbus, 1); Index: head/sys/dev/pwm/pwmbus.h =================================================================== --- head/sys/dev/pwm/pwmbus.h (revision 349087) +++ head/sys/dev/pwm/pwmbus.h (revision 349088) @@ -1,54 +1,54 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Emmanuel Vadot * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _PWMBUS_H_ #include struct pwm_channel { device_t dev; - int channel; + u_int channel; uint64_t period; uint64_t duty; uint32_t flags; bool enabled; }; typedef struct pwm_channel *pwm_channel_t; int pwm_get_by_ofw_propidx(device_t consumer, phandle_t node, const char *prop_name, int idx, pwm_channel_t *channel); int pwm_get_by_ofw_idx(device_t consumer, phandle_t node, int idx, pwm_channel_t *out_channel); int pwm_get_by_ofw_property(device_t consumer, phandle_t node, const char *prop_name, pwm_channel_t *out_channel); int pwm_get_by_ofw_name(device_t consumer, phandle_t node, const char *name, pwm_channel_t *out_channel); #endif /* _PWMBUS_H_ */ Index: head/sys/dev/pwm/pwmbus_if.m =================================================================== --- head/sys/dev/pwm/pwmbus_if.m (revision 349087) +++ head/sys/dev/pwm/pwmbus_if.m (revision 349088) @@ -1,115 +1,115 @@ #- # SPDX-License-Identifier: BSD-2-Clause-FreeBSD # # Copyright (c) 2018 Emmanuel Vadot # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # #include INTERFACE pwmbus; CODE { static int - pwm_default_set_flags(device_t dev, int channel, uint32_t flags) + pwm_default_set_flags(device_t dev, u_int channel, uint32_t flags) { return (EOPNOTSUPP); } static int - pwm_default_get_flags(device_t dev, int channel, uint32_t *flags) + pwm_default_get_flags(device_t dev, u_int channel, uint32_t *flags) { *flags = 0; return (0); } }; # # Config the period (Total number of cycle in ns) and # the duty (active number of cycle in ns) # METHOD int channel_config { device_t bus; - int channel; + u_int channel; unsigned int period; unsigned int duty; }; # # Get the period (Total number of cycle in ns) and # the duty (active number of cycle in ns) # METHOD int channel_get_config { device_t bus; - int channel; + u_int channel; unsigned int *period; unsigned int *duty; }; # # Set the flags # METHOD int channel_set_flags { device_t bus; - int channel; + u_int channel; uint32_t flags; } DEFAULT pwm_default_set_flags; # # Get the flags # METHOD int channel_get_flags { device_t dev; - int channel; + u_int channel; uint32_t *flags; } DEFAULT pwm_default_get_flags; # # Enable the pwm output # METHOD int channel_enable { device_t bus; - int channel; + u_int channel; bool enable; }; # # Is the pwm output enabled # METHOD int channel_is_enabled { device_t bus; - int channel; + u_int channel; bool *enabled; }; # # Get the number of channels # METHOD int channel_count { device_t bus; - int *nchannel; + u_int *nchannel; }; Index: head/sys/dev/pwm/pwmc.c =================================================================== --- head/sys/dev/pwm/pwmc.c (revision 349087) +++ head/sys/dev/pwm/pwmc.c (revision 349088) @@ -1,161 +1,161 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Emmanuel Vadot * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include "pwmbus_if.h" struct pwmc_softc { device_t dev; struct cdev *pwm_dev; char name[32]; }; static int pwm_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td) { struct pwmc_softc *sc; struct pwm_state state; device_t bus; - int nchannel; + u_int nchannel; int rv = 0; sc = dev->si_drv1; bus = device_get_parent(sc->dev); switch (cmd) { case PWMMAXCHANNEL: - nchannel = -1; + nchannel = 0; rv = PWMBUS_CHANNEL_COUNT(bus, &nchannel); bcopy(&nchannel, data, sizeof(nchannel)); break; case PWMSETSTATE: bcopy(data, &state, sizeof(state)); rv = PWMBUS_CHANNEL_CONFIG(bus, state.channel, state.period, state.duty); if (rv == 0) rv = PWMBUS_CHANNEL_ENABLE(bus, state.channel, state.enable); break; case PWMGETSTATE: bcopy(data, &state, sizeof(state)); rv = PWMBUS_CHANNEL_GET_CONFIG(bus, state.channel, &state.period, &state.duty); if (rv != 0) return (rv); rv = PWMBUS_CHANNEL_IS_ENABLED(bus, state.channel, &state.enable); if (rv != 0) return (rv); bcopy(&state, data, sizeof(state)); break; } return (rv); } static struct cdevsw pwm_cdevsw = { .d_version = D_VERSION, .d_name = "pwm", .d_ioctl = pwm_ioctl }; static int pwmc_probe(device_t dev) { device_set_desc(dev, "PWM Controller"); return (BUS_PROBE_NOWILDCARD); } static int pwmc_attach(device_t dev) { struct pwmc_softc *sc; struct make_dev_args args; sc = device_get_softc(dev); sc->dev = dev; snprintf(sc->name, sizeof(sc->name), "pwmc%d", device_get_unit(dev)); make_dev_args_init(&args); args.mda_flags = MAKEDEV_CHECKNAME | MAKEDEV_WAITOK; args.mda_devsw = &pwm_cdevsw; args.mda_uid = UID_ROOT; args.mda_gid = GID_OPERATOR; args.mda_mode = 0600; args.mda_si_drv1 = sc; if (make_dev_s(&args, &sc->pwm_dev, "%s", sc->name) != 0) { device_printf(dev, "Failed to make PWM device\n"); return (ENXIO); } return (0); } static int pwmc_detach(device_t dev) { struct pwmc_softc *sc; sc = device_get_softc(dev); destroy_dev(sc->pwm_dev); return (0); } static device_method_t pwmc_methods[] = { /* device_if */ DEVMETHOD(device_probe, pwmc_probe), DEVMETHOD(device_attach, pwmc_attach), DEVMETHOD(device_detach, pwmc_detach), DEVMETHOD_END }; static driver_t pwmc_driver = { "pwmc", pwmc_methods, sizeof(struct pwmc_softc), }; static devclass_t pwmc_devclass; DRIVER_MODULE(pwmc, pwmbus, pwmc_driver, pwmc_devclass, 0, 0); MODULE_DEPEND(pwmc, pwmbus, 1, 1, 1); MODULE_VERSION(pwmc, 1); Index: head/usr.sbin/pwm/pwm.c =================================================================== --- head/usr.sbin/pwm/pwm.c (revision 349087) +++ head/usr.sbin/pwm/pwm.c (revision 349088) @@ -1,225 +1,225 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Emmanuel Vadot * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define PWM_ENABLE 0x0001 #define PWM_DISABLE 0x0002 #define PWM_SHOW_CONFIG 0x0004 #define PWM_PERIOD 0x0008 #define PWM_DUTY 0x0010 static void usage(void) { fprintf(stderr, "Usage:\n"); fprintf(stderr, "\tpwm [-f dev] -c channel -E\n"); fprintf(stderr, "\tpwm [-f dev] -c channel -D\n"); fprintf(stderr, "\tpwm [-f dev] -c channel -C\n"); fprintf(stderr, "\tpwm [-f dev] -c channel -p period\n"); fprintf(stderr, "\tpwm [-f dev] -c channel -d duty\n"); exit(1); } int main(int argc, char *argv[]) { struct pwm_state state; int fd; - int channel, nchannels; + u_int channel, nchannels; int period, duty; int action, ch; cap_rights_t right_ioctl; const unsigned long pwm_ioctls[] = {PWMGETSTATE, PWMSETSTATE, PWMMAXCHANNEL}; char *percent; action = 0; fd = -1; - channel = -1; + channel = -1u; period = duty = -1; while ((ch = getopt(argc, argv, "f:c:EDCp:d:")) != -1) { switch (ch) { case 'E': if (action) usage(); action = PWM_ENABLE; break; case 'D': if (action) usage(); action = PWM_DISABLE; break; case 'C': if (action) usage(); action = PWM_SHOW_CONFIG; break; case 'p': if (action & ~(PWM_PERIOD | PWM_DUTY)) usage(); action = PWM_PERIOD; period = strtol(optarg, NULL, 10); break; case 'd': if (action & ~(PWM_PERIOD | PWM_DUTY)) usage(); action = PWM_DUTY; duty = strtol(optarg, &percent, 10); if (*percent != '\0' && *percent != '%') usage(); break; case 'c': - if (channel != -1) + if (channel != -1u) usage(); - channel = strtol(optarg, NULL, 10); + channel = strtoul(optarg, NULL, 10); break; case 'f': if ((fd = open(optarg, O_RDWR)) < 0) { fprintf(stderr, "pwm: cannot open %s %s\n", optarg, strerror(errno)); exit(1); } } } if (fd == -1) { if ((fd = open("/dev/pwmc0", O_RDWR)) < 0) { fprintf(stderr, "pwm: cannot open %s %s\n", optarg, strerror(errno)); exit(1); } } if (action == 0 || fd == -1) usage(); if (caph_limit_stdio() < 0) { fprintf(stderr, "can't limit stdio rights"); goto fail; } caph_cache_catpages(); cap_rights_init(&right_ioctl, CAP_IOCTL); if (caph_rights_limit(fd, &right_ioctl) < 0) { fprintf(stderr, "cap_right_limit() failed\n"); goto fail; } if (caph_ioctls_limit(fd, pwm_ioctls, nitems(pwm_ioctls)) < 0) { fprintf(stderr, "caph_ioctls_limit() failed\n"); goto fail; } if (caph_enter() < 0) { fprintf(stderr, "failed to enter capability mode\n"); goto fail; } /* Check if the channel is correct */ if (ioctl(fd, PWMMAXCHANNEL, &nchannels) == -1) { fprintf(stderr, "ioctl: %s\n", strerror(errno)); goto fail; } if (channel > nchannels) { fprintf(stderr, "pwm controller only support %d channels\n", nchannels); goto fail; } /* Fill the common args */ state.channel = channel; if (ioctl(fd, PWMGETSTATE, &state) == -1) { fprintf(stderr, "Cannot get current state of the pwm controller\n"); goto fail; } switch (action) { case PWM_ENABLE: if (state.enable == false) { state.enable = true; if (ioctl(fd, PWMSETSTATE, &state) == -1) { fprintf(stderr, "Cannot enable the pwm controller\n"); goto fail; } } break; case PWM_DISABLE: if (state.enable == true) { state.enable = false; if (ioctl(fd, PWMSETSTATE, &state) == -1) { fprintf(stderr, "Cannot disable the pwm controller\n"); goto fail; } } break; case PWM_SHOW_CONFIG: printf("period: %u\nduty: %u\nenabled:%d\n", state.period, state.duty, state.enable); break; case PWM_PERIOD: case PWM_DUTY: if (period != -1) state.period = period; if (duty != -1) { if (*percent != '\0') state.duty = state.period * duty / 100; else state.duty = duty; } if (ioctl(fd, PWMSETSTATE, &state) == -1) { fprintf(stderr, "Cannot configure the pwm controller\n"); goto fail; } break; } close(fd); return (0); fail: close(fd); return (1); }