19312900fSEmmanuel Vadot /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 39312900fSEmmanuel Vadot * 49312900fSEmmanuel Vadot * Copyright (c) 2018 Emmanuel Vadot <manu@FreeBSD.org> 59312900fSEmmanuel Vadot * 69312900fSEmmanuel Vadot * Redistribution and use in source and binary forms, with or without 79312900fSEmmanuel Vadot * modification, are permitted provided that the following conditions 89312900fSEmmanuel Vadot * are met: 99312900fSEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright 109312900fSEmmanuel Vadot * notice, this list of conditions and the following disclaimer. 119312900fSEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright 129312900fSEmmanuel Vadot * notice, this list of conditions and the following disclaimer in the 139312900fSEmmanuel Vadot * documentation and/or other materials provided with the distribution. 149312900fSEmmanuel Vadot * 159312900fSEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 169312900fSEmmanuel Vadot * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 179312900fSEmmanuel Vadot * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 189312900fSEmmanuel Vadot * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 199312900fSEmmanuel Vadot * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 209312900fSEmmanuel Vadot * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 219312900fSEmmanuel Vadot * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 229312900fSEmmanuel Vadot * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 239312900fSEmmanuel Vadot * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 249312900fSEmmanuel Vadot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 259312900fSEmmanuel Vadot * SUCH DAMAGE. 269312900fSEmmanuel Vadot */ 279312900fSEmmanuel Vadot 289312900fSEmmanuel Vadot #include <sys/cdefs.h> 299312900fSEmmanuel Vadot #include "opt_platform.h" 309312900fSEmmanuel Vadot 319312900fSEmmanuel Vadot #include <sys/param.h> 329312900fSEmmanuel Vadot #include <sys/systm.h> 339312900fSEmmanuel Vadot #include <sys/bus.h> 349312900fSEmmanuel Vadot #include <sys/conf.h> 359312900fSEmmanuel Vadot #include <sys/endian.h> 369312900fSEmmanuel Vadot #include <sys/kernel.h> 370af7a9a4SIan Lepore #include <sys/malloc.h> 389312900fSEmmanuel Vadot #include <sys/module.h> 39ddfc9c4cSWarner Losh #include <sys/sbuf.h> 409312900fSEmmanuel Vadot 410af7a9a4SIan Lepore #include <dev/pwm/pwmbus.h> 429312900fSEmmanuel Vadot 439312900fSEmmanuel Vadot #include "pwmbus_if.h" 449312900fSEmmanuel Vadot 450af7a9a4SIan Lepore /* 460af7a9a4SIan Lepore * bus_if methods... 470af7a9a4SIan Lepore */ 480af7a9a4SIan Lepore 490af7a9a4SIan Lepore static device_t 500af7a9a4SIan Lepore pwmbus_add_child(device_t dev, u_int order, const char *name, int unit) 510af7a9a4SIan Lepore { 520af7a9a4SIan Lepore device_t child; 530af7a9a4SIan Lepore struct pwmbus_ivars *ivars; 540af7a9a4SIan Lepore 550af7a9a4SIan Lepore child = device_add_child_ordered(dev, order, name, unit); 560af7a9a4SIan Lepore if (child == NULL) 570af7a9a4SIan Lepore return (child); 580af7a9a4SIan Lepore 590af7a9a4SIan Lepore ivars = malloc(sizeof(struct pwmbus_ivars), M_DEVBUF, M_NOWAIT | M_ZERO); 600af7a9a4SIan Lepore if (ivars == NULL) { 610af7a9a4SIan Lepore device_delete_child(dev, child); 620af7a9a4SIan Lepore return (NULL); 630af7a9a4SIan Lepore } 640af7a9a4SIan Lepore device_set_ivars(child, ivars); 650af7a9a4SIan Lepore 660af7a9a4SIan Lepore return (child); 670af7a9a4SIan Lepore } 680af7a9a4SIan Lepore 690af7a9a4SIan Lepore static int 70ddfc9c4cSWarner Losh pwmbus_child_location(device_t dev, device_t child, struct sbuf *sb) 710af7a9a4SIan Lepore { 720af7a9a4SIan Lepore struct pwmbus_ivars *ivars; 730af7a9a4SIan Lepore 740af7a9a4SIan Lepore ivars = device_get_ivars(child); 75ddfc9c4cSWarner Losh sbuf_printf(sb, "hwdev=%s channel=%u", 760af7a9a4SIan Lepore device_get_nameunit(device_get_parent(dev)), ivars->pi_channel); 770af7a9a4SIan Lepore 780af7a9a4SIan Lepore return (0); 790af7a9a4SIan Lepore } 800af7a9a4SIan Lepore 810af7a9a4SIan Lepore static void 820af7a9a4SIan Lepore pwmbus_hinted_child(device_t dev, const char *dname, int dunit) 830af7a9a4SIan Lepore { 840af7a9a4SIan Lepore struct pwmbus_ivars *ivars; 850af7a9a4SIan Lepore device_t child; 860af7a9a4SIan Lepore 870af7a9a4SIan Lepore child = pwmbus_add_child(dev, 0, dname, dunit); 880af7a9a4SIan Lepore 890af7a9a4SIan Lepore /* 900af7a9a4SIan Lepore * If there is a channel hint, use it. Otherwise pi_channel was 910af7a9a4SIan Lepore * initialized to zero, so that's the channel we'll use. 920af7a9a4SIan Lepore */ 930af7a9a4SIan Lepore ivars = device_get_ivars(child); 940af7a9a4SIan Lepore resource_int_value(dname, dunit, "channel", &ivars->pi_channel); 950af7a9a4SIan Lepore } 960af7a9a4SIan Lepore 970af7a9a4SIan Lepore static int 980af7a9a4SIan Lepore pwmbus_print_child(device_t dev, device_t child) 990af7a9a4SIan Lepore { 1000af7a9a4SIan Lepore struct pwmbus_ivars *ivars; 1010af7a9a4SIan Lepore int rv; 1020af7a9a4SIan Lepore 1030af7a9a4SIan Lepore ivars = device_get_ivars(child); 1040af7a9a4SIan Lepore 1050af7a9a4SIan Lepore rv = bus_print_child_header(dev, child); 1060af7a9a4SIan Lepore rv += printf(" channel %u", ivars->pi_channel); 1070af7a9a4SIan Lepore rv += bus_print_child_footer(dev, child); 1080af7a9a4SIan Lepore 1090af7a9a4SIan Lepore return (rv); 1100af7a9a4SIan Lepore } 1110af7a9a4SIan Lepore 1120af7a9a4SIan Lepore static void 1130af7a9a4SIan Lepore pwmbus_probe_nomatch(device_t dev, device_t child) 1140af7a9a4SIan Lepore { 1150af7a9a4SIan Lepore struct pwmbus_ivars *ivars; 1160af7a9a4SIan Lepore 1170af7a9a4SIan Lepore ivars = device_get_ivars(child); 1180af7a9a4SIan Lepore if (ivars != NULL) 1190af7a9a4SIan Lepore device_printf(dev, "<unknown> on channel %u\n", 1200af7a9a4SIan Lepore ivars->pi_channel); 1210af7a9a4SIan Lepore 1220af7a9a4SIan Lepore return; 1230af7a9a4SIan Lepore } 1240af7a9a4SIan Lepore 1250af7a9a4SIan Lepore static int 1260af7a9a4SIan Lepore pwmbus_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 1270af7a9a4SIan Lepore { 1280af7a9a4SIan Lepore struct pwmbus_ivars *ivars; 1290af7a9a4SIan Lepore 1300af7a9a4SIan Lepore ivars = device_get_ivars(child); 1310af7a9a4SIan Lepore 1320af7a9a4SIan Lepore switch (which) { 1330af7a9a4SIan Lepore case PWMBUS_IVAR_CHANNEL: 1340af7a9a4SIan Lepore *(u_int *)result = ivars->pi_channel; 1350af7a9a4SIan Lepore break; 1360af7a9a4SIan Lepore default: 1370af7a9a4SIan Lepore return (EINVAL); 1380af7a9a4SIan Lepore } 1390af7a9a4SIan Lepore 1400af7a9a4SIan Lepore return (0); 1410af7a9a4SIan Lepore } 1420af7a9a4SIan Lepore 1430af7a9a4SIan Lepore /* 1440af7a9a4SIan Lepore * device_if methods... 1450af7a9a4SIan Lepore */ 1460af7a9a4SIan Lepore 1479312900fSEmmanuel Vadot static int 1489312900fSEmmanuel Vadot pwmbus_probe(device_t dev) 1499312900fSEmmanuel Vadot { 1509312900fSEmmanuel Vadot device_set_desc(dev, "PWM bus"); 1519312900fSEmmanuel Vadot return (BUS_PROBE_GENERIC); 1529312900fSEmmanuel Vadot } 1539312900fSEmmanuel Vadot 1549312900fSEmmanuel Vadot static int 1559312900fSEmmanuel Vadot pwmbus_attach(device_t dev) 1569312900fSEmmanuel Vadot { 1579312900fSEmmanuel Vadot struct pwmbus_softc *sc; 1580af7a9a4SIan Lepore struct pwmbus_ivars *ivars; 1590af7a9a4SIan Lepore device_t child, parent; 1600af7a9a4SIan Lepore u_int chan; 1619312900fSEmmanuel Vadot 1629312900fSEmmanuel Vadot sc = device_get_softc(dev); 163f8f8d87cSIan Lepore sc->dev = dev; 1640af7a9a4SIan Lepore parent = device_get_parent(dev); 1659312900fSEmmanuel Vadot 1660af7a9a4SIan Lepore if (PWMBUS_CHANNEL_COUNT(parent, &sc->nchannels) != 0 || 167f8f8d87cSIan Lepore sc->nchannels == 0) { 168f8f8d87cSIan Lepore device_printf(sc->dev, "No channels on parent %s\n", 1690af7a9a4SIan Lepore device_get_nameunit(parent)); 1709312900fSEmmanuel Vadot return (ENXIO); 171f8f8d87cSIan Lepore } 1729312900fSEmmanuel Vadot 1730af7a9a4SIan Lepore /* Add a pwmc(4) child for each channel. */ 1740af7a9a4SIan Lepore for (chan = 0; chan < sc->nchannels; ++chan) { 1750af7a9a4SIan Lepore if ((child = pwmbus_add_child(sc->dev, 0, "pwmc", -1)) == NULL) { 1760af7a9a4SIan Lepore device_printf(dev, "failed to add pwmc child device " 1770af7a9a4SIan Lepore "for channel %u\n", chan); 1780af7a9a4SIan Lepore continue; 1790af7a9a4SIan Lepore } 1800af7a9a4SIan Lepore ivars = device_get_ivars(child); 1810af7a9a4SIan Lepore ivars->pi_channel = chan; 1820af7a9a4SIan Lepore } 183f8f8d87cSIan Lepore 1840af7a9a4SIan Lepore bus_enumerate_hinted_children(dev); 185723da5d9SJohn Baldwin bus_identify_children(dev); 18618250ec6SJohn Baldwin bus_attach_children(dev); 1879312900fSEmmanuel Vadot 18818250ec6SJohn Baldwin return (0); 1899312900fSEmmanuel Vadot } 1909312900fSEmmanuel Vadot 1910af7a9a4SIan Lepore /* 1920af7a9a4SIan Lepore * pwmbus_if methods... 1930af7a9a4SIan Lepore */ 1940af7a9a4SIan Lepore 1959312900fSEmmanuel Vadot static int 1966cdbe2bfSIan Lepore pwmbus_channel_config(device_t dev, u_int chan, u_int period, u_int duty) 1979312900fSEmmanuel Vadot { 198f8f8d87cSIan Lepore return (PWMBUS_CHANNEL_CONFIG(device_get_parent(dev), chan, period, duty)); 1999312900fSEmmanuel Vadot } 2009312900fSEmmanuel Vadot 2019312900fSEmmanuel Vadot static int 2026cdbe2bfSIan Lepore pwmbus_channel_get_config(device_t dev, u_int chan, u_int *period, u_int *duty) 2039312900fSEmmanuel Vadot { 204f8f8d87cSIan Lepore return (PWMBUS_CHANNEL_GET_CONFIG(device_get_parent(dev), chan, period, duty)); 2059312900fSEmmanuel Vadot } 2069312900fSEmmanuel Vadot 2079312900fSEmmanuel Vadot static int 2086cdbe2bfSIan Lepore pwmbus_channel_get_flags(device_t dev, u_int chan, uint32_t *flags) 2099312900fSEmmanuel Vadot { 210f8f8d87cSIan Lepore return (PWMBUS_CHANNEL_GET_FLAGS(device_get_parent(dev), chan, flags)); 2119312900fSEmmanuel Vadot } 2129312900fSEmmanuel Vadot 2139312900fSEmmanuel Vadot static int 2146cdbe2bfSIan Lepore pwmbus_channel_enable(device_t dev, u_int chan, bool enable) 2159312900fSEmmanuel Vadot { 216f8f8d87cSIan Lepore return (PWMBUS_CHANNEL_ENABLE(device_get_parent(dev), chan, enable)); 2179312900fSEmmanuel Vadot } 2189312900fSEmmanuel Vadot 2199312900fSEmmanuel Vadot static int 2206cdbe2bfSIan Lepore pwmbus_channel_set_flags(device_t dev, u_int chan, uint32_t flags) 2219312900fSEmmanuel Vadot { 222f8f8d87cSIan Lepore return (PWMBUS_CHANNEL_SET_FLAGS(device_get_parent(dev), chan, flags)); 2239312900fSEmmanuel Vadot } 2249312900fSEmmanuel Vadot 2259312900fSEmmanuel Vadot static int 2266cdbe2bfSIan Lepore pwmbus_channel_is_enabled(device_t dev, u_int chan, bool *enable) 2279312900fSEmmanuel Vadot { 228f8f8d87cSIan Lepore return (PWMBUS_CHANNEL_IS_ENABLED(device_get_parent(dev), chan, enable)); 229f8f8d87cSIan Lepore } 2309312900fSEmmanuel Vadot 231f8f8d87cSIan Lepore static int 2326cdbe2bfSIan Lepore pwmbus_channel_count(device_t dev, u_int *nchannel) 233f8f8d87cSIan Lepore { 234f8f8d87cSIan Lepore return (PWMBUS_CHANNEL_COUNT(device_get_parent(dev), nchannel)); 2359312900fSEmmanuel Vadot } 2369312900fSEmmanuel Vadot 2379312900fSEmmanuel Vadot static device_method_t pwmbus_methods[] = { 2389312900fSEmmanuel Vadot /* device_if */ 2399312900fSEmmanuel Vadot DEVMETHOD(device_probe, pwmbus_probe), 2409312900fSEmmanuel Vadot DEVMETHOD(device_attach, pwmbus_attach), 241*cf416f56SJohn Baldwin DEVMETHOD(device_detach, bus_generic_detach), 2429312900fSEmmanuel Vadot 2430af7a9a4SIan Lepore /* bus_if */ 2440af7a9a4SIan Lepore DEVMETHOD(bus_add_child, pwmbus_add_child), 245ddfc9c4cSWarner Losh DEVMETHOD(bus_child_location, pwmbus_child_location), 2460af7a9a4SIan Lepore DEVMETHOD(bus_hinted_child, pwmbus_hinted_child), 2470af7a9a4SIan Lepore DEVMETHOD(bus_print_child, pwmbus_print_child), 2480af7a9a4SIan Lepore DEVMETHOD(bus_probe_nomatch, pwmbus_probe_nomatch), 2490af7a9a4SIan Lepore DEVMETHOD(bus_read_ivar, pwmbus_read_ivar), 2500af7a9a4SIan Lepore 251f8f8d87cSIan Lepore /* pwmbus_if */ 252f8f8d87cSIan Lepore DEVMETHOD(pwmbus_channel_count, pwmbus_channel_count), 2539312900fSEmmanuel Vadot DEVMETHOD(pwmbus_channel_config, pwmbus_channel_config), 2549312900fSEmmanuel Vadot DEVMETHOD(pwmbus_channel_get_config, pwmbus_channel_get_config), 2559312900fSEmmanuel Vadot DEVMETHOD(pwmbus_channel_set_flags, pwmbus_channel_set_flags), 2569312900fSEmmanuel Vadot DEVMETHOD(pwmbus_channel_get_flags, pwmbus_channel_get_flags), 2579312900fSEmmanuel Vadot DEVMETHOD(pwmbus_channel_enable, pwmbus_channel_enable), 2589312900fSEmmanuel Vadot DEVMETHOD(pwmbus_channel_is_enabled, pwmbus_channel_is_enabled), 2599312900fSEmmanuel Vadot 2609312900fSEmmanuel Vadot DEVMETHOD_END 2619312900fSEmmanuel Vadot }; 2629312900fSEmmanuel Vadot 2630af7a9a4SIan Lepore driver_t pwmbus_driver = { 2649312900fSEmmanuel Vadot "pwmbus", 2659312900fSEmmanuel Vadot pwmbus_methods, 2669312900fSEmmanuel Vadot sizeof(struct pwmbus_softc), 2679312900fSEmmanuel Vadot }; 2689312900fSEmmanuel Vadot 269024d9473SJohn Baldwin EARLY_DRIVER_MODULE(pwmbus, pwm, pwmbus_driver, 0, 0, 2700af7a9a4SIan Lepore BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); 2719312900fSEmmanuel Vadot MODULE_VERSION(pwmbus, 1); 272