xref: /netbsd-src/sys/dev/fdt/fdt_pwm.c (revision 233c5d85efd0721c11837e7294d260f3a2bd8f2f)
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