1*233c5d85Sjmcneill /* $NetBSD: fdt_pwm.c,v 1.2 2018/06/30 20:34:43 jmcneill Exp $ */
239f9e242Sjmcneill
339f9e242Sjmcneill /*-
439f9e242Sjmcneill * Copyright (c) 2018 Jared McNeill <jmcneill@invisible.ca>
539f9e242Sjmcneill * All rights reserved.
639f9e242Sjmcneill *
739f9e242Sjmcneill * Redistribution and use in source and binary forms, with or without
839f9e242Sjmcneill * modification, are permitted provided that the following conditions
939f9e242Sjmcneill * are met:
1039f9e242Sjmcneill * 1. Redistributions of source code must retain the above copyright
1139f9e242Sjmcneill * notice, this list of conditions and the following disclaimer.
1239f9e242Sjmcneill * 2. Redistributions in binary form must reproduce the above copyright
1339f9e242Sjmcneill * notice, this list of conditions and the following disclaimer in the
1439f9e242Sjmcneill * documentation and/or other materials provided with the distribution.
1539f9e242Sjmcneill *
1639f9e242Sjmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1739f9e242Sjmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1839f9e242Sjmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1939f9e242Sjmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2039f9e242Sjmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2139f9e242Sjmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2239f9e242Sjmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2339f9e242Sjmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2439f9e242Sjmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2539f9e242Sjmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2639f9e242Sjmcneill * SUCH DAMAGE.
2739f9e242Sjmcneill */
2839f9e242Sjmcneill
2939f9e242Sjmcneill #include <sys/cdefs.h>
30*233c5d85Sjmcneill __KERNEL_RCSID(0, "$NetBSD: fdt_pwm.c,v 1.2 2018/06/30 20:34:43 jmcneill Exp $");
3139f9e242Sjmcneill
3239f9e242Sjmcneill #include <sys/param.h>
3339f9e242Sjmcneill #include <sys/bus.h>
3439f9e242Sjmcneill #include <sys/kmem.h>
35*233c5d85Sjmcneill #include <sys/queue.h>
3639f9e242Sjmcneill
3739f9e242Sjmcneill #include <libfdt.h>
3839f9e242Sjmcneill #include <dev/fdt/fdtvar.h>
3939f9e242Sjmcneill
4039f9e242Sjmcneill struct fdtbus_pwm_controller {
4139f9e242Sjmcneill device_t pc_dev;
4239f9e242Sjmcneill int pc_phandle;
4339f9e242Sjmcneill const struct fdtbus_pwm_controller_func *pc_funcs;
4439f9e242Sjmcneill
45*233c5d85Sjmcneill LIST_ENTRY(fdtbus_pwm_controller) pc_next;
4639f9e242Sjmcneill };
4739f9e242Sjmcneill
48*233c5d85Sjmcneill static LIST_HEAD(, fdtbus_pwm_controller) fdtbus_pwm_controllers =
49*233c5d85Sjmcneill LIST_HEAD_INITIALIZER(fdtbus_pwm_controllers);
5039f9e242Sjmcneill
5139f9e242Sjmcneill int
fdtbus_register_pwm_controller(device_t dev,int phandle,const struct fdtbus_pwm_controller_func * funcs)5239f9e242Sjmcneill fdtbus_register_pwm_controller(device_t dev, int phandle,
5339f9e242Sjmcneill const struct fdtbus_pwm_controller_func *funcs)
5439f9e242Sjmcneill {
5539f9e242Sjmcneill struct fdtbus_pwm_controller *pc;
5639f9e242Sjmcneill
5739f9e242Sjmcneill pc = kmem_alloc(sizeof(*pc), KM_SLEEP);
5839f9e242Sjmcneill pc->pc_dev = dev;
5939f9e242Sjmcneill pc->pc_phandle = phandle;
6039f9e242Sjmcneill pc->pc_funcs = funcs;
6139f9e242Sjmcneill
62*233c5d85Sjmcneill LIST_INSERT_HEAD(&fdtbus_pwm_controllers, pc, pc_next);
6339f9e242Sjmcneill
6439f9e242Sjmcneill return 0;
6539f9e242Sjmcneill }
6639f9e242Sjmcneill
6739f9e242Sjmcneill static struct fdtbus_pwm_controller *
fdtbus_get_pwm_controller(int phandle)6839f9e242Sjmcneill fdtbus_get_pwm_controller(int phandle)
6939f9e242Sjmcneill {
7039f9e242Sjmcneill struct fdtbus_pwm_controller *pc;
7139f9e242Sjmcneill
72*233c5d85Sjmcneill LIST_FOREACH(pc, &fdtbus_pwm_controllers, pc_next) {
73*233c5d85Sjmcneill if (pc->pc_phandle == phandle)
7439f9e242Sjmcneill return pc;
7539f9e242Sjmcneill }
7639f9e242Sjmcneill
7739f9e242Sjmcneill return NULL;
7839f9e242Sjmcneill }
7939f9e242Sjmcneill
8039f9e242Sjmcneill pwm_tag_t
fdtbus_pwm_acquire(int phandle,const char * prop)8139f9e242Sjmcneill fdtbus_pwm_acquire(int phandle, const char *prop)
8239f9e242Sjmcneill {
8339f9e242Sjmcneill return fdtbus_pwm_acquire_index(phandle, prop, 0);
8439f9e242Sjmcneill }
8539f9e242Sjmcneill
8639f9e242Sjmcneill pwm_tag_t
fdtbus_pwm_acquire_index(int phandle,const char * prop,int index)8739f9e242Sjmcneill fdtbus_pwm_acquire_index(int phandle, const char *prop, int index)
8839f9e242Sjmcneill {
8939f9e242Sjmcneill struct fdtbus_pwm_controller *pc;
9039f9e242Sjmcneill const uint32_t *pwms, *p;
9139f9e242Sjmcneill u_int n, pwm_cells;
9239f9e242Sjmcneill int len, resid;
9339f9e242Sjmcneill
9439f9e242Sjmcneill pwms = fdtbus_get_prop(phandle, prop, &len);
9539f9e242Sjmcneill if (pwms == NULL)
9639f9e242Sjmcneill return NULL;
9739f9e242Sjmcneill
9839f9e242Sjmcneill p = pwms;
9939f9e242Sjmcneill for (n = 0, resid = len; resid > 0; n++) {
10039f9e242Sjmcneill const int pc_phandle =
10139f9e242Sjmcneill fdtbus_get_phandle_from_native(be32toh(p[0]));
10239f9e242Sjmcneill if (of_getprop_uint32(pc_phandle, "#pwm-cells", &pwm_cells))
10339f9e242Sjmcneill break;
10439f9e242Sjmcneill if (n == index) {
10539f9e242Sjmcneill pc = fdtbus_get_pwm_controller(pc_phandle);
10639f9e242Sjmcneill if (pc == NULL)
10739f9e242Sjmcneill return NULL;
10839f9e242Sjmcneill return pc->pc_funcs->get_tag(pc->pc_dev,
10939f9e242Sjmcneill &p[0], (pwm_cells + 1) * 4);
11039f9e242Sjmcneill }
11139f9e242Sjmcneill resid -= (pwm_cells + 1) * 4;
11239f9e242Sjmcneill p += pwm_cells + 1;
11339f9e242Sjmcneill }
11439f9e242Sjmcneill
11539f9e242Sjmcneill return NULL;
11639f9e242Sjmcneill }
117